diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml
new file mode 100644
index 0000000..7e54323
--- /dev/null
+++ b/.github/workflows/nodejs.yml
@@ -0,0 +1,31 @@
+name: Node.js CI
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ strategy:
+ matrix:
+ node-version: [16, 18, 20]
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ - name: Setup Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@v3
+ with:
+ node-version: ${{ matrix.node-version }}
+ cache: 'npm'
+
+ - name: Install dependencies
+ run: npm install
+
+ - name: Run tests
+ run: npm test
\ No newline at end of file
diff --git a/README.md b/README.md
index b82aec9..59cc6c8 100644
--- a/README.md
+++ b/README.md
@@ -1,201 +1,305 @@
# Smart Commit
-Smart Commit is a highly customizable CLI utility for creating Git commits interactively. It offers a range of features to help you produce consistent, well-formatted commit messages while integrating with your workflow. Below is a detailed overview of its features and commands:
+Smart Commit is a highly customizable CLI utility for creating Git commits interactively. It helps you produce consistent, well-formatted commit messages and branch names that integrate seamlessly with your development workflow.
## Features
-- **Interactive Prompts:**
+- **Interactive Prompts**
- Customize which prompts appear during commit creation (commit type, scope, summary, body, footer, ticket, and CI tests).
- - Automatically suggest a commit type based on staged changes.
+ - Automatically suggest commit types based on staged changes.
-- **Template-Based Commit Message:**
+- **Template-Based Commit Messages**
- Define your commit message format using placeholders:
- - {type}: Commit type (e.g., feat, fix, docs, etc.)
- - {scope}: Optional scope (if enabled)
- - {ticket}: Ticket ID (if provided or auto-extracted)
- - {ticketSeparator}: Separator inserted if a ticket is provided
- - {summary}: Commit summary (short description)
- - {body}: Detailed commit message body (if enabled)
- - {footer}: Additional footer information (if enabled)
-
-- **CI Integration:**
- - Optionally run a CI command before executing a commit.
-
-- **Auto Ticket Extraction:**
- - Extract a ticket ID from your branch name using a custom regular expression (if configured).
-
-- **Push Support:**
- - Automatically push commits to the remote repository using the --push flag.
-
-- **Signed Commits:**
- - Create GPG-signed commits using the --sign flag.
-
-- **Commit Statistics:**
- - View commit statistics (e.g., Git shortlog by author or commit activity with ASCII graphs) using the `sc stats` command.
-
-- **Commit History Search:**
- - Search your commit history by:
- - Keyword in commit messages
- - Author name or email
- - Date range
- - Use the `sc history` command for flexible commit searching.
-
-- **Additional Commands:**
- - **Amend:** Interactively amend the last commit, with optional linting support.
- - **Rollback:** Rollback the last commit with an option for a soft reset (keeping changes staged) or a hard reset (discarding changes).
- - **Rebase Helper:** Launch an interactive rebase helper that provides in-editor instructions for modifying recent commits.
-
-- **Local and Global Configuration:**
- - Global configuration is stored in your home directory as ~/.smart-commit-config.json.
- - Override global settings for a specific project by creating a .smartcommitrc.json file in the project root.
- - Configure settings such as auto-add, emoji usage, CI command, commit message template, prompt toggles (scope, body, footer, ticket, CI), linting rules, and ticket extraction regex via the `sc config` command or the interactive setup (`sc setup`).
-
-- **Commit Message Linting:**
- - Optionally enable linting to enforce rules such as maximum summary length, lowercase starting character in the summary, and ticket inclusion when required.
+ - {type}: The commit type (e.g., feat, fix, docs, etc.)
+ - {ticketSeparator}: A separator inserted if a ticket ID is provided.
+ - {ticket}: The ticket ID (entered by the user or auto-extracted).
+ - {summary}: A short summary of the commit.
+ - {body}: A detailed description of the commit.
+ - {footer}: Additional footer text.
+
+- **CI Integration**
+ - Optionally run a specified CI command (e.g., tests) before creating the commit.
+
+- **Auto Ticket Extraction**
+ - Automatically extract a ticket ID from the current branch name using a custom regular expression.
+
+- **Push and Signed Commits**
+ - Automatically push commits after creation using the --push flag.
+ - Create GPG-signed commits with the --sign flag.
+
+- **Commit Statistics and History Search**
+ - View commit statistics as ASCII graphs (shortlog by author, activity graphs) with the `sc stats` command.
+ - Search commit history by keyword, author, or date range using the `sc history` command.
+
+- **Additional Commands**
+ - **Amend:** Interactively edit the last commit message (with optional linting).
+ - **Rollback:** Rollback the last commit, with options for soft (keeping changes staged) or hard (discarding changes) resets.
+ - **Rebase Helper:** Launch an interactive rebase session with guidance on modifying recent commits.
+
+- **Advanced Branch Creation**
+ - **sc branch** creates a new branch from a base branch (or current HEAD) using a naming template and autocomplete.
+ - **Universal Placeholders:** Use placeholders (e.g., {type}, {ticketId}, {shortDesc}, or any custom placeholder) in your branch template.
+ - **Branch Type Selection:** Define a list of branch types in your configuration; if defined, you can select one or provide a custom input.
+ - **Custom Sanitization Options:** For each placeholder, you can set custom sanitization rules:
+ - **lowercase:** (default true) Converts the value to lowercase unless set to false.
+ - **separator:** (default "-") Character to replace spaces.
+ - **collapseSeparator:** (default true) Collapses multiple consecutive separators into one.
+ - **maxLength:** Limits the maximum length of the sanitized value.
+ - The branch name is built from the template by replacing placeholders with sanitized inputs. Extraneous separators are removed, and if the final branch name is empty, a random fallback name is generated.
+ - After branch creation, you are prompted whether to remain on the new branch or switch back to the base branch.
## Commands
-- **sc commit (or sc c):**
- - Start the interactive commit process.
- - Prompts for commit type, scope, summary, body, footer, ticket, CI tests, and staging changes.
- - Supports auto-add, signed commits, and CI integration.
+- **sc commit (or sc c)**
+ - Initiates the interactive commit process.
+ - Prompts for commit type, scope, summary, body, footer, ticket, and CI test execution.
+ - Supports manual file staging or auto-add, GPG signing (--sign), and pushing (--push).
+ - Applies commit message linting if enabled.
+ - **Linting Behavior and Overrides:**
+
+ By default, commit message linting is disabled (i.e. `enableLint` is set to `false` in your configuration). This means that if you don’t specify any command‑line flag, your commit will be created without linting the message.
+
+ If you want to enable linting for a specific commit—even if your configuration has it disabled—you can pass the `--lint` flag. Conversely, if linting is enabled in your configuration but you want to skip it for one commit, you can pass the standard Commander flag `--no-lint` (which sets the option to false).
+
+ For example:
+
+ ```bash
+ sc commit --lint
+ sc commit --no-lint
+ ```
+
+ The command‑line flags override the configuration settings, giving you flexibility on a per‑commit basis.
+
+- **sc amend**
+ - Opens the last commit message in your default editor for amendment.
+ - Validates the amended message using linting rules (if enabled) before updating the commit.
+
+- **sc rollback**
+ - Rolls back the last commit.
+ - Offers a choice between a soft reset (keep changes staged) or a hard reset (discard changes).
+
+- **sc rebase-helper (or sc rebase)**
+ - Launches an interactive rebase session.
+ - Guides you through modifying recent commits with options like pick, reword, edit, squash, fixup, exec, and drop.
+
+- **sc stats**
+ - Displays commit statistics as ASCII graphs.
+ - Choose between a shortlog by author or an activity graph over a specified period (Day, Week, Month).
+
+- **sc history**
+ - Searches commit history.
+ - Offers search options by keyword, author, or date range.
+ - Provides different view modes via interactive prompt:
+ - **All commits:** Shows complete commit history
+ - **Current branch only:** Shows commits unique to the current branch
+
+- **sc config (or sc cfg)**
+ - View and update Smart Commit settings.
+ - Reset Configuration
+ - Configure options such as:
+ - Auto-add (automatically stage changes)
+ - Emoji usage in commit type prompts
+ - CI command
+ - Commit message template
+ - Prompt toggles for scope, body, footer, ticket, and CI
+ - Ticket extraction regex
+ - Commit linting rules
+ - Branch configuration (template, types, and custom sanitization options)
+ - **Examples:**
+ - Enable auto-add: `sc config --auto-add true`
+ - Set CI command: `sc config --ci-command "npm test"`
+ - View current configuration: `sc config`
+ - Reset configuration to default: `sc config --reset`
+
+- **sc setup**
+ - Launches an interactive setup wizard to configure your Smart Commit preferences step by step.
+ - Walks you through each configuration option.
+
+- **sc branch (or sc b)**
+ - Creates a new branch from a base branch (or current HEAD) using a naming template and autocomplete.
+ - **Key Features:**
+ - **Universal Placeholders:** Customize branch names with placeholders such as {type}, {ticketId}, {shortDesc}, or any custom placeholder.
+ - **Branch Type Selection:** If branch types are defined in the configuration, you can select from a list or enter a custom type.
+ - **Custom Sanitization Options:** For each placeholder, set options to control:
+ - Conversion to lowercase (default true)
+ - Replacement of spaces with a specific separator (default "-")
+ - Collapsing of consecutive separators (default true)
+ - Maximum length of the sanitized value
+ - **Final Name Assembly:** Constructs the branch name from the template by replacing placeholders with sanitized values and cleaning extraneous separators.
+ - **Fallback Mechanism:** Generates a random branch name if the final name is empty.
+ - **Stay on Branch Prompt:** After creation, decide whether to remain on the new branch or switch back to the base branch.
-- **sc amend:**
- - Amend the last commit interactively.
- - Opens the current commit message in your default editor for modifications.
- - Validates the amended commit message with linting rules if enabled.
-
-- **sc rollback:**
- - Rollback the last commit.
- - Offers a choice between a soft reset (keeping changes staged) and a hard reset (discarding changes).
-
-- **sc rebase-helper:**
- - Launch an interactive rebase helper.
- - Provides instructions and options (pick, reword, edit, squash, fixup, drop) for modifying recent commits.
+## Configuration File
-- **sc stats:**
- - Display commit statistics.
- - Options include viewing a shortlog by author or commit activity graphs over a selected period (day, week, month).
+Global configuration is stored in your home directory as `~/.smart-commit-config.json`. To override these settings for a specific project, create a `.smartcommitrc.json` file in the project root. Use the `sc setup` or `sc config` commands to modify your settings.
+
+### Detailed Configuration Options
+
+| Option | Type | Default | Description | Example |
+|--------------------------------|---------|-----------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------|
+| **commitTypes** | Array | List of commit types (feat, fix, docs, style, refactor, perf, test, chore) | Each type includes an emoji, a value, and a description used in commit prompts. | [{"emoji": "✨", "value": "feat", "description": "A new feature"}, ...] |
+| **autoAdd** | Boolean | false | If true, automatically stage all changed files before committing. | true |
+| **useEmoji** | Boolean | true | If true, display emojis in commit type prompts. | false |
+| **ciCommand** | String | "" | Command to run CI tests before committing. | "npm test" |
+| **templates.defaultTemplate** | String | "[{type}]{ticketSeparator}{ticket}: {summary}\n\nBody:\n{body}\n\nFooter:\n{footer}" | Template for commit messages; placeholders are replaced with user input or auto-generated content. | "[{type}]: {summary}" |
+| **steps.scope** | Boolean | false | Whether to prompt for a commit scope. | true |
+| **steps.body** | Boolean | false | Whether to prompt for a detailed commit body. | true |
+| **steps.footer** | Boolean | false | Whether to prompt for additional footer information. | true |
+| **steps.ticket** | Boolean | false | Whether to prompt for a ticket ID. If enabled and left empty, the ticket may be auto-extracted using the regex. | true |
+| **steps.runCI** | Boolean | false | Whether to prompt for running CI tests before committing. | true |
+| **ticketRegex** | String | "" | Regular expression for extracting a ticket ID from the branch name. | "^(DEV-\\d+)" |
+| **enableLint** | Boolean | false | If true, enable commit message linting. | true |
+| **lintRules.summaryMaxLength** | Number | 72 | Maximum allowed length for the commit summary. | 72 |
+| **lintRules.typeCase** | String | "lowercase" | Required case for the first character of the commit summary. | "lowercase" |
+| **lintRules.requiredTicket** | Boolean | false | If true, a ticket ID is required in the commit message. | true |
+| **branch.template** | String | "{type}/{ticketId}-{shortDesc}" | Template for branch names; supports placeholders replaced by user input. | "{type}/{ticketId}-{shortDesc}" |
+| **branch.types** | Array | List of branch types (feature, fix, chore, hotfix, release, dev) | Provides options for branch types during branch creation. | [{"value": "feature", "description": "New feature"}, ...] |
+| **branch.placeholders** | Object | { ticketId: { lowercase: false } } | Custom sanitization options for branch placeholders. Options include: lowercase (default true), separator (default "-"), collapseSeparator (default true), maxLength. | {"ticketId": {"lowercase": false}} |
+
+### Example Local Configuration File (.smartcommitrc.json)
-- **sc history:**
- - Search commit history with flexible options.
- - Choose to search by a keyword in commit messages, by author, or by a date range.
+```json
+{
+ "autoAdd": true,
+ "useEmoji": true,
+ "ciCommand": "npm test",
+ "templates": {
+ "defaultTemplate": "[{type}]: {summary}"
+ },
+ "steps": {
+ "scope": true,
+ "body": true,
+ "footer": true,
+ "ticket": true,
+ "runCI": true
+ },
+ "ticketRegex": "^(DEV-\\d+)",
+ "enableLint": true,
+ "lintRules": {
+ "summaryMaxLength": 72,
+ "typeCase": "lowercase",
+ "requiredTicket": true
+ },
+ "branch": {
+ "template": "{type}/{ticketId}-{shortDesc}",
+ "types": [
+ { "value": "feature", "description": "New feature" },
+ { "value": "fix", "description": "Bug fix" },
+ { "value": "chore", "description": "Chore branch" },
+ { "value": "hotfix", "description": "Hotfix branch" },
+ { "value": "release", "description": "Release branch" },
+ { "value": "dev", "description": "Development branch" }
+ ],
+ "placeholders": {
+ "ticketId": {
+ "lowercase": false,
+ "separator": "-",
+ "collapseSeparator": true,
+ "maxLength": 10
+ }
+ }
+ }
+}
+```
-- **sc config (or sc cfg):**
- - View and update global Smart Commit settings.
- - Configure options such as auto-add, emoji usage, CI command, commit message template, prompt settings, linting, and ticket extraction regex.
+## Custom Sanitization Options
-- **sc setup:**
- - Run the interactive setup wizard to configure your Smart Commit preferences.
+When creating branch names, each placeholder can be sanitized using custom options defined in the configuration. The available options are:
+- **lowercase:** Converts input to lowercase (default true; set to false to preserve original case).
+- **separator:** Character to replace spaces (default is "-").
+- **collapseSeparator:** If true, collapses multiple consecutive separator characters into one (default true).
+- **maxLength:** Limits the maximum length of the sanitized string. Note that the fallback branch name (generated randomly) is appended and should be considered when setting this value.
## Installation
-Install Smart Commit globally via npm:
+Install Smart Commit globally using npm:
-```bash
-npm install -g @el1fe/smart-commit
-```
+npm install -g @el1fe/smart-commit
-After installation, the commands smart-commit and the alias sc will be available in your terminal.
+After installation, the commands `smart-commit` and `sc` will be available in your terminal.
## Usage Examples
-- Creating a commit:
+- **Creating a Commit:**
```bash
-sc commit [--push] [--sign]
+ sc commit [--push] [--sign]
```
-- Amending the last commit:
+- **Amending the Last Commit:**
```bash
-sc amend
+ sc amend
```
-- Rolling back the last commit:
+- **Rolling Back the Last Commit:**
```bash
-sc rollback
+ sc rollback
```
-- Launching the interactive rebase helper:
+- **Launching the Interactive Rebase Helper:**
```bash
-sc rebase-helper
+ sc rebase-helper
```
-- Viewing commit statistics:
+- **Viewing Commit Statistics:**
```bash
-sc stats
+ sc stats
```
-- Searching commit history:
+- **Searching Commit History:**
```bash
-sc history
+ sc history
```
-- Configuring settings:
-
+- **Configuring Settings:**
+
```bash
-sc config
-sc setup
+ sc config
+ sc setup
```
-## Configuration File
+- **Creating a Branch:**
-Global settings are stored in ~/.smart-commit-config.json. You can override these settings locally by creating a .smartcommitrc.json file in your project directory. To configure Smart Commit, run `sc setup` or you can use the `sc config` command to manually edit the configuration file.
-
-### Configuration Options
-
-Below is a table explaining each configuration option available in Smart Commit, along with their types, default values, descriptions, and examples.
-
-| Option | Type | Default | Description | Example |
-|--------------------------------|----------|----------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------|----------------------------------|
-| **commitTypes** | Array | See default list below:
• feat: "A new feature"
• fix: "A bug fix"
• docs: "Documentation changes"
• style: "Code style improvements"
• refactor: "Code refactoring"
• perf: "Performance improvements"
• test: "Adding tests"
• chore: "Maintenance and chores" | List of available commit types, each with an emoji, a value, and a description. | `[{"emoji": "✨", "value": "feat", "description": "A new feature"}, ...]` |
-| **autoAdd** | Boolean | false | If set to true, all changes will be staged automatically before creating a commit. | true |
-| **useEmoji** | Boolean | true | Determines whether emojis are displayed in the commit type selection prompt. | false |
-| **ciCommand** | String | "" | Command to run CI tests before committing. If provided, CI tests will run automatically when prompted. | "npm test" |
-| **templates.defaultTemplate** | String | `[{type}]{ticketSeparator}{ticket}: {summary}\n\nBody:\n{body}\n\nFooter:\n{footer}` | Template used to format the commit message. Placeholders will be replaced with user-provided or auto-generated content. | `"[{type}]: {summary}"` |
-| **steps.scope** | Boolean | false | Whether to prompt for a commit scope (an optional field). | true |
-| **steps.body** | Boolean | false | Whether to prompt for a detailed commit body. | true |
-| **steps.footer** | Boolean | false | Whether to prompt for additional commit footer information. | true |
-| **steps.ticket** | Boolean | false | Whether to prompt for a ticket ID. If enabled and left empty, ticket ID might be auto-extracted using the regex. | true |
-| **steps.runCI** | Boolean | false | Whether to prompt for running CI tests before committing. | true |
-| **ticketRegex** | String | "" | A regular expression used to extract a ticket ID from the current branch name. | `"^(DEV-\\d+)"` |
-| **enableLint** | Boolean | false | Enables commit message linting based on specified linting rules. | true |
-| **lintRules.summaryMaxLength** | Number | 72 | Maximum allowed length for the commit summary. | 72 |
-| **lintRules.typeCase** | String | "lowercase" | Specifies the required case for the first character of the commit summary. | "lowercase" |
-| **lintRules.requiredTicket** | Boolean | false | If true, a ticket ID is required in the commit message. | true |
+```bash
+ sc branch
+```
+ - Select the base branch via autocomplete or enter manually.
+ - When prompted, choose a branch type from the list (if defined) or provide a custom value.
+ - Enter values for placeholders (e.g., ticket ID, short description, or any custom placeholder).
+ - The branch name is constructed from your branch template with custom sanitization applied.
+ - After branch creation, choose whether to remain on the new branch or switch back to the base branch.
-### Example of a Local Configuration File (`.smartcommitrc.json`)
+## Configuration File
-```json
-{
- "autoAdd": true,
- "useEmoji": true,
- "ciCommand": "npm test",
- "templates": {
- "defaultTemplate": "[{type}]: {summary}"
- },
- "steps": {
- "scope": true,
- "body": true,
- "footer": true,
- "ticket": true,
- "runCI": true
- },
- "ticketRegex": "^(DEV-\\d+)",
- "enableLint": true,
- "lintRules": {
- "summaryMaxLength": 72,
- "typeCase": "lowercase",
- "requiredTicket": true
- }
-}
-```
+Global configuration is stored in `~/.smart-commit-config.json`. To override global settings for a project, create a `.smartcommitrc.json` file in the project directory. Use the `sc setup` or `sc config` commands to update your settings.
+
+### Detailed Configuration Options
+
+- **commitTypes:** Array of commit types (each with emoji, value, and description).
+- **autoAdd:** Boolean indicating whether changes are staged automatically.
+- **useEmoji:** Boolean to enable emoji display in commit type prompts.
+- **ciCommand:** Command to run CI tests before committing.
+- **templates.defaultTemplate:** Template for commit messages.
+- **steps:** Object with booleans for each prompt: scope, body, footer, ticket, and runCI.
+- **ticketRegex:** Regular expression to extract a ticket ID from the branch name.
+- **enableLint:** Boolean to enable commit message linting.
+- **lintRules:** Object defining linting rules (summaryMaxLength, typeCase, requiredTicket).
+- **branch:** Branch configuration including:
+ - **template:** Template for branch names (e.g., "{type}/{ticketId}-{shortDesc}").
+ - **types:** Array of branch types (each with value and description).
+ - **placeholders:** Custom sanitization options for branch placeholders. For each placeholder, you can set:
+ - **lowercase:** Whether to convert the value to lowercase (default true).
+ - **separator:** Character to replace spaces (default "-").
+ - **collapseSeparator:** Whether to collapse multiple separators (default true).
+ - **maxLength:** Maximum length for the sanitized value.
## License
-MIT
\ No newline at end of file
+MIT
+
+For more information and to contribute, please visit the GitHub repository.
\ No newline at end of file
diff --git a/__tests__/amend.test.ts b/__tests__/amend.test.ts
new file mode 100644
index 0000000..9468011
--- /dev/null
+++ b/__tests__/amend.test.ts
@@ -0,0 +1,154 @@
+import { Command } from 'commander';
+import { registerAmendCommand } from '../src/commands/amend';
+import { loadConfig, ensureGitRepo, lintCommitMessage } from '../src/utils';
+import inquirer from 'inquirer';
+import { execSync } from 'child_process';
+
+jest.mock('inquirer', () => ({
+ prompt: jest.fn(),
+}));
+jest.mock('child_process', () => ({
+ execSync: jest.fn(),
+}));
+jest.mock('../src/utils', () => ({
+ ensureGitRepo: jest.fn(),
+ loadConfig: jest.fn(),
+ lintCommitMessage: jest.fn(),
+}));
+
+describe('registerAmendCommand', () => {
+ let program: Command;
+ let mockExit: jest.SpyInstance;
+
+ beforeEach(() => {
+ program = new Command();
+ registerAmendCommand(program);
+
+ (inquirer.prompt as unknown as jest.Mock).mockReset();
+ (execSync as jest.Mock).mockReset();
+ (ensureGitRepo as jest.Mock).mockReset();
+ (loadConfig as jest.Mock).mockReset();
+ (lintCommitMessage as jest.Mock).mockReset();
+
+ mockExit = jest.spyOn(process, 'exit').mockImplementation(code => {
+ throw new Error(`process.exit: ${code}`);
+ });
+ });
+
+ afterEach(() => {
+ mockExit.mockRestore();
+ });
+
+ it('should throw if ensureGitRepo throws an error', async () => {
+ (ensureGitRepo as jest.Mock).mockImplementation(() => {
+ throw new Error('Not a Git repo');
+ });
+
+ await expect(program.parseAsync(['node', 'test', 'amend']))
+ .rejects
+ .toThrow('Not a Git repo');
+
+ expect(execSync).not.toHaveBeenCalled();
+ });
+
+ it('should exit if user does not confirm amend', async () => {
+ (ensureGitRepo as jest.Mock).mockImplementation(() => { });
+ (loadConfig as jest.Mock).mockReturnValue({});
+
+ (execSync as jest.Mock).mockReturnValueOnce('Old commit message\n');
+
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ amendConfirm: false });
+
+ await expect(program.parseAsync(['node', 'test', 'amend']))
+ .resolves
+ .not.toThrow();
+
+ expect(execSync).toHaveBeenCalledTimes(1);
+ });
+
+ it('should amend normally if user confirms and lint is disabled', async () => {
+ (ensureGitRepo as jest.Mock).mockImplementation(() => { });
+ (loadConfig as jest.Mock).mockReturnValue({
+ enableLint: false,
+ });
+ (execSync as jest.Mock).mockReturnValueOnce('Old commit message\n');
+
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ amendConfirm: true })
+ .mockResolvedValueOnce({ newMessage: 'New commit message' });
+
+ await program.parseAsync(['node', 'test', 'amend']);
+
+ const calls = (execSync as jest.Mock).mock.calls;
+ const amendCall = calls.find(call => call[0].includes('git commit --amend'));
+ expect(amendCall).toBeTruthy();
+ expect(amendCall[0]).toMatch(/New commit message/);
+
+ expect(lintCommitMessage).not.toHaveBeenCalled();
+ });
+
+ it('should abort amend if lint errors persist and user chooses not to re-edit', async () => {
+ (ensureGitRepo as jest.Mock).mockImplementation(() => { });
+ (loadConfig as jest.Mock).mockReturnValue({
+ enableLint: true,
+ lintRules: { /* ... */ },
+ });
+ (execSync as jest.Mock).mockReturnValueOnce('Old commit message\n');
+
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ amendConfirm: true })
+ .mockResolvedValueOnce({ newMessage: 'bad commit message' })
+ .mockResolvedValueOnce({ retry: false });
+
+ (lintCommitMessage as jest.Mock).mockReturnValue(['Error: summary too long']);
+
+ await expect(program.parseAsync(['node', 'test', 'amend']))
+ .rejects
+ .toThrow('process.exit: 1');
+
+ expect(execSync).toHaveBeenCalledTimes(1);
+ const calls = (execSync as jest.Mock).mock.calls;
+ const amendCall = calls.find(call => call[0].includes('git commit --amend'));
+ expect(amendCall).toBeUndefined();
+ });
+
+ it('should allow re-edit after lint errors and amend successfully', async () => {
+ (ensureGitRepo as jest.Mock).mockImplementation(() => { });
+ (loadConfig as jest.Mock).mockReturnValue({
+ enableLint: true,
+ lintRules: { /* ... */ },
+ });
+ (execSync as jest.Mock).mockReturnValueOnce('Old commit message\n');
+
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ amendConfirm: true })
+ .mockResolvedValueOnce({ newMessage: 'bad commit message' })
+ .mockResolvedValueOnce({ retry: true })
+ .mockResolvedValueOnce({ newMessage: 'good commit message' });
+
+ (lintCommitMessage as jest.Mock)
+ .mockReturnValueOnce(['Error: summary too long'])
+ .mockReturnValueOnce([]);
+
+ await program.parseAsync(['node', 'test', 'amend']);
+
+ const calls = (execSync as jest.Mock).mock.calls;
+ const amendCall = calls.find(call => call[0].includes('git commit --amend'));
+ expect(amendCall).toBeTruthy();
+ expect(amendCall[0]).toMatch(/good commit message/);
+ });
+
+ it('should catch execSync errors and exit with code 1', async () => {
+ (ensureGitRepo as jest.Mock).mockImplementation(() => { });
+ (loadConfig as jest.Mock).mockReturnValue({ enableLint: false });
+
+ (execSync as jest.Mock).mockImplementationOnce(() => {
+ throw new Error('git error');
+ });
+
+ await expect(program.parseAsync(['node', 'test', 'amend']))
+ .rejects
+ .toThrow('process.exit: 1');
+ });
+});
\ No newline at end of file
diff --git a/__tests__/branch.test.ts b/__tests__/branch.test.ts
new file mode 100644
index 0000000..0865c00
--- /dev/null
+++ b/__tests__/branch.test.ts
@@ -0,0 +1,184 @@
+import { execSync } from 'child_process';
+import { Command } from 'commander';
+import { loadConfig } from '../src/utils';
+import inquirer from 'inquirer';
+import { registerBranchCommand, sanitizeForBranch } from '../src/commands/branch';
+
+jest.mock('child_process', () => ({
+ execSync: jest.fn(),
+}));
+jest.mock('inquirer', () => ({
+ prompt: jest.fn(),
+}));
+jest.mock('../src/utils', () => ({
+ loadConfig: jest.fn(),
+ ensureGitRepo: jest.fn(),
+}));
+
+describe('sanitizeForBranch', () => {
+ it('should replace spaces with default separator and lowercase the input', () => {
+ const input = 'My Custom Branch';
+ const result = sanitizeForBranch(input);
+ expect(result).toBe('my-custom-branch');
+ });
+
+ it('should not convert to lowercase if lowercase is set to false', () => {
+ const input = 'My Custom Branch';
+ const result = sanitizeForBranch(input, { lowercase: false });
+ expect(result).toBe('My-Custom-Branch');
+ });
+
+ it('should replace spaces with a custom separator', () => {
+ const input = 'My Custom Branch';
+ const result = sanitizeForBranch(input, { separator: '_' });
+ expect(result).toBe('my_custom_branch');
+ });
+
+ it('should collapse multiple separators if collapseSeparator is true', () => {
+ const input = 'My Custom Branch';
+ const result = sanitizeForBranch(input, { separator: '-', collapseSeparator: true });
+ expect(result).toBe('my-custom-branch');
+ });
+
+ it('should not collapse separators if collapseSeparator is false', () => {
+ const input = 'My Custom Branch';
+ const result = sanitizeForBranch(input, { separator: '-', collapseSeparator: false });
+ expect(result).toBe('my---custom----branch');
+ });
+
+ it('should truncate the result to the specified maxLength', () => {
+ const input = 'this is a very long branch name that should be truncated';
+ const result = sanitizeForBranch(input, { maxLength: 20 });
+ expect(result.length).toBeLessThanOrEqual(20);
+ });
+
+ it('should remove invalid characters', () => {
+ const input = 'Branch@Name!#%';
+ const result = sanitizeForBranch(input);
+ expect(result).toBe('branchname');
+ });
+});
+
+describe('registerBranchCommand', () => {
+ let program: Command;
+
+ beforeEach(() => {
+ program = new Command();
+ (execSync as jest.Mock).mockReset();
+ (inquirer.prompt as unknown as jest.Mock).mockReset();
+ (loadConfig as jest.Mock).mockReturnValue({
+ branch: {
+ template: "{type}/{ticketId}-{shortDesc}",
+ types: [
+ { value: 'feat', description: 'Feature' },
+ { value: 'fix', description: 'Bug fix' }
+ ],
+ placeholders: {}
+ }
+ });
+ });
+
+ it('should create a branch with valid branch name using provided inputs', async () => {
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ baseBranchChoice: 'main' })
+ .mockResolvedValueOnce({ type: 'feat' })
+ .mockResolvedValueOnce({ ticketId: '123' })
+ .mockResolvedValueOnce({ shortDesc: 'add login' })
+ .mockResolvedValueOnce({ stayOnBranch: true });
+
+ registerBranchCommand(program);
+ await program.parseAsync(['node', 'test', 'branch']);
+
+ const calls = (execSync as jest.Mock).mock.calls;
+ const branchCommandCall = calls.find(call => call[0].includes('git checkout -b'));
+ expect(branchCommandCall[0]).toMatch(/feat\/123-add-login/);
+ });
+
+ it('should handle "Manual input..." for base branch', async () => {
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ baseBranchChoice: 'Manual input...' })
+ .mockResolvedValueOnce({ manualBranch: 'develop' })
+ .mockResolvedValueOnce({ type: 'fix' })
+ .mockResolvedValueOnce({ ticketId: '456' })
+ .mockResolvedValueOnce({ shortDesc: 'bug fix' })
+ .mockResolvedValueOnce({ stayOnBranch: true });
+
+ registerBranchCommand(program);
+ await program.parseAsync(['node', 'test', 'branch']);
+
+ const calls = (execSync as jest.Mock).mock.calls;
+ const branchCommandCall = calls.find(call => call[0].includes('git checkout -b'));
+ expect(branchCommandCall[0]).toMatch(/fix\/456-bug-fix/);
+ });
+
+ it('should prompt for custom branch type when "CUSTOM_INPUT" is selected', async () => {
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ baseBranchChoice: 'main' })
+ .mockResolvedValueOnce({ type: 'CUSTOM_INPUT' })
+ .mockResolvedValueOnce({ customType: 'custom' })
+ .mockResolvedValueOnce({ ticketId: '789' })
+ .mockResolvedValueOnce({ shortDesc: 'custom branch' })
+ .mockResolvedValueOnce({ stayOnBranch: true });
+
+ registerBranchCommand(program);
+ await program.parseAsync(['node', 'test', 'branch']);
+
+ const calls = (execSync as jest.Mock).mock.calls;
+ const branchCommandCall = calls.find(call => call[0].includes('git checkout -b'));
+ expect(branchCommandCall[0]).toMatch(/custom\/789-custom-branch/);
+ });
+
+ it('should generate fallback branch name if final branch name is empty', async () => {
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ baseBranchChoice: 'main' })
+ .mockResolvedValueOnce({ type: '' })
+ .mockResolvedValueOnce({ ticketId: '' })
+ .mockResolvedValueOnce({ shortDesc: '' })
+ .mockResolvedValueOnce({ stayOnBranch: true });
+
+ registerBranchCommand(program);
+ await program.parseAsync(['node', 'test', 'branch']);
+
+ const calls = (execSync as jest.Mock).mock.calls;
+ const branchCommandCall = calls.find(call => call[0].includes('git checkout -b'));
+ // new-branch-XXXX
+ expect(branchCommandCall[0]).toMatch(/new-branch-\d+/);
+ });
+
+ it('should switch back to the base branch when user opts not to stay on the new branch', async () => {
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ baseBranchChoice: 'main' })
+ .mockResolvedValueOnce({ type: 'feat' })
+ .mockResolvedValueOnce({ ticketId: '123' })
+ .mockResolvedValueOnce({ shortDesc: 'add feature' })
+ .mockResolvedValueOnce({ stayOnBranch: false });
+
+ registerBranchCommand(program);
+ await program.parseAsync(['node', 'test', 'branch']);
+
+ const calls = (execSync as jest.Mock).mock.calls;
+ const switchBackCall = calls.find(call => call[0].includes('git checkout "') && !call[0].includes('-b'));
+ expect(switchBackCall).toBeTruthy();
+ expect(switchBackCall[0]).toMatch(/git checkout "main"/);
+ });
+
+ it('should handle empty manual input for base branch and not attempt to switch back if base branch is empty', async () => {
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ baseBranchChoice: 'Manual input...' })
+ .mockResolvedValueOnce({ manualBranch: ' ' })
+ .mockResolvedValueOnce({ type: 'fix' })
+ .mockResolvedValueOnce({ ticketId: '456' })
+ .mockResolvedValueOnce({ shortDesc: 'fix bug' })
+ .mockResolvedValueOnce({ stayOnBranch: false });
+
+ registerBranchCommand(program);
+ await program.parseAsync(['node', 'test', 'branch']);
+
+ const calls = (execSync as jest.Mock).mock.calls;
+ const branchCommandCall = calls.find(call => call[0].includes('git checkout -b'));
+ expect(branchCommandCall[0]).toMatch(/^git checkout -b "[^"]+"$/);
+
+ const switchBackCall = calls.find(call => call[0].startsWith('git checkout "') && !call[0].includes('-b'));
+ expect(switchBackCall).toBeUndefined();
+ });
+});
\ No newline at end of file
diff --git a/__tests__/commit.test.ts b/__tests__/commit.test.ts
new file mode 100644
index 0000000..43fe93a
--- /dev/null
+++ b/__tests__/commit.test.ts
@@ -0,0 +1,414 @@
+import { Command } from 'commander';
+import { registerCommitCommand } from '../src/commands/commit';
+import {
+ loadConfig,
+ getUnstagedFiles,
+ loadGitignorePatterns,
+ stageSelectedFiles,
+ computeAutoSummary,
+ suggestCommitType,
+ previewCommitMessage,
+ ensureGitRepo,
+ showDiffPreview,
+} from '../src/utils';
+import inquirer from 'inquirer';
+import { execSync } from 'child_process';
+import micromatch from 'micromatch';
+
+jest.mock('inquirer', () => ({
+ prompt: jest.fn(),
+}));
+jest.mock('child_process', () => ({
+ execSync: jest.fn(),
+}));
+jest.mock('../src/utils', () => ({
+ loadConfig: jest.fn(),
+ getUnstagedFiles: jest.fn(),
+ loadGitignorePatterns: jest.fn(),
+ stageSelectedFiles: jest.fn(),
+ computeAutoSummary: jest.fn(),
+ suggestCommitType: jest.fn(),
+ previewCommitMessage: jest.fn(),
+ ensureGitRepo: jest.fn(),
+ showDiffPreview: jest.fn(),
+}));
+jest.mock('micromatch', () => ({
+ isMatch: jest.fn(),
+}));
+
+describe('registerCommitCommand', () => {
+ let program: Command;
+ let mockExit: jest.SpyInstance;
+
+ beforeEach(() => {
+ program = new Command();
+ registerCommitCommand(program);
+
+ (inquirer.prompt as unknown as jest.Mock).mockReset();
+ (execSync as jest.Mock).mockReset();
+ (loadConfig as jest.Mock).mockReset();
+ (getUnstagedFiles as jest.Mock).mockReset();
+ (loadGitignorePatterns as jest.Mock).mockReset();
+ (stageSelectedFiles as jest.Mock).mockReset();
+ (computeAutoSummary as jest.Mock).mockReset();
+ (suggestCommitType as jest.Mock).mockReset();
+ (previewCommitMessage as jest.Mock).mockReset();
+ (ensureGitRepo as jest.Mock).mockReset();
+ (showDiffPreview as jest.Mock).mockReset();
+ (micromatch.isMatch as jest.Mock).mockReset();
+
+ mockExit = jest.spyOn(process, 'exit').mockImplementation((code?: string | number | null | undefined) => {
+ throw new Error(`process.exit: ${code}`);
+ });
+ });
+
+ afterEach(() => {
+ mockExit.mockRestore();
+ });
+
+ it('should fail if not a git repo', async () => {
+ (ensureGitRepo as jest.Mock).mockImplementation(() => { throw new Error('Not a Git repo'); });
+ await expect(program.parseAsync(['node', 'test', 'commit'])).rejects.toThrow('Not a Git repo');
+ });
+
+ it('should abort if no unstaged files (manual staging)', async () => {
+ (ensureGitRepo as jest.Mock).mockImplementation(() => { });
+ (loadConfig as jest.Mock).mockReturnValue({
+ autoAdd: false,
+ commitTypes: [],
+ useEmoji: true,
+ steps: {},
+ templates: { defaultTemplate: '[{type}]: {summary}' },
+ });
+ (getUnstagedFiles as jest.Mock).mockReturnValue([]);
+ (loadGitignorePatterns as jest.Mock).mockReturnValue([]);
+ (execSync as jest.Mock).mockReturnValueOnce('').mockReturnValue('');
+ await expect(program.parseAsync(['node', 'test', 'commit'])).resolves.not.toThrow();
+ expect(stageSelectedFiles).not.toHaveBeenCalled();
+ });
+
+ it('should let user pick files then abort if no changes staged', async () => {
+ (ensureGitRepo as jest.Mock).mockImplementation(() => { });
+ (loadConfig as jest.Mock).mockReturnValue({
+ autoAdd: false,
+ commitTypes: [{ emoji: '✨', value: 'feat', description: 'feature' }],
+ useEmoji: true,
+ steps: {},
+ templates: { defaultTemplate: '[{type}]: {summary}' },
+ });
+ (getUnstagedFiles as jest.Mock).mockReturnValue(['src/a.ts', 'test/b.ts']);
+ (loadGitignorePatterns as jest.Mock).mockReturnValue([]);
+ (micromatch.isMatch as jest.Mock).mockReturnValue(false);
+ (inquirer.prompt as unknown as jest.Mock).mockResolvedValueOnce({ files: ['src/a.ts', 'test/b.ts'] });
+ (execSync as jest.Mock).mockReturnValueOnce('').mockReturnValue('');
+ await expect(program.parseAsync(['node', 'test', 'commit'])).resolves.not.toThrow();
+ expect(stageSelectedFiles).toHaveBeenCalledWith(['src/a.ts', 'test/b.ts']);
+ });
+
+ it('should auto-add files if autoAdd=true then abort if no changes staged', async () => {
+ (ensureGitRepo as jest.Mock).mockImplementation(() => { });
+ (loadConfig as jest.Mock).mockReturnValue({
+ autoAdd: true,
+ commitTypes: [],
+ useEmoji: true,
+ steps: {},
+ templates: {},
+ });
+ (getUnstagedFiles as jest.Mock).mockReturnValue(['src/x.ts']);
+ (loadGitignorePatterns as jest.Mock).mockReturnValue([]);
+ (micromatch.isMatch as jest.Mock).mockReturnValue(false);
+ (execSync as jest.Mock).mockReturnValue('');
+ await expect(program.parseAsync(['node', 'test', 'commit'])).resolves.not.toThrow();
+ expect(stageSelectedFiles).toHaveBeenCalledWith(['src/x.ts']);
+ });
+
+ it('should ask main questions and commit if all is good (no diff preview, no lint, no CI)', async () => {
+ (ensureGitRepo as jest.Mock).mockImplementation(() => { });
+ (loadConfig as jest.Mock).mockReturnValue({
+ autoAdd: false,
+ commitTypes: [
+ { emoji: '✨', value: 'feat', description: 'feature' },
+ { emoji: '🐛', value: 'fix', description: 'bug fix' }
+ ],
+ useEmoji: true,
+ steps: { scope: true, body: false, footer: false, ticket: false, runCI: false },
+ templates: { defaultTemplate: '[{type}]{scope}: {summary}' },
+ enableLint: false
+ });
+ (getUnstagedFiles as jest.Mock).mockReturnValue(['a.js']);
+ (loadGitignorePatterns as jest.Mock).mockReturnValue([]);
+ (micromatch.isMatch as jest.Mock).mockReturnValue(false);
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ files: ['a.js'] })
+ .mockResolvedValueOnce({ type: 'feat', scope: 'myScope', summary: 'My summary', pushCommit: false })
+ .mockResolvedValueOnce({ diffPreview: false })
+ .mockResolvedValueOnce({ previewChoice: false })
+ .mockResolvedValueOnce({ finalConfirm: true });
+ (execSync as jest.Mock)
+ .mockReturnValueOnce('a.js\n')
+ .mockReturnValueOnce('a.js\n')
+ .mockReturnValueOnce('');
+ (computeAutoSummary as jest.Mock).mockReturnValue('AutoSummary');
+ (suggestCommitType as jest.Mock).mockReturnValue('feat');
+ await program.parseAsync(['node', 'test', 'commit']);
+ const calls = (execSync as jest.Mock).mock.calls;
+ const commitCall = calls.find(c => c[0].includes('git commit'));
+ expect(commitCall).toBeTruthy();
+ expect(commitCall[0]).toMatch(/\[feat\]\(myScope\): My summary/);
+ });
+
+ it('should run CI and fail, causing exit(1) and no commit', async () => {
+ (ensureGitRepo as jest.Mock).mockImplementation(() => { });
+ (loadConfig as jest.Mock).mockReturnValue({
+ autoAdd: false,
+ commitTypes: [],
+ useEmoji: true,
+ steps: { runCI: true },
+ ciCommand: 'npm test',
+ templates: { defaultTemplate: '[{type}]: {summary}' },
+ enableLint: false
+ });
+ (getUnstagedFiles as jest.Mock).mockReturnValue(['file.js']);
+ (loadGitignorePatterns as jest.Mock).mockReturnValue([]);
+ (micromatch.isMatch as jest.Mock).mockReturnValue(false);
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ files: ['file.js'] })
+ .mockResolvedValueOnce({ type: 'fix', summary: 'some fix', runCI: true, pushCommit: false })
+ .mockResolvedValueOnce({ diffPreview: false })
+ .mockResolvedValueOnce({ previewChoice: false })
+ .mockResolvedValueOnce({ finalConfirm: true });
+ (execSync as jest.Mock)
+ .mockReturnValueOnce('file.js\n')
+ .mockImplementationOnce(() => { throw new Error('Tests failed'); });
+ await expect(program.parseAsync(['node', 'test', 'commit'])).rejects.toThrow('process.exit: 1');
+ expect((execSync as jest.Mock).mock.calls.some(call => call[0].includes('git commit'))).toBe(false);
+ });
+
+ it('should show diff preview and abort if user declines diff confirm', async () => {
+ (ensureGitRepo as jest.Mock).mockImplementation(() => { });
+ (loadConfig as jest.Mock).mockReturnValue({
+ steps: { runCI: false },
+ commitTypes: [{ value: 'feat' }],
+ templates: { defaultTemplate: '' },
+ enableLint: false
+ });
+ (getUnstagedFiles as jest.Mock).mockReturnValue(['f1']);
+ (loadGitignorePatterns as jest.Mock).mockReturnValue([]);
+ (micromatch.isMatch as jest.Mock).mockReturnValue(false);
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ files: ['f1'] })
+ .mockResolvedValueOnce({ type: 'feat', summary: 'summary', pushCommit: false })
+ .mockResolvedValueOnce({ diffPreview: true })
+ .mockResolvedValueOnce({ diffConfirm: false });
+ (execSync as jest.Mock)
+ .mockReturnValueOnce('f1\n')
+ .mockReturnValueOnce('f1\n');
+ (showDiffPreview as jest.Mock).mockImplementation(() => { });
+ await expect(program.parseAsync(['node', 'test', 'commit'])).resolves.not.toThrow();
+ expect((execSync as jest.Mock).mock.calls.some(call => call[0].includes('git commit'))).toBe(false);
+ });
+
+ it('should call previewCommitMessage if lint=true and fail, causing exit(1)', async () => {
+ (ensureGitRepo as jest.Mock).mockImplementation(() => { });
+ (loadConfig as jest.Mock).mockReturnValue({
+ autoAdd: false,
+ commitTypes: [{ value: 'feat' }],
+ templates: { defaultTemplate: '[{type}]: {summary}' },
+ steps: {},
+ enableLint: true
+ });
+ (getUnstagedFiles as jest.Mock).mockReturnValue(['x.ts']);
+ (loadGitignorePatterns as jest.Mock).mockReturnValue([]);
+ (micromatch.isMatch as jest.Mock).mockReturnValue(false);
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ files: ['x.ts'] })
+ .mockResolvedValueOnce({ type: 'feat', scope: '', summary: 'some', pushCommit: false })
+ .mockResolvedValueOnce({ diffPreview: false });
+ (execSync as jest.Mock)
+ .mockReturnValueOnce('x.ts\n')
+ .mockReturnValueOnce('x.ts\n');
+ (previewCommitMessage as jest.Mock).mockImplementation(() => { throw new Error('lint fail'); });
+ await expect(program.parseAsync(['node', 'test', 'commit', '--lint'])).rejects.toThrow('lint fail');
+ expect((execSync as jest.Mock).mock.calls.some(c => c[0].includes('git commit'))).toBe(false);
+ });
+
+ it('should skip lint, show preview, and abort if finalConfirm is false', async () => {
+ (ensureGitRepo as jest.Mock).mockImplementation(() => { });
+ (loadConfig as jest.Mock).mockReturnValue({
+ autoAdd: false,
+ commitTypes: [{ value: 'feat' }],
+ templates: { defaultTemplate: '[{type}]: {summary}' },
+ steps: {}
+ });
+ (getUnstagedFiles as jest.Mock).mockReturnValue(['abc']);
+ (loadGitignorePatterns as jest.Mock).mockReturnValue([]);
+ (micromatch.isMatch as jest.Mock).mockReturnValue(false);
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ files: ['abc'] })
+ .mockResolvedValueOnce({ type: 'feat', scope: '', summary: 'summary', pushCommit: false })
+ .mockResolvedValueOnce({ diffPreview: false })
+ .mockResolvedValueOnce({ previewChoice: true })
+ .mockResolvedValueOnce({ finalConfirm: false });
+ (execSync as jest.Mock)
+ .mockReturnValueOnce('abc\n')
+ .mockReturnValueOnce('abc\n');
+ await expect(program.parseAsync(['node', 'test', 'commit'])).resolves.not.toThrow();
+ expect((execSync as jest.Mock).mock.calls.some(call => call[0].includes('git commit'))).toBe(false);
+ });
+
+ it('should commit and push if pushCommit=true', async () => {
+ (ensureGitRepo as jest.Mock).mockImplementation(() => { });
+ (loadConfig as jest.Mock).mockReturnValue({
+ autoAdd: false,
+ commitTypes: [{ value: 'fix' }],
+ templates: { defaultTemplate: '[{type}]: {summary}' },
+ steps: {}
+ });
+ (getUnstagedFiles as jest.Mock).mockReturnValue(['file']);
+ (loadGitignorePatterns as jest.Mock).mockReturnValue([]);
+ (micromatch.isMatch as jest.Mock).mockReturnValue(false);
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ files: ['file'] })
+ .mockResolvedValueOnce({ type: 'fix', scope: '', summary: 'fix something', pushCommit: true })
+ .mockResolvedValueOnce({ diffPreview: false })
+ .mockResolvedValueOnce({ previewChoice: false })
+ .mockResolvedValueOnce({ finalConfirm: true });
+ (execSync as jest.Mock)
+ .mockReturnValueOnce('file\n')
+ .mockReturnValueOnce('file\n')
+ .mockReturnValueOnce('') // commit
+ .mockReturnValueOnce(''); // push
+ await program.parseAsync(['node', 'test', 'commit']);
+ const calls = (execSync as jest.Mock).mock.calls;
+ const commitCall = calls.find(c => c[0].includes('git commit -m'));
+ expect(commitCall).toBeTruthy();
+ expect(commitCall[0]).toMatch(/\[fix\]\: fix something/);
+ const pushCall = calls.find(c => c[0] === 'git push');
+ expect(pushCall).toBeTruthy();
+ });
+
+ it('should do git commit -S if --sign is true', async () => {
+ (ensureGitRepo as jest.Mock).mockImplementation(() => { });
+ (loadConfig as jest.Mock).mockReturnValue({
+ autoAdd: false,
+ commitTypes: [{ value: 'chore' }],
+ templates: { defaultTemplate: '[{type}]: {summary}' },
+ steps: {}
+ });
+ (getUnstagedFiles as jest.Mock).mockReturnValue(['xxx']);
+ (loadGitignorePatterns as jest.Mock).mockReturnValue([]);
+ (micromatch.isMatch as jest.Mock).mockReturnValue(false);
+ (execSync as jest.Mock)
+ .mockReturnValueOnce('xxx\n')
+ .mockReturnValueOnce('xxx\n')
+ .mockReturnValueOnce('');
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ files: ['xxx'] })
+ .mockResolvedValueOnce({ type: 'chore', scope: '', summary: 'some chore', pushCommit: false })
+ .mockResolvedValueOnce({ diffPreview: false })
+ .mockResolvedValueOnce({ previewChoice: false })
+ .mockResolvedValueOnce({ finalConfirm: true });
+ await program.parseAsync(['node', 'test', 'commit', '--sign']);
+ const calls = (execSync as jest.Mock).mock.calls;
+ const commitCall = calls.find(c => c[0].includes('git commit -S -m'));
+ expect(commitCall).toBeTruthy();
+ expect(commitCall[0]).toMatch(/some chore/);
+ });
+
+ it('should extract ticket from branch name if config.ticket is enabled and ticket is empty', async () => {
+ (ensureGitRepo as jest.Mock).mockImplementation(() => {});
+ (loadConfig as jest.Mock).mockReturnValue({
+ autoAdd: false,
+ commitTypes: [{ emoji: '✨', value: 'feat', description: 'feature' }],
+ useEmoji: true,
+ steps: { ticket: true },
+ templates: { defaultTemplate: '[{ticket}]{ticketSeparator}[{type}]: {summary}' },
+ ticketRegex: 'ABC-\\d+',
+ enableLint: false
+ });
+ (getUnstagedFiles as jest.Mock).mockReturnValue(['file1.js']);
+ (loadGitignorePatterns as jest.Mock).mockReturnValue([]);
+ (micromatch.isMatch as jest.Mock).mockReturnValue(false);
+
+ const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
+
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ files: ['file1.js'] })
+ .mockResolvedValueOnce({ type: 'feat', summary: 'added feature', pushCommit: false })
+ .mockResolvedValueOnce({ ticket: '' })
+ .mockResolvedValueOnce({ diffPreview: false })
+ .mockResolvedValueOnce({ previewChoice: false })
+ .mockResolvedValueOnce({ finalConfirm: true });
+
+ (execSync as jest.Mock).mockImplementation((cmd: string, options: any) => {
+ if (cmd.startsWith('git diff --cached')) {
+ return 'file1.js\n';
+ }
+ if (cmd.startsWith('git rev-parse --abbrev-ref HEAD')) {
+ return 'ABC-123-feature';
+ }
+ return 'file1.js\n';
+ });
+
+ await program.parseAsync(['commit'], { from: 'user' });
+
+ expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('Extracted ticket from branch: ABC-123'));
+ consoleLogSpy.mockRestore();
+ });
+
+ it('should commit if diff preview is shown and confirmed', async () => {
+ (ensureGitRepo as jest.Mock).mockImplementation(() => {});
+ (loadConfig as jest.Mock).mockReturnValue({
+ autoAdd: false,
+ commitTypes: [{ value: 'fix' }],
+ useEmoji: false,
+ steps: {},
+ templates: { defaultTemplate: '[{type}]: {summary}' },
+ enableLint: false
+ });
+ (getUnstagedFiles as jest.Mock).mockReturnValue(['update.js']);
+ (loadGitignorePatterns as jest.Mock).mockReturnValue([]);
+ (micromatch.isMatch as jest.Mock).mockReturnValue(false);
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ files: ['update.js'] })
+ .mockResolvedValueOnce({ type: 'fix', scope: '', summary: 'bug fix', pushCommit: false })
+ .mockResolvedValueOnce({ diffPreview: true })
+ .mockResolvedValueOnce({ diffConfirm: true })
+ .mockResolvedValueOnce({ previewChoice: false })
+ .mockResolvedValueOnce({ finalConfirm: true });
+ (execSync as jest.Mock)
+ .mockReturnValueOnce('update.js\n')
+ .mockReturnValueOnce('update.js\n');
+ (showDiffPreview as jest.Mock).mockImplementation(() => {});
+ await program.parseAsync(['commit'], { from: 'user' });
+ const commitCall = (execSync as jest.Mock).mock.calls.find(call => call[0].includes('git commit'));
+ expect(commitCall).toBeTruthy();
+ });
+
+ it('should abort commit if no staged changes remain after diff preview', async () => {
+ (ensureGitRepo as jest.Mock).mockImplementation(() => {});
+ (loadConfig as jest.Mock).mockReturnValue({
+ autoAdd: false,
+ commitTypes: [{ value: 'chore' }],
+ useEmoji: false,
+ steps: {},
+ templates: { defaultTemplate: '[{type}]: {summary}' },
+ enableLint: false
+ });
+ (getUnstagedFiles as jest.Mock).mockReturnValue(['script.js']);
+ (loadGitignorePatterns as jest.Mock).mockReturnValue([]);
+ (micromatch.isMatch as jest.Mock).mockReturnValue(false);
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ files: ['script.js'] })
+ .mockResolvedValueOnce({ type: 'chore', scope: '', summary: 'cleanup', pushCommit: false })
+ .mockResolvedValueOnce({ diffPreview: true })
+ .mockResolvedValueOnce({ diffConfirm: false });
+ (execSync as jest.Mock)
+ .mockReturnValueOnce('script.js\n')
+ .mockReturnValueOnce('');
+ (showDiffPreview as jest.Mock).mockImplementation(() => {});
+ await expect(program.parseAsync(['commit'], { from: 'user' })).resolves.not.toThrow();
+ const commitCall = (execSync as jest.Mock).mock.calls.find(call => call[0].includes('git commit'));
+ expect(commitCall).toBeUndefined();
+ });
+});
\ No newline at end of file
diff --git a/__tests__/config.test.ts b/__tests__/config.test.ts
new file mode 100644
index 0000000..475b5a9
--- /dev/null
+++ b/__tests__/config.test.ts
@@ -0,0 +1,216 @@
+import { Command } from 'commander';
+import { registerConfigCommand } from '../src/commands/config';
+import { defaultConfig, loadConfig, saveConfig } from '../src/utils';
+
+jest.mock('../src/utils', () => ({
+ loadConfig: jest.fn(),
+ saveConfig: jest.fn(),
+ defaultConfig: {
+ autoAdd: false,
+ useEmoji: true,
+ ciCommand: "",
+ templates: { defaultTemplate: "[{type}]{ticketSeparator}{ticket}: {summary}" },
+ steps: { scope: false, body: false, footer: false, ticket: false, runCI: false },
+ ticketRegex: "",
+ enableLint: false,
+ lintRules: { summaryMaxLength: 72, typeCase: "lowercase", requiredTicket: false },
+ commitTypes: [
+ { emoji: "✨", value: "feat", description: "A new feature" },
+ { emoji: "🐛", value: "fix", description: "A bug fix" }
+ ],
+ branch: {
+ template: "{type}/{ticketId}-{shortDesc}",
+ types: [
+ { value: "feature", description: "New feature" },
+ { value: "fix", description: "Bug fix" }
+ ],
+ placeholders: { ticketId: { lowercase: false } }
+ }
+ },
+}));
+
+jest.mock('chalk', () => ({
+ ...jest.requireActual('chalk'),
+ blue: jest.fn((str) => str),
+ red: jest.fn((str) => str),
+ green: jest.fn((str) => str),
+}));
+
+describe('registerConfigCommand with --reset', () => {
+ let program: Command;
+ let saveConfigMock: jest.Mock;
+ let consoleLogSpy: jest.SpyInstance;
+
+ beforeEach(() => {
+ program = new Command();
+ registerConfigCommand(program);
+ saveConfigMock = saveConfig as jest.Mock;
+ saveConfigMock.mockReset();
+ consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
+ });
+
+ afterEach(() => {
+ consoleLogSpy.mockRestore();
+ jest.resetAllMocks();
+ });
+
+ it('should reset configuration to default when --reset is passed', async () => {
+ await program.parseAsync(['node', 'test', 'config', '--reset']);
+ expect(saveConfigMock).toHaveBeenCalledWith(defaultConfig);
+ expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining("Configuration has been reset to default settings."));
+ });
+});
+
+describe('registerConfigCommand', () => {
+ let program: Command;
+ let mockLoadConfig: jest.Mock;
+ let mockSaveConfig: jest.Mock;
+ let consoleLogSpy: jest.SpyInstance;
+ let consoleErrorSpy: jest.SpyInstance;
+
+ beforeEach(() => {
+ program = new Command();
+ registerConfigCommand(program);
+
+ mockLoadConfig = loadConfig as jest.Mock;
+ mockSaveConfig = saveConfig as jest.Mock;
+
+ mockLoadConfig.mockReturnValue({
+ autoAdd: false,
+ useEmoji: true,
+ ciCommand: "",
+ templates: {
+ defaultTemplate: "[{type}]{ticketSeparator}{ticket}: {summary}"
+ },
+ steps: {
+ scope: false,
+ body: false,
+ footer: false,
+ ticket: false,
+ runCI: false
+ },
+ ticketRegex: "",
+ enableLint: false,
+ lintRules: {
+ summaryMaxLength: 72,
+ typeCase: "lowercase",
+ requiredTicket: false
+ },
+ commitTypes: [
+ { emoji: "✨", value: "feat", description: "A new feature" },
+ { emoji: "🐛", value: "fix", description: "A bug fix" }
+ ],
+ branch: {
+ template: "{type}/{ticketId}-{shortDesc}",
+ types: [
+ { value: "feature", description: "New feature" },
+ { value: "fix", description: "Bug fix" }
+ ],
+ placeholders: {
+ ticketId: { lowercase: false }
+ }
+ }
+ });
+
+ consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
+ consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => { });
+ });
+
+ afterEach(() => {
+ consoleLogSpy.mockRestore();
+ consoleErrorSpy.mockRestore();
+ jest.resetAllMocks();
+ });
+
+ it('prints current config if no flags are passed', async () => {
+ const tableSpy = jest.spyOn(console, 'table').mockImplementation(() => { });
+ await program.parseAsync(['node', 'test', 'config']);
+
+ expect(saveConfig).not.toHaveBeenCalled();
+ expect(tableSpy).toHaveBeenCalledWith(expect.arrayContaining([
+ expect.objectContaining({ Key: 'autoAdd', Value: false })
+ ]));
+ tableSpy.mockRestore();
+ });
+
+ it('updates autoAdd when passing --auto-add true', async () => {
+ await program.parseAsync(['node', 'test', 'config', '--auto-add', 'true']);
+
+ expect(mockLoadConfig).toHaveBeenCalled();
+ expect(saveConfig).toHaveBeenCalledTimes(1);
+ const updatedConfig = (saveConfig as jest.Mock).mock.calls[0][0];
+ expect(updatedConfig.autoAdd).toBe(true);
+ });
+
+ it('updates multiple fields in one go', async () => {
+ await program.parseAsync([
+ 'node',
+ 'test',
+ 'config',
+ '--auto-add',
+ 'true',
+ '--enable-body',
+ 'true',
+ '--enable-run-ci',
+ 'true',
+ '--ci-command',
+ 'npm run test'
+ ]);
+ expect(saveConfig).toHaveBeenCalledTimes(1);
+ const updatedConfig = (saveConfig as jest.Mock).mock.calls[0][0];
+ expect(updatedConfig.autoAdd).toBe(true);
+ expect(updatedConfig.steps.body).toBe(true);
+ expect(updatedConfig.steps.runCI).toBe(true);
+ expect(updatedConfig.ciCommand).toBe('npm run test');
+ });
+
+ it('parses valid JSON in --branch-type and updates config', async () => {
+ const validJson = '[{"value":"hotfix","description":"Hotfix branch"}]';
+ await program.parseAsync(['node', 'test', 'config', '--branch-type', validJson]);
+ expect(saveConfig).toHaveBeenCalledTimes(1);
+ const updatedConfig = (saveConfig as jest.Mock).mock.calls[0][0];
+ expect(updatedConfig.branch.types).toEqual([
+ { value: "hotfix", description: "Hotfix branch" }
+ ]);
+ });
+
+ it('logs error if invalid JSON in --branch-type', async () => {
+ const invalidJson = '{"not":"an array"}';
+ await program.parseAsync(['node', 'test', 'config', '--branch-type', invalidJson]);
+
+ expect(consoleErrorSpy).toHaveBeenCalledWith(
+ expect.stringContaining("branch-type JSON must be an array of objects!")
+ );
+ expect(saveConfig).not.toHaveBeenCalled();
+ });
+
+ it('parses valid JSON in --branch-placeholder and updates config', async () => {
+ const validJson = '{"ticketId": {"maxLength":10,"separator":"_"}}';
+ await program.parseAsync(['node', 'test', 'config', '--branch-placeholder', validJson]);
+ expect(saveConfig).toHaveBeenCalledTimes(1);
+ const updatedConfig = (saveConfig as jest.Mock).mock.calls[0][0];
+ expect(updatedConfig.branch.placeholders).toEqual({
+ ticketId: { maxLength: 10, separator: "_" }
+ });
+ });
+
+ it('logs error if invalid JSON in --branch-placeholder', async () => {
+ const invalidJson = 'not valid json...';
+ await program.parseAsync(['node', 'test', 'config', '--branch-placeholder', invalidJson]);
+
+ expect(consoleErrorSpy).toHaveBeenCalledTimes(1);
+ const [firstArg, secondArg] = consoleErrorSpy.mock.calls[0];
+
+ expect(firstArg).toContain("Invalid JSON for --branch-placeholder:");
+ expect(secondArg).toBeInstanceOf(SyntaxError);
+
+ expect(saveConfig).not.toHaveBeenCalled();
+ });
+
+ it('updates enableLint if passed --enable-lint true', async () => {
+ await program.parseAsync(['node', 'test', 'config', '--enable-lint', 'true']);
+ expect(saveConfig).toHaveBeenCalledTimes(1);
+ const updatedConfig = (saveConfig as jest.Mock).mock.calls[0][0];
+ expect(updatedConfig.enableLint).toBe(true);
+ });
+});
\ No newline at end of file
diff --git a/__tests__/history.test.ts b/__tests__/history.test.ts
new file mode 100644
index 0000000..a98aa0d
--- /dev/null
+++ b/__tests__/history.test.ts
@@ -0,0 +1,141 @@
+import { Command } from 'commander';
+import { registerHistoryCommand } from '../src/commands/history';
+import inquirer from 'inquirer';
+import { execSync } from 'child_process';
+import { ensureGitRepo } from '../src/utils';
+import chalk from 'chalk';
+
+jest.mock('inquirer', () => ({
+ prompt: jest.fn(),
+}));
+jest.mock('child_process', () => ({
+ execSync: jest.fn(),
+}));
+jest.mock('../src/utils', () => ({
+ ensureGitRepo: jest.fn(),
+}));
+
+describe('registerHistoryCommand', () => {
+ let program: Command;
+ let consoleLogSpy: jest.SpyInstance;
+ let consoleErrorSpy: jest.SpyInstance;
+ let mockExit: jest.SpyInstance;
+
+ beforeEach(() => {
+ program = new Command();
+ registerHistoryCommand(program);
+ consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
+ consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => { });
+ mockExit = jest.spyOn(process, 'exit').mockImplementation((code?: number | string | null | undefined) => {
+ throw new Error(`process.exit: ${code}`);
+ });
+ (inquirer.prompt as unknown as jest.Mock).mockReset();
+ (execSync as jest.Mock).mockReset();
+ (ensureGitRepo as jest.Mock).mockReset();
+ });
+
+ afterEach(() => {
+ consoleLogSpy.mockRestore();
+ consoleErrorSpy.mockRestore();
+ mockExit.mockRestore();
+ });
+
+ it('should build and paginate the command correctly for filterType "keyword"', async () => {
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ filterType: 'keyword', viewMode: 'merged' })
+ .mockResolvedValueOnce({ keyword: 'fix' })
+ .mockResolvedValueOnce({ limit: '20' })
+ .mockResolvedValueOnce({ showMore: false });
+
+ (execSync as jest.Mock).mockReturnValueOnce('commit1\ncommit2\n');
+
+ await program.parseAsync(['node', 'test', 'history']);
+
+ expect(ensureGitRepo).toHaveBeenCalled();
+ expect(inquirer.prompt).toHaveBeenCalledTimes(4);
+ expect(execSync).toHaveBeenCalledWith(
+ 'git log --pretty=oneline --grep="fix" --max-count=20 --skip=0',
+ { encoding: 'utf8' }
+ );
+ expect(consoleLogSpy).toHaveBeenCalledWith(chalk.blue("\nCommit History:\n"));
+ expect(consoleLogSpy).toHaveBeenCalledWith(chalk.green('commit1\ncommit2\n'));
+ });
+
+ it('should build and paginate the command correctly for filterType "author"', async () => {
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ filterType: 'author', viewMode: 'merged' })
+ .mockResolvedValueOnce({ author: 'john@example.com' })
+ .mockResolvedValueOnce({ limit: '15' })
+ .mockResolvedValueOnce({ showMore: false });
+ (execSync as jest.Mock).mockReturnValueOnce('commitA\ncommitB\n');
+
+ await program.parseAsync(['node', 'test', 'history']);
+
+ expect(inquirer.prompt).toHaveBeenCalledTimes(4);
+ expect(execSync).toHaveBeenCalledWith(
+ 'git log --pretty=oneline --author="john@example.com" --max-count=15 --skip=0',
+ { encoding: 'utf8' }
+ );
+ expect(consoleLogSpy).toHaveBeenCalledWith(chalk.green('commitA\ncommitB\n'));
+ });
+
+ it('should build and paginate the command correctly for filterType "date"', async () => {
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ filterType: 'date', viewMode: 'merged' })
+ .mockResolvedValueOnce({ since: '2023-01-01', until: '2023-01-31' })
+ .mockResolvedValueOnce({ limit: '10' })
+ .mockResolvedValueOnce({ showMore: false });
+ (execSync as jest.Mock).mockReturnValueOnce('commitX\ncommitY\n');
+
+ await program.parseAsync(['node', 'test', 'history']);
+
+ expect(inquirer.prompt).toHaveBeenCalledTimes(4);
+ expect(execSync).toHaveBeenCalledWith(
+ 'git log --pretty=oneline --since="2023-01-01" --until="2023-01-31" --max-count=10 --skip=0',
+ { encoding: 'utf8' }
+ );
+ expect(consoleLogSpy).toHaveBeenCalledWith(chalk.green('commitX\ncommitY\n'));
+ });
+
+ it('should paginate over multiple pages if user selects to show more', async () => {
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ filterType: 'keyword', viewMode: 'merged' })
+ .mockResolvedValueOnce({ keyword: 'update' })
+ .mockResolvedValueOnce({ limit: '5' })
+ .mockResolvedValueOnce({ showMore: true })
+ .mockResolvedValueOnce({ showMore: false });
+
+ (execSync as jest.Mock)
+ .mockReturnValueOnce('commit1\ncommit2\ncommit3\ncommit4\ncommit5\n')
+ .mockReturnValueOnce('');
+
+ await program.parseAsync(['node', 'test', 'history']);
+
+ expect(execSync).toHaveBeenNthCalledWith(
+ 1,
+ 'git log --pretty=oneline --grep="update" --max-count=5 --skip=0',
+ { encoding: 'utf8' }
+ );
+ expect(execSync).toHaveBeenNthCalledWith(
+ 2,
+ 'git log --pretty=oneline --grep="update" --max-count=5 --skip=5',
+ { encoding: 'utf8' }
+ );
+ });
+
+ it('should log error and exit if execSync fails during pagination', async () => {
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ filterType: 'keyword', viewMode: 'merged' })
+ .mockResolvedValueOnce({ keyword: 'error' })
+ .mockResolvedValueOnce({ limit: '20' })
+ .mockResolvedValueOnce({ showMore: false });
+ (execSync as jest.Mock).mockImplementation(() => {
+ throw new Error('Git error occurred');
+ });
+
+ await expect(program.parseAsync(['node', 'test', 'history']))
+ .rejects.toThrow('process.exit: 1');
+
+ expect(consoleErrorSpy).toHaveBeenCalledWith(chalk.red("Error retrieving history:"), 'Git error occurred');
+ });
+});
\ No newline at end of file
diff --git a/__tests__/rebaseHelper.test.ts b/__tests__/rebaseHelper.test.ts
new file mode 100644
index 0000000..053827f
--- /dev/null
+++ b/__tests__/rebaseHelper.test.ts
@@ -0,0 +1,73 @@
+import { Command } from 'commander';
+import inquirer from 'inquirer';
+import { registerRebaseHelperCommand } from '../src/commands/rebaseHelper';
+import { ensureGitRepo } from '../src/utils';
+
+jest.mock('inquirer');
+jest.mock('../src/utils', () => ({
+ ensureGitRepo: jest.fn()
+}));
+
+describe('registerRebaseHelperCommand', () => {
+ let program: Command;
+ let exitSpy: jest.SpyInstance;
+ let execSyncSpy: jest.SpyInstance;
+ let consoleLogSpy: jest.SpyInstance;
+ let consoleErrorSpy: jest.SpyInstance;
+
+ beforeEach(() => {
+ program = new Command();
+ registerRebaseHelperCommand(program);
+ exitSpy = jest.spyOn(process, 'exit').mockImplementation((code?: string | number | null | undefined) => {
+ throw new Error(`process.exit: ${code}`);
+ });
+ execSyncSpy = jest.spyOn(require('child_process'), 'execSync').mockImplementation(() => {});
+ consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
+ consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
+ });
+
+ afterEach(() => {
+ jest.restoreAllMocks();
+ });
+
+ test('executes rebase when valid inputs and confirmed', async () => {
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ commitCount: '3' })
+ .mockResolvedValueOnce({ confirm: true });
+
+ await program.parseAsync(['rebase-helper'], { from: 'user' });
+
+ expect(ensureGitRepo).toHaveBeenCalled();
+ expect(execSyncSpy).toHaveBeenCalledWith('git rebase -i HEAD~3', { stdio: 'inherit' });
+ expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('Interactive rebase completed.'));
+ });
+
+ test('aborts rebase when user does not confirm', async () => {
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ commitCount: '5' })
+ .mockResolvedValueOnce({ confirm: false });
+
+ await expect(program.parseAsync(['rebase-helper'], { from: 'user' }))
+ .rejects.toThrow('process.exit: 0');
+
+ expect(execSyncSpy).not.toHaveBeenCalled();
+ expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining('Rebase aborted by user.'));
+ });
+
+ test('exits with error if execSync throws an error', async () => {
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ commitCount: '2' })
+ .mockResolvedValueOnce({ confirm: true });
+
+ const errorMessage = 'Simulated exec error';
+ execSyncSpy.mockImplementation(() => { throw new Error(errorMessage); });
+
+ await expect(program.parseAsync(['rebase-helper'], { from: 'user' }))
+ .rejects.toThrow('process.exit: 1');
+
+ expect(consoleErrorSpy).toHaveBeenCalledWith(
+ expect.stringContaining('Error during interactive rebase:'),
+ expect.stringContaining(errorMessage)
+ );
+ });
+});
\ No newline at end of file
diff --git a/__tests__/rollback.test.ts b/__tests__/rollback.test.ts
new file mode 100644
index 0000000..b889835
--- /dev/null
+++ b/__tests__/rollback.test.ts
@@ -0,0 +1,132 @@
+import { Command } from 'commander';
+import inquirer from 'inquirer';
+import { registerRollbackCommand } from '../src/commands/rollback';
+import { ensureGitRepo } from '../src/utils';
+
+jest.mock('inquirer');
+jest.mock('../src/utils', () => ({
+ ensureGitRepo: jest.fn()
+}));
+
+describe('registerRollbackCommand', () => {
+ let program: Command;
+ let exitSpy: jest.SpyInstance;
+ let execSyncSpy: jest.SpyInstance;
+ let consoleLogSpy: jest.SpyInstance;
+ let consoleErrorSpy: jest.SpyInstance;
+
+ beforeEach(() => {
+ program = new Command();
+ registerRollbackCommand(program);
+ exitSpy = jest.spyOn(process, 'exit').mockImplementation((code?: string | number | null | undefined) => {
+ throw new Error(`process.exit: ${code}`);
+ });
+ execSyncSpy = jest.spyOn(require('child_process'), 'execSync').mockImplementation(() => { });
+ consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
+ consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => { });
+ });
+
+ afterEach(() => {
+ jest.restoreAllMocks();
+ });
+
+ test('performs soft reset with default target (HEAD~1) when user does not choose specific commit and confirms', async () => {
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ resetType: 'soft' })
+ .mockResolvedValueOnce({ chooseSpecific: false })
+ .mockResolvedValueOnce({ confirmRollback: true });
+
+ await program.parseAsync(['rollback'], { from: 'user' });
+
+ expect(ensureGitRepo).toHaveBeenCalled();
+ expect(execSyncSpy).toHaveBeenCalledWith('git reset --soft HEAD~1', { stdio: 'inherit' });
+ expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining("Rollback successful!"));
+ });
+
+ test('performs soft reset with chosen commit when user opts to choose specific commit', async () => {
+ const fakeLog = 'abc123 Commit message one\ndef456 Commit message two\n';
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ resetType: 'soft' })
+ .mockResolvedValueOnce({ chooseSpecific: true })
+ .mockResolvedValueOnce({ selectedCommit: 'def456' })
+ .mockResolvedValueOnce({ confirmRollback: true });
+
+ execSyncSpy.mockImplementationOnce(() => fakeLog);
+
+ await program.parseAsync(['rollback'], { from: 'user' });
+
+ expect(ensureGitRepo).toHaveBeenCalled();
+ expect(execSyncSpy).toHaveBeenCalledWith('git log --oneline -n 10', { encoding: 'utf8' });
+ expect(execSyncSpy).toHaveBeenCalledWith('git reset --soft def456', { stdio: 'inherit' });
+ expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining("Rollback successful!"));
+ });
+
+ test('performs hard reset successfully when confirmed', async () => {
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ resetType: 'hard' })
+ .mockResolvedValueOnce({ confirmRollback: true });
+
+ await program.parseAsync(['rollback'], { from: 'user' });
+
+ expect(ensureGitRepo).toHaveBeenCalled();
+ expect(execSyncSpy).toHaveBeenCalledWith('git reset --hard HEAD~1', { stdio: 'inherit' });
+ expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining("Rollback successful!"));
+ });
+
+ test('cancels rollback when confirmation is false', async () => {
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ resetType: 'soft' })
+ .mockResolvedValueOnce({ chooseSpecific: false })
+ .mockResolvedValueOnce({ confirmRollback: false });
+
+ await expect(program.parseAsync(['rollback'], { from: 'user' }))
+ .rejects.toThrow('process.exit: 0');
+
+ expect(execSyncSpy).not.toHaveBeenCalled();
+ expect(consoleLogSpy).toHaveBeenCalledWith(expect.stringContaining("Rollback cancelled."));
+ });
+
+ test('exits with error if execSync throws an error during soft reset', async () => {
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ resetType: 'soft' })
+ .mockResolvedValueOnce({ chooseSpecific: false })
+ .mockResolvedValueOnce({ confirmRollback: true });
+
+ const errorMessage = 'Simulated soft reset error';
+ execSyncSpy.mockImplementation(() => { throw new Error(errorMessage); });
+
+ await expect(program.parseAsync(['rollback'], { from: 'user' }))
+ .rejects.toThrow('process.exit: 1');
+
+ expect(consoleErrorSpy).toHaveBeenCalledWith(
+ expect.stringContaining("Error during rollback:"),
+ expect.stringContaining(errorMessage)
+ );
+ });
+
+ test('exits with error if execSync throws an error during hard reset', async () => {
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ resetType: 'hard' })
+ .mockResolvedValueOnce({ confirmRollback: true });
+
+ const errorMessage = 'Simulated hard reset error';
+ execSyncSpy.mockImplementation(() => { throw new Error(errorMessage); });
+
+ await expect(program.parseAsync(['rollback'], { from: 'user' }))
+ .rejects.toThrow('process.exit: 1');
+
+ expect(consoleErrorSpy).toHaveBeenCalledWith(
+ expect.stringContaining("Error during rollback:"),
+ expect.stringContaining(errorMessage)
+ );
+ });
+
+ test('validates that ensureGitRepo is always called before any rollback logic', async () => {
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ resetType: 'hard' })
+ .mockResolvedValueOnce({ confirmRollback: true });
+
+ await program.parseAsync(['rollback'], { from: 'user' });
+ expect(ensureGitRepo).toHaveBeenCalled();
+ });
+});
\ No newline at end of file
diff --git a/__tests__/setup.test.ts b/__tests__/setup.test.ts
new file mode 100644
index 0000000..0162e05
--- /dev/null
+++ b/__tests__/setup.test.ts
@@ -0,0 +1,231 @@
+import { Command } from 'commander';
+import inquirer from 'inquirer';
+import { registerSetupCommand } from '../src/commands/setup';
+import { defaultConfig } from '../src/utils';
+import { Config } from '../src/types';
+
+jest.mock('inquirer', () => ({
+ prompt: jest.fn(),
+}));
+jest.mock('../src/utils', () => ({
+ saveConfig: jest.fn(),
+ defaultConfig: {
+ autoAdd: false,
+ ciCommand: "npm test",
+ templates: { defaultTemplate: "[{type}]: {summary}" },
+ steps: { scope: false, body: false, footer: false, ticket: false, runCI: false },
+ ticketRegex: "",
+ enableLint: false,
+ branch: {
+ template: "{type}/{ticketId}-{shortDesc}",
+ types: [],
+ placeholders: {},
+ },
+ },
+}));
+
+describe('registerSetupCommand', () => {
+ let program: Command;
+ let promptMock: jest.Mock;
+ let saveConfigMock: jest.Mock;
+
+ beforeEach(() => {
+ program = new Command();
+ registerSetupCommand(program);
+ promptMock = (inquirer.prompt as unknown) as jest.Mock;
+ saveConfigMock = require('../src/utils').saveConfig;
+ promptMock.mockReset();
+ saveConfigMock.mockReset();
+ });
+
+ it('should run through setup and save config without branch config', async () => {
+ promptMock.mockResolvedValueOnce({
+ enableScope: true,
+ enableBody: false,
+ enableFooter: false,
+ enableTicket: true,
+ enableRunCi: false,
+ ticketRegex: "ABC-\\d+",
+ template: "[{type}]: {summary}",
+ autoAdd: true,
+ ciCommand: "yarn test",
+ enableLint: true,
+ enableBranchConfig: false,
+ });
+ await program.parseAsync(['setup'], { from: 'user' });
+ const expectedConfig: Config = {
+ ...defaultConfig,
+ autoAdd: true,
+ ciCommand: "yarn test",
+ templates: { defaultTemplate: "[{type}]: {summary}" },
+ steps: {
+ scope: true,
+ body: false,
+ footer: false,
+ ticket: true,
+ runCI: false,
+ },
+ ticketRegex: "ABC-\\d+",
+ enableLint: true,
+ };
+ expect(saveConfigMock).toHaveBeenCalledWith(expectedConfig);
+ });
+
+ it('should run through setup with branch config and parse branch types and placeholders', async () => {
+ const branchTypesJson = `[
+ {"value": "feature", "description": "New feature"},
+ {"value": "fix", "description": "Bug fix"}
+ ]`;
+ const branchPlaceholdersJson = `{
+ "ticketId": {"lowercase": true}
+ }`;
+ promptMock.mockResolvedValueOnce({
+ enableScope: false,
+ enableBody: true,
+ enableFooter: true,
+ enableTicket: true,
+ enableRunCi: true,
+ ticketRegex: "XYZ-\\d+",
+ template: "[{ticket}]{ticketSeparator}[{type}]: {summary}",
+ autoAdd: false,
+ ciCommand: "npm run ci",
+ enableLint: false,
+ enableBranchConfig: true,
+ branchTemplate: "{type}/{ticketId}-{shortDesc}",
+ addBranchTypes: true,
+ branchTypes: branchTypesJson,
+ addPlaceholders: true,
+ branchPlaceholders: branchPlaceholdersJson,
+ });
+ await program.parseAsync(['setup'], { from: 'user' });
+ const expectedConfig: Config = {
+ ...defaultConfig,
+ autoAdd: false,
+ ciCommand: "npm run ci",
+ templates: { defaultTemplate: "[{ticket}]{ticketSeparator}[{type}]: {summary}" },
+ steps: {
+ scope: false,
+ body: true,
+ footer: true,
+ ticket: true,
+ runCI: true,
+ },
+ ticketRegex: "XYZ-\\d+",
+ enableLint: false,
+ branch: {
+ template: "{type}/{ticketId}-{shortDesc}",
+ types: JSON.parse(branchTypesJson),
+ placeholders: JSON.parse(branchPlaceholdersJson),
+ },
+ };
+ expect(saveConfigMock).toHaveBeenCalledWith(expectedConfig);
+ });
+
+ it('should ignore branch types JSON if parsing fails', async () => {
+ promptMock.mockResolvedValueOnce({
+ enableScope: false,
+ enableBody: false,
+ enableFooter: false,
+ enableTicket: false,
+ enableRunCi: false,
+ ticketRegex: "",
+ template: "[{type}]: {summary}",
+ autoAdd: false,
+ ciCommand: "",
+ enableLint: false,
+ enableBranchConfig: true,
+ branchTemplate: "{type}/{ticketId}-{shortDesc}",
+ addBranchTypes: true,
+ branchTypes: "invalid json",
+ addPlaceholders: false,
+ });
+ await program.parseAsync(['setup'], { from: 'user' });
+ expect(saveConfigMock).toHaveBeenCalledWith(expect.objectContaining({
+ branch: {
+ template: "{type}/{ticketId}-{shortDesc}",
+ types: defaultConfig.branch?.types,
+ placeholders: defaultConfig.branch?.placeholders,
+ }
+ }));
+ });
+
+ it('should ignore branch placeholders JSON if parsing fails', async () => {
+ promptMock.mockResolvedValueOnce({
+ enableScope: false,
+ enableBody: false,
+ enableFooter: false,
+ enableTicket: false,
+ enableRunCi: false,
+ ticketRegex: "",
+ template: "[{type}]: {summary}",
+ autoAdd: false,
+ ciCommand: "",
+ enableLint: false,
+ enableBranchConfig: true,
+ branchTemplate: "{type}/{ticketId}-{shortDesc}",
+ addBranchTypes: false,
+ addPlaceholders: true,
+ branchPlaceholders: "not a json",
+ });
+ await program.parseAsync(['setup'], { from: 'user' });
+ expect(saveConfigMock).toHaveBeenCalledWith(expect.objectContaining({
+ branch: {
+ template: "{type}/{ticketId}-{shortDesc}",
+ types: defaultConfig.branch?.types,
+ placeholders: defaultConfig.branch?.placeholders,
+ }
+ }));
+ });
+
+ it('should save config using default values for unanswered questions', async () => {
+ promptMock.mockResolvedValueOnce({
+ enableScope: false,
+ enableBody: false,
+ enableFooter: false,
+ enableTicket: false,
+ enableRunCi: false,
+ ticketRegex: "",
+ template: "",
+ autoAdd: false,
+ ciCommand: "",
+ enableLint: false,
+ enableBranchConfig: false,
+ });
+ await program.parseAsync(['setup'], { from: 'user' });
+ expect(saveConfigMock).toHaveBeenCalledWith({
+ ...defaultConfig,
+ autoAdd: false,
+ ciCommand: defaultConfig.ciCommand,
+ templates: { defaultTemplate: defaultConfig.templates.defaultTemplate },
+ steps: {
+ scope: false,
+ body: false,
+ footer: false,
+ ticket: false,
+ runCI: false,
+ },
+ ticketRegex: "",
+ enableLint: false,
+ });
+ });
+
+ it('should log "Setup complete!" after saving config', async () => {
+ const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
+ promptMock.mockResolvedValueOnce({
+ enableScope: false,
+ enableBody: false,
+ enableFooter: false,
+ enableTicket: false,
+ enableRunCi: false,
+ ticketRegex: "",
+ template: "[{type}]: {summary}",
+ autoAdd: false,
+ ciCommand: "",
+ enableLint: false,
+ enableBranchConfig: false,
+ });
+ await program.parseAsync(['setup'], { from: 'user' });
+ expect(consoleLogSpy).toHaveBeenCalledWith("Setup complete!");
+ consoleLogSpy.mockRestore();
+ });
+});
\ No newline at end of file
diff --git a/__tests__/stats.test.ts b/__tests__/stats.test.ts
new file mode 100644
index 0000000..164ed8e
--- /dev/null
+++ b/__tests__/stats.test.ts
@@ -0,0 +1,116 @@
+import { Command } from 'commander';
+import { registerStatsCommand } from '../src/commands/stats';
+import inquirer from 'inquirer';
+import { execSync } from 'child_process';
+import { ensureGitRepo } from '../src/utils';
+import chalk from 'chalk';
+
+jest.mock('inquirer', () => ({
+ prompt: jest.fn(),
+}));
+jest.mock('child_process', () => ({
+ execSync: jest.fn(),
+}));
+jest.mock('../src/utils', () => ({
+ ensureGitRepo: jest.fn(),
+}));
+
+describe('registerStatsCommand', () => {
+ let program: Command;
+ let promptMock: jest.Mock;
+ let execSyncMock: jest.Mock;
+ let consoleLogSpy: jest.SpyInstance;
+ let consoleErrorSpy: jest.SpyInstance;
+ let exitSpy: jest.SpyInstance;
+
+ beforeEach(() => {
+ program = new Command();
+ registerStatsCommand(program);
+ promptMock = inquirer.prompt as unknown as jest.Mock;
+ execSyncMock = execSync as jest.Mock;
+ consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
+ consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => { });
+ exitSpy = jest.spyOn(process, 'exit').mockImplementation((code?: number | string | null | undefined) => {
+ throw new Error(`process.exit: ${code}`);
+ });
+ (ensureGitRepo as jest.Mock).mockReset();
+ });
+
+ afterEach(() => {
+ jest.restoreAllMocks();
+ });
+
+ it('should show shortlog statistics for selected period', async () => {
+ promptMock
+ .mockResolvedValueOnce({ period: '1 week ago' })
+ .mockResolvedValueOnce({ statsType: 'shortlog' });
+
+ execSyncMock.mockImplementation((cmd: string, options: any) => {
+ if (cmd.startsWith('git --no-pager shortlog')) {
+ expect(cmd).toContain('--since="1 week ago"');
+ return "";
+ }
+ return "";
+ });
+
+ await program.parseAsync(['stats'], { from: 'user' });
+ expect(ensureGitRepo).toHaveBeenCalled();
+ expect(execSyncMock).toHaveBeenCalledWith('git --no-pager shortlog -s -n --since="1 week ago"', { stdio: 'inherit' });
+ });
+
+ it('should show activity statistics for selected period', async () => {
+ promptMock
+ .mockResolvedValueOnce({ period: '1 month ago' })
+ .mockResolvedValueOnce({ statsType: 'activity' });
+ const datesOutput = `2025-02-01
+2025-02-01
+2025-02-02
+2025-02-03
+2025-02-03
+2025-02-03`;
+ execSyncMock.mockImplementation((cmd: string, options: any) => {
+ if (cmd.startsWith('git log')) {
+ expect(cmd).toContain('--since="1 month ago"');
+ return datesOutput;
+ }
+ return "";
+ });
+
+ await program.parseAsync(['stats'], { from: 'user' });
+ expect(ensureGitRepo).toHaveBeenCalled();
+ expect(consoleLogSpy).toHaveBeenCalledWith(chalk.blue("\nCommit Activity:"));
+ expect(consoleLogSpy).toHaveBeenCalledWith(chalk.green(`2025-02-01: ${"#".repeat(2)} (2)`));
+ expect(consoleLogSpy).toHaveBeenCalledWith(chalk.green(`2025-02-02: ${"#".repeat(1)} (1)`));
+ expect(consoleLogSpy).toHaveBeenCalledWith(chalk.green(`2025-02-03: ${"#".repeat(3)} (3)`));
+ });
+
+ it('should print "No commits found for the selected period." when no commits are present', async () => {
+ promptMock
+ .mockResolvedValueOnce({ period: '1 day ago' })
+ .mockResolvedValueOnce({ statsType: 'activity' });
+ execSyncMock.mockImplementation((cmd: string, options: any) => {
+ if (cmd.startsWith('git log')) {
+ return "";
+ }
+ return "";
+ });
+
+ await program.parseAsync(['stats'], { from: 'user' });
+ expect(consoleLogSpy).toHaveBeenCalledWith(chalk.yellow("No commits found for the selected period."));
+ });
+
+ it('should exit with error if execSync fails', async () => {
+ promptMock
+ .mockResolvedValueOnce({ period: '1 day ago' })
+ .mockResolvedValueOnce({ statsType: 'shortlog' });
+
+ const errorMessage = 'Simulated error';
+ execSyncMock.mockImplementation(() => {
+ throw new Error(errorMessage);
+ });
+
+ await expect(program.parseAsync(['stats'], { from: 'user' }))
+ .rejects.toThrow('process.exit: 1');
+ expect(consoleErrorSpy).toHaveBeenCalledWith(chalk.red("Error retrieving statistics:"), expect.stringContaining(errorMessage));
+ });
+});
\ No newline at end of file
diff --git a/__tests__/utils.test.ts b/__tests__/utils.test.ts
new file mode 100644
index 0000000..0365c6a
--- /dev/null
+++ b/__tests__/utils.test.ts
@@ -0,0 +1,312 @@
+import fs from 'fs';
+import path from 'path';
+import os from 'os';
+import { execSync } from 'child_process';
+import parseGitIgnore from 'parse-gitignore';
+import inquirer from 'inquirer';
+import chalk from 'chalk';
+
+import {
+ defaultConfig,
+ loadConfig,
+ saveConfig,
+ loadGitignorePatterns,
+ getUnstagedFiles,
+ stageSelectedFiles,
+ computeAutoSummary,
+ suggestCommitType,
+ lintCommitMessage,
+ previewCommitMessage,
+ ensureGitRepo,
+ showDiffPreview,
+} from '../src/utils';
+
+jest.mock('fs');
+jest.mock('child_process');
+jest.mock('parse-gitignore');
+jest.mock('inquirer');
+
+const CONFIG_PATH = path.join(os.homedir(), '.smart-commit-config.json');
+
+describe('Utils', () => {
+ describe('loadConfig', () => {
+ beforeEach(() => {
+ jest.resetAllMocks();
+ });
+ it('should return defaultConfig if global config file does not exist', () => {
+ (fs.existsSync as jest.Mock).mockReturnValue(false);
+ (fs.existsSync as jest.Mock).mockReturnValueOnce(false);
+ const config = loadConfig();
+ expect(config).toEqual(defaultConfig);
+ });
+ it('should load and parse global config if file exists', () => {
+ const globalConfig = { ...defaultConfig, autoAdd: true };
+ jest.spyOn(process, 'cwd').mockReturnValue('/fake/path');
+ (fs.existsSync as jest.Mock).mockImplementation((filePath: string) => {
+ if (filePath === CONFIG_PATH) return true;
+ if (filePath === path.join('/fake/path', '.smartcommitrc.json')) return false;
+ return false;
+ });
+ (fs.readFileSync as jest.Mock).mockReturnValue(JSON.stringify(globalConfig));
+ const config = loadConfig();
+ expect(config).toEqual(globalConfig);
+ });
+ it('should merge local config over global config', () => {
+ const globalConfig = { ...defaultConfig, autoAdd: false, ciCommand: "npm test" };
+ const localConfig = { autoAdd: true, ciCommand: "yarn test" };
+ jest.spyOn(process, 'cwd').mockReturnValue('/fake/path');
+ (fs.existsSync as jest.Mock).mockImplementation((filePath: string) => {
+ if (filePath === CONFIG_PATH) return true;
+ if (filePath === path.join('/fake/path', '.smartcommitrc.json')) return true;
+ return false;
+ });
+ (fs.readFileSync as jest.Mock)
+ .mockImplementation((filePath: string) => {
+ if (filePath === CONFIG_PATH) return JSON.stringify(globalConfig);
+ if (filePath === path.join('/fake/path', '.smartcommitrc.json')) return JSON.stringify(localConfig);
+ return "";
+ });
+ const config = loadConfig();
+ expect(config.autoAdd).toBe(true);
+ expect(config.ciCommand).toBe("yarn test");
+ });
+ it('should log error and use default if global config is invalid JSON', () => {
+ jest.spyOn(process, 'cwd').mockReturnValue('/fake/path');
+ const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
+ (fs.existsSync as jest.Mock).mockReturnValue(true);
+ (fs.readFileSync as jest.Mock).mockImplementation(() => { throw new Error('Invalid JSON'); });
+ const config = loadConfig();
+ expect(console.error).toHaveBeenCalledWith(chalk.red("Error reading global config, using default settings."));
+ expect(config).toEqual(defaultConfig);
+ consoleErrorSpy.mockRestore();
+ });
+ });
+
+ describe('saveConfig', () => {
+ it('should write config to CONFIG_PATH and log message', () => {
+ const writeFileSyncMock = fs.writeFileSync as jest.Mock;
+ const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
+ saveConfig(defaultConfig);
+ expect(writeFileSyncMock).toHaveBeenCalledWith(
+ CONFIG_PATH,
+ JSON.stringify(defaultConfig, null, 2),
+ 'utf8'
+ );
+ expect(consoleLogSpy).toHaveBeenCalledWith(chalk.green("Global configuration saved at"), CONFIG_PATH);
+ consoleLogSpy.mockRestore();
+ });
+ });
+
+ describe('loadGitignorePatterns', () => {
+ beforeEach(() => {
+ jest.resetAllMocks();
+ });
+ it('should return empty array if .gitignore does not exist', () => {
+ jest.spyOn(process, 'cwd').mockReturnValue('/fake/path');
+ (fs.existsSync as jest.Mock).mockReturnValue(false);
+ const patterns = loadGitignorePatterns();
+ expect(patterns).toEqual([]);
+ });
+ it('should parse and return patterns from .gitignore', () => {
+ jest.spyOn(process, 'cwd').mockReturnValue('/fake/path');
+ (fs.existsSync as jest.Mock).mockReturnValue(true);
+ (fs.readFileSync as jest.Mock).mockReturnValue("node_modules\n.dist\n");
+ (parseGitIgnore as unknown as jest.Mock).mockReturnValue(["node_modules", ".dist"]);
+ const patterns = loadGitignorePatterns();
+ expect(patterns).toEqual(["node_modules", ".dist"]);
+ });
+ it('should log error and return empty array if parsing fails', () => {
+ jest.spyOn(process, 'cwd').mockReturnValue('/fake/path');
+ (fs.existsSync as jest.Mock).mockReturnValue(true);
+ (fs.readFileSync as jest.Mock).mockImplementation(() => { throw new Error("read error"); });
+ const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
+ const patterns = loadGitignorePatterns();
+ expect(consoleErrorSpy).toHaveBeenCalledWith(chalk.red("Failed to parse .gitignore:"), expect.any(Error));
+ expect(patterns).toEqual([]);
+ consoleErrorSpy.mockRestore();
+ });
+ });
+
+ describe('getUnstagedFiles', () => {
+ beforeEach(() => {
+ jest.resetAllMocks();
+ });
+ it('should return unique list of changed and untracked files', () => {
+ (execSync as jest.Mock)
+ .mockReturnValueOnce("file1.js\nfile2.js\n")
+ .mockReturnValueOnce("file2.js\nfile3.js\n");
+ const files = getUnstagedFiles();
+ expect(files.sort()).toEqual(["file1.js", "file2.js", "file3.js"].sort());
+ });
+ it('should log error and return empty array if execSync fails', () => {
+ const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
+ (execSync as jest.Mock).mockImplementation(() => { throw new Error("git error"); });
+ const files = getUnstagedFiles();
+ expect(consoleErrorSpy).toHaveBeenCalledWith(chalk.red("Error getting unstaged files:"), "git error");
+ expect(files).toEqual([]);
+ consoleErrorSpy.mockRestore();
+ });
+ });
+
+ describe('stageSelectedFiles', () => {
+ it('should call git add for each file in the list', () => {
+ (execSync as jest.Mock).mockReset();
+ stageSelectedFiles(["file1.js", "file2.js"]);
+ expect(execSync).toHaveBeenCalledWith('git add "file1.js"', { stdio: 'inherit' });
+ expect(execSync).toHaveBeenCalledWith('git add "file2.js"', { stdio: 'inherit' });
+ });
+ it('should do nothing if file list is empty', () => {
+ (execSync as jest.Mock).mockReset();
+ stageSelectedFiles([]);
+ expect(execSync).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('computeAutoSummary', () => {
+ it('should return a concatenated summary based on staged files', () => {
+ (execSync as jest.Mock).mockReturnValue("package.json\nsrc/app.ts\nREADME.md\n");
+ const summary = computeAutoSummary();
+ expect(summary).toContain("Update dependencies");
+ expect(summary).toContain("Update source code");
+ expect(summary).toContain("Update documentation");
+ });
+ it('should return empty string if no staged files', () => {
+ (execSync as jest.Mock).mockReturnValue("");
+ const summary = computeAutoSummary();
+ expect(summary).toBe("");
+ });
+ });
+
+ describe('suggestCommitType', () => {
+ it('should suggest "docs" if all staged files are markdown', () => {
+ (execSync as jest.Mock).mockReturnValue("README.md\nCONTRIBUTING.md\n");
+ const type = suggestCommitType();
+ expect(type).toBe("docs");
+ });
+ it('should suggest "chore" if package.json is staged', () => {
+ (execSync as jest.Mock).mockReturnValue("package.json\nother.txt\n");
+ const type = suggestCommitType();
+ expect(type).toBe("chore");
+ });
+ it('should suggest "feat" if any staged file is in src/', () => {
+ (execSync as jest.Mock).mockReturnValue("src/index.ts\n");
+ const type = suggestCommitType();
+ expect(type).toBe("feat");
+ });
+ it('should return null if no staged files', () => {
+ (execSync as jest.Mock).mockReturnValue("");
+ const type = suggestCommitType();
+ expect(type).toBeNull();
+ });
+ });
+
+ describe('lintCommitMessage', () => {
+ const rules = {
+ summaryMaxLength: 10,
+ typeCase: "lowercase",
+ requiredTicket: true,
+ };
+ it('should return error if summary too long', () => {
+ const message = "This summary is definitely too long\nOther lines";
+ const errors = lintCommitMessage(message, rules);
+ expect(errors[0]).toMatch(/Summary is too long/);
+ });
+ it('should return error if summary does not start with lowercase', () => {
+ const message = "Invalid summary\nBody";
+ const errors = lintCommitMessage(message, { ...rules, summaryMaxLength: 100, requiredTicket: false });
+ expect(errors).toContain("Summary should start with a lowercase letter.");
+ });
+ it('should return error if ticket is required but not present', () => {
+ const message = "valid summary\nBody";
+ const errors = lintCommitMessage(message, { ...rules, summaryMaxLength: 100, requiredTicket: true });
+ expect(errors).toContain("A ticket ID is required in the commit message (e.g., '#DEV-123').");
+ });
+ it('should return empty array if message passes all lint rules', () => {
+ const message = "valid\nBody with #123";
+ const errors = lintCommitMessage(message, { summaryMaxLength: 100, typeCase: "lowercase", requiredTicket: true });
+ expect(errors).toEqual([]);
+ });
+ });
+
+ describe('previewCommitMessage', () => {
+ it('should return message if preview is confirmed and no lint errors', async () => {
+ (inquirer.prompt as unknown as jest.Mock).mockResolvedValueOnce({ confirmPreview: true });
+ const message = "valid message with #ticket";
+ const result = await previewCommitMessage(message, { summaryMaxLength: 100, typeCase: "lowercase", requiredTicket: false });
+ expect(result).toBe(message);
+ });
+
+ it('should allow editing message when not confirmed', async () => {
+ (inquirer.prompt as unknown as jest.Mock)
+ .mockResolvedValueOnce({ confirmPreview: false })
+ .mockResolvedValueOnce({ editedMessage: "edited message" })
+ .mockResolvedValueOnce({ confirmPreview: true });
+
+ const message = "original message";
+ const result = await previewCommitMessage(message, { summaryMaxLength: 100, typeCase: "lowercase", requiredTicket: false });
+ expect(result).toBe("edited message");
+ });
+ });
+
+ describe('ensureGitRepo', () => {
+ let exitSpy: jest.SpyInstance;
+ let consoleLogSpy: jest.SpyInstance;
+
+ beforeEach(() => {
+ exitSpy = jest.spyOn(process, 'exit').mockImplementation((code?: string | number | null | undefined) => {
+ throw new Error(`process.exit: ${code}`);
+ });
+ consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
+ });
+
+ afterEach(() => {
+ exitSpy.mockRestore();
+ consoleLogSpy.mockRestore();
+ });
+
+ it('should do nothing if inside a Git repo', () => {
+ (execSync as jest.Mock).mockReturnValue("true");
+ expect(() => ensureGitRepo()).not.toThrow();
+ });
+
+ it('should log error and call process.exit if not inside a Git repo', () => {
+ (execSync as jest.Mock).mockImplementation(() => { throw new Error("not a repo"); });
+ expect(() => ensureGitRepo()).toThrow('process.exit: 1');
+ expect(consoleLogSpy).toHaveBeenCalledWith(
+ chalk.red("Not a Git repository. Please run 'git init' or navigate to a valid repo.")
+ );
+ });
+ });
+
+ describe('showDiffPreview', () => {
+ beforeEach(() => {
+ jest.resetAllMocks();
+ });
+ it('should show message if no staged changes to show', () => {
+ (execSync as jest.Mock).mockReturnValue(" ");
+ const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
+ showDiffPreview();
+ expect(consoleLogSpy).toHaveBeenCalledWith(chalk.yellow("No staged changes to show."));
+ consoleLogSpy.mockRestore();
+ });
+ it('should show diff preview if diff is not empty', () => {
+ const fakeDiff = "diff --git a/file b/file";
+ (execSync as jest.Mock).mockReturnValue(fakeDiff);
+ const consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
+ showDiffPreview();
+ expect(consoleLogSpy).toHaveBeenCalledWith(chalk.green("\nStaged Diff Preview:\n"));
+ expect(consoleLogSpy).toHaveBeenCalledWith(chalk.green(fakeDiff));
+ consoleLogSpy.mockRestore();
+ });
+ it('should log error if execSync fails', () => {
+ (execSync as jest.Mock).mockImplementation(() => { throw new Error("diff error"); });
+ const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
+ showDiffPreview();
+ expect(consoleErrorSpy).toHaveBeenCalledWith(chalk.red("Error retrieving diff:"), "diff error");
+ consoleErrorSpy.mockRestore();
+ });
+ });
+ afterAll(() => {
+ jest.restoreAllMocks();
+ });
+});
\ No newline at end of file
diff --git a/babel.config.js b/babel.config.js
new file mode 100644
index 0000000..d67ea06
--- /dev/null
+++ b/babel.config.js
@@ -0,0 +1,5 @@
+module.exports = {
+ presets: [
+ ['@babel/preset-env', { targets: { node: 'current' } }]
+ ],
+};
\ No newline at end of file
diff --git a/index.ts b/index.ts
deleted file mode 100644
index d978ed7..0000000
--- a/index.ts
+++ /dev/null
@@ -1,958 +0,0 @@
-#!/usr/bin/env node
-
-import { program } from 'commander';
-import inquirer, { Question } from 'inquirer';
-import fs from 'fs';
-import path from 'path';
-import os from 'os';
-import { execSync } from 'child_process';
-import chalk from 'chalk';
-import { fileURLToPath } from 'url';
-
-// These variables are required to get the current file's path and directory in ES modules.
-// In CommonJS, these are available globally, but in ES modules we need to construct them.
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = path.dirname(__filename);
-
-/**
- * Question type without using generic Answers.
- */
-type InputQuestion = Question & { type: 'input' };
-type ListQuestion = Question & { type: 'list' };
-type ConfirmQuestion = Question & { type: 'confirm' };
-type EditorQuestion = Question & { type: 'editor' };
-
-/**
- * Represents a commit type (with emoji, value, description).
- */
-interface CommitType {
- emoji: string;
- value: string;
- description: string;
-}
-
-/**
- * Represents commit message templates.
- */
-interface Templates {
- defaultTemplate: string;
-}
-
-/**
- * Represents linting rules for commit messages.
- */
-interface LintRules {
- summaryMaxLength: number;
- typeCase: string; // e.g. 'lowercase'
- requiredTicket: boolean;
-}
-
-/**
- * Main configuration interface.
- */
-interface Config {
- commitTypes: CommitType[];
- autoAdd: boolean;
- useEmoji: boolean;
- ciCommand: string;
- templates: Templates;
- steps: {
- scope: boolean;
- body: boolean;
- footer: boolean;
- ticket: boolean;
- runCI: boolean;
- };
- ticketRegex: string;
- enableLint: boolean;
- lintRules: LintRules;
- // enableHooks: boolean; // TODO: implement hooks
-}
-
-/**
- * Path to the global config file in the user's home directory.
- */
-const CONFIG_PATH = path.join(os.homedir(), '.smart-commit-config.json');
-
-/**
- * Default configuration values.
- */
-const defaultConfig: Config = {
- commitTypes: [
- { emoji: "✨", value: "feat", description: "A new feature" },
- { emoji: "🐛", value: "fix", description: "A bug fix" },
- { emoji: "📝", value: "docs", description: "Documentation changes" },
- { emoji: "💄", value: "style", description: "Code style improvements" },
- { emoji: "♻️", value: "refactor", description: "Code refactoring" },
- { emoji: "🚀", value: "perf", description: "Performance improvements" },
- { emoji: "✅", value: "test", description: "Adding tests" },
- { emoji: "🔧", value: "chore", description: "Maintenance and chores" }
- ],
- autoAdd: false,
- useEmoji: true,
- ciCommand: "",
- templates: {
- defaultTemplate: "[{type}]{ticketSeparator}{ticket}: {summary}\n\nBody:\n{body}\n\nFooter:\n{footer}"
- },
- steps: {
- scope: false,
- body: false,
- footer: false,
- ticket: false,
- runCI: false,
- },
- ticketRegex: "",
- enableLint: false,
- lintRules: {
- summaryMaxLength: 72,
- typeCase: "lowercase",
- requiredTicket: false,
- },
- // enableHooks: false,
-};
-
-/**
- * Loads the global and local config, merging them if both exist.
- */
-function loadConfig(): Config {
- let config: Config = defaultConfig;
-
- if (fs.existsSync(CONFIG_PATH)) {
- try {
- const data = fs.readFileSync(CONFIG_PATH, 'utf8');
- config = JSON.parse(data) as Config;
- } catch {
- console.error(chalk.red("Error reading global config, using default settings."));
- }
- }
- const localConfigPath = path.join(process.cwd(), '.smartcommitrc.json');
- if (fs.existsSync(localConfigPath)) {
- try {
- const localData = fs.readFileSync(localConfigPath, 'utf8');
- const localConfig = JSON.parse(localData) as Partial;
- config = { ...config, ...localConfig };
- } catch {
- console.error(chalk.red("Error reading local config, ignoring."));
- }
- }
-
- if (!config.lintRules) {
- config.lintRules = { ...defaultConfig.lintRules };
- }
-
- return config;
-}
-
-/**
- * Saves the config to disk (global config).
- */
-function saveConfig(config: Config): void {
- fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), 'utf8');
- console.log(chalk.green("Global configuration saved at"), CONFIG_PATH);
-}
-
-/**
- * Answers interface for commit creation.
- */
-interface CommitAnswers {
- type: string;
- scope: string;
- summary: string;
- body: string;
- footer: string;
- ticket: string;
- runCI: boolean;
- autoAdd: boolean;
- confirmCommit: boolean;
- pushCommit: boolean;
- signCommit: boolean;
-}
-
-/**
- * Generates a default summary by analyzing staged changes.
- */
-function computeAutoSummary(): string {
- let summaries: string[] = [];
- try {
- const diffFiles = execSync('git diff --cached --name-only', { encoding: 'utf8' })
- .split('\n')
- .filter(f => f.trim() !== '');
- if (diffFiles.length > 0) {
- if (diffFiles.includes('package.json')) summaries.push('Update dependencies');
- if (diffFiles.some(f => f.includes('Dockerfile'))) summaries.push('Update Docker configuration');
- if (diffFiles.some(f => f.endsWith('.md'))) summaries.push('Update documentation');
- if (diffFiles.some(f => f.startsWith('src/') || f.endsWith('.ts') || f.endsWith('.js'))) summaries.push('Update source code');
- return summaries.join(', ');
- }
- } catch { }
- return '';
-}
-
-/**
- * Suggests a commit type based on staged files.
- */
-function suggestCommitType(): string | null {
- try {
- const diffFiles = execSync('git diff --cached --name-only', { encoding: 'utf8' })
- .split('\n')
- .filter(f => f.trim() !== '');
- if (diffFiles.length > 0) {
- if (diffFiles.every(f => f.endsWith('.md'))) return 'docs';
- if (diffFiles.includes('package.json')) return 'chore';
- if (diffFiles.some(f => f.startsWith('src/'))) return 'feat';
- }
- } catch { }
- return null;
-}
-
-/**
- * Lints the commit message using specified rules.
- */
-function lintCommitMessage(message: string, rules: LintRules): string[] {
- const errors: string[] = [];
- const lines = message.split('\n');
- const summary = lines[0].trim();
- if (summary.length > rules.summaryMaxLength) {
- errors.push(`Summary is too long (${summary.length} characters). Max allowed is ${rules.summaryMaxLength}.`);
- }
- if (rules.typeCase === 'lowercase' && summary && summary[0] !== summary[0].toLowerCase()) {
- errors.push("Summary should start with a lowercase letter.");
- }
- if (rules.requiredTicket && !message.includes('#')) {
- errors.push("A ticket ID is required in the commit message (e.g., '#DEV-123').");
- }
- return errors;
-}
-
-/**
- * Interactive preview of the commit message with optional linting fix.
- */
-async function previewCommitMessage(message: string, lintRules: LintRules): Promise {
- console.log(chalk.blue("\nPreview commit message:\n"));
- console.log(message);
- const { confirmPreview } = await inquirer.prompt([
- {
- type: 'confirm',
- name: 'confirmPreview',
- message: 'Does the commit message look OK?',
- default: true,
- }
- ]);
- if (confirmPreview) {
- const errors = lintCommitMessage(message, lintRules);
- if (errors.length > 0) {
- console.log(chalk.red("Linting errors:"));
- errors.forEach(err => console.log(chalk.red("- " + err)));
- const { editedMessage } = await inquirer.prompt([
- {
- type: 'editor',
- name: 'editedMessage',
- message: 'Edit the commit message to fix these issues:',
- default: message,
- }
- ]);
- return previewCommitMessage(editedMessage, lintRules);
- } else {
- return message;
- }
- } else {
- const { editedMessage } = await inquirer.prompt([
- {
- type: 'editor',
- name: 'editedMessage',
- message: 'Edit the commit message as needed:',
- default: message,
- }
- ]);
- return previewCommitMessage(editedMessage, lintRules);
- }
-}
-
-/**
- * Checks if the current directory is inside a Git repository.
- * If the directory is not a Git repository, displays an error message and exits the process.
- *
- * @throws {Error} If the directory is not a Git repository
- */
-function ensureGitRepo(): void {
- try {
- execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' });
- } catch {
- console.log(chalk.red("Not a Git repository. Please run 'git init' or navigate to a valid repo."));
- process.exit(1);
- }
-}
-
-/**
- * Shows a preview of the staged diff.
- */
-function showDiffPreview(): void {
- try {
- const diffSoFancyPath = path.join(__dirname, '..', 'node_modules', '.bin', 'diff-so-fancy');
- const diff = execSync(`git diff --staged | "${diffSoFancyPath}"`, { encoding: 'utf8' });
- if (diff.trim() === "") {
- console.log(chalk.yellow("No staged changes to show."));
- } else {
- console.log(chalk.green("\nStaged Diff Preview:\n"));
- console.log(chalk.green(diff));
- }
- } catch (err: any) {
- console.error(chalk.red("Error retrieving diff:"), err.message);
- }
-}
-
-program
- .name('sc')
- .description('Smart Commit CLI Tool - Create customizable Git commits with ease.')
- .version('1.1.5');
-
-program.addHelpText('beforeAll', chalk.blue(`
-========================================
- Welcome to Smart Commit CLI!
-========================================
-`));
-
-program.addHelpText('afterAll', chalk.blue(`
-Examples:
- sc commit # Start interactive commit prompt
- sc amend # Amend the last commit interactively
- sc rollback # Rollback the last commit (soft or hard reset)
- sc rebase-helper # Launch interactive rebase helper
- sc ci # Run CI tests as configured
- sc stats # Show enhanced commit statistics
- sc history # Show commit history with filtering
- sc config # Configure or view settings
- sc setup # Run interactive setup wizard
-`));
-
-program
- .command('config')
- .alias('cfg')
- .description('Configure or view Smart Commit settings')
- .option('-a, --auto-add ', 'Set auto-add for commits (true/false)', (value: string) => value === 'true')
- .option('-e, --use-emoji ', 'Use emojis in commit types (true/false)', (value: string) => value === 'true')
- .option('-c, --ci-command ', 'Set CI command (e.g., "npm test")')
- .option('-t, --template ', 'Set default commit message template')
- .option('--enable-scope ', 'Enable scope prompt (true/false)', (value: string) => value === 'true')
- .option('--enable-body ', 'Enable body prompt (true/false)', (value: string) => value === 'true')
- .option('--enable-footer ', 'Enable footer prompt (true/false)', (value: string) => value === 'true')
- .option('--enable-ticket ', 'Enable ticket prompt (true/false)', (value: string) => value === 'true')
- .option('--enable-run-ci ', 'Enable CI prompt (true/false)', (value: string) => value === 'true')
- .option('--ticket-regex ', 'Set regex for ticket extraction from branch name')
- .option('--enable-lint ', 'Enable commit message linting (true/false)', (value: string) => value === 'true')
- .option('--enable-hooks ', 'Enable Git Hooks installation (true/false)', (value: string) => value === 'true')
- .action((options) => {
- const config = loadConfig();
- let changed = false;
-
- if (options.autoAdd !== undefined) {
- config.autoAdd = options.autoAdd;
- changed = true;
- }
- if (options.useEmoji !== undefined) {
- config.useEmoji = options.useEmoji;
- changed = true;
- }
- if (options.ciCommand) {
- config.ciCommand = options.ciCommand;
- changed = true;
- }
- if (options.template) {
- config.templates.defaultTemplate = options.template;
- changed = true;
- }
- if (options.enableScope !== undefined) {
- config.steps.scope = options.enableScope;
- changed = true;
- }
- if (options.enableBody !== undefined) {
- config.steps.body = options.enableBody;
- changed = true;
- }
- if (options.enableFooter !== undefined) {
- config.steps.footer = options.enableFooter;
- changed = true;
- }
- if (options.enableTicket !== undefined) {
- config.steps.ticket = options.enableTicket;
- changed = true;
- }
- if (options.enableRunCi !== undefined) {
- config.steps.runCI = options.enableRunCi;
- changed = true;
- }
- if (options.ticketRegex) {
- config.ticketRegex = options.ticketRegex;
- changed = true;
- }
- if (options.enableLint !== undefined) {
- config.enableLint = options.enableLint;
- changed = true;
- }
- // if (options.enableHooks !== undefined) {
- // config.enableHooks = options.enableHooks;
- // changed = true;
- // }
-
- if (changed) {
- saveConfig(config);
- } else {
- console.log("\nCurrent configuration:\n");
-
- console.table([
- { Key: 'autoAdd', Value: config.autoAdd },
- { Key: 'useEmoji', Value: config.useEmoji },
- { Key: 'ciCommand', Value: config.ciCommand },
- { Key: 'ticketRegex', Value: config.ticketRegex },
- { Key: 'enableLint', Value: config.enableLint },
- // { Key: 'enableHooks', Value: config.enableHooks },
- ]);
-
- console.log("\nSteps (prompts enabled):");
- console.table([
- { Step: 'scope', Enabled: config.steps.scope },
- { Step: 'body', Enabled: config.steps.body },
- { Step: 'footer', Enabled: config.steps.footer },
- { Step: 'ticket', Enabled: config.steps.ticket },
- { Step: 'runCI', Enabled: config.steps.runCI }
- ]);
-
- console.log("\nLint Rules:");
- console.table([
- {
- summaryMaxLength: config.lintRules.summaryMaxLength,
- typeCase: config.lintRules.typeCase,
- requiredTicket: config.lintRules.requiredTicket
- }
- ]);
-
- console.log("\nCommit Types:");
- console.table(config.commitTypes);
-
- console.log("\nDefault Template:\n", config.templates.defaultTemplate);
- }
- });
-
-program
- .command('setup')
- .description('Interactive setup for Smart Commit configuration')
- .action(async () => {
- console.log("Welcome to Smart Commit setup!");
- const questions = [
- {
- type: 'confirm',
- name: 'enableScope',
- message: 'Enable scope prompt?',
- default: false,
- },
- {
- type: 'confirm',
- name: 'enableBody',
- message: 'Enable body prompt?',
- default: false,
- },
- {
- type: 'confirm',
- name: 'enableFooter',
- message: 'Enable footer prompt?',
- default: false,
- },
- {
- type: 'confirm',
- name: 'enableTicket',
- message: 'Enable ticket prompt?',
- default: false,
- },
- {
- type: 'confirm',
- name: 'enableRunCi',
- message: 'Enable CI prompt?',
- default: false,
- },
- {
- type: 'input',
- name: 'ticketRegex',
- message: 'Enter regex for ticket extraction (leave blank for none):',
- default: ""
- },
- {
- type: 'input',
- name: 'template',
- message: 'Enter default commit message template:',
- default: "[{type}]: {summary}"
- },
- {
- type: 'confirm',
- name: 'autoAdd',
- message: 'Enable auto-add by default?',
- default: false,
- },
- {
- type: 'input',
- name: 'ciCommand',
- message: 'Enter CI command (leave blank for none):',
- default: ""
- },
- {
- type: 'confirm',
- name: 'enableLint',
- message: 'Enable commit message linting?',
- default: false
- },
- // {
- // type: 'confirm',
- // name: 'enableHooks',
- // message: 'Enable Git Hooks installation?',
- // default: false
- // }
- ];
- const setupAnswers = await inquirer.prompt(questions as any);
-
- const newConfig: Config = {
- ...defaultConfig,
- autoAdd: setupAnswers.autoAdd,
- ciCommand: setupAnswers.ciCommand || defaultConfig.ciCommand,
- templates: {
- defaultTemplate: setupAnswers.template || defaultConfig.templates.defaultTemplate
- },
- steps: {
- scope: setupAnswers.enableScope,
- body: setupAnswers.enableBody,
- footer: setupAnswers.enableFooter,
- ticket: setupAnswers.enableTicket,
- runCI: setupAnswers.enableRunCi,
- },
- ticketRegex: setupAnswers.ticketRegex || "",
- enableLint: setupAnswers.enableLint,
- // enableHooks: setupAnswers.enableHooks,
- };
- saveConfig(newConfig);
- console.log("Setup complete!");
- });
-
-program
- .command('commit')
- .alias('c')
- .description('Create a commit with interactive prompts')
- .option('--push', 'Push commit to remote after creation', false)
- .option('--sign', 'Sign commit with GPG', false)
- .option('--no-lint', 'Skip commit message linting', false)
- .action(async (cmdObj: { lint: boolean; sign: any; push: any; }) => {
- ensureGitRepo();
- const config = loadConfig();
- const suggestedType = suggestCommitType();
- const commitTypeChoices = config.commitTypes.map(ct => ({
- name: config.useEmoji
- ? `${ct.emoji} ${ct.value} (${ct.description})`
- : `${ct.value} (${ct.description})`,
- value: ct.value,
- }));
- const autoSummary = computeAutoSummary();
-
- const questions: (ListQuestion | InputQuestion | ConfirmQuestion | EditorQuestion)[] = [];
- questions.push({
- type: 'list',
- name: 'type',
- message: 'Select commit type:',
- choices: commitTypeChoices,
- default: suggestedType || undefined,
- } as ListQuestion);
-
- if (config.steps.scope) {
- questions.push({
- type: 'input',
- name: 'scope',
- message: 'Enter scope (optional):',
- } as InputQuestion);
- }
- questions.push({
- type: 'input',
- name: 'summary',
- message: 'Enter commit summary:',
- default: autoSummary,
- validate: (input: string) => input ? true : 'Summary cannot be empty',
- } as InputQuestion);
-
- if (config.steps.body) {
- questions.push({
- type: 'editor',
- name: 'body',
- message: 'Enter commit body (your default editor will open, leave empty to skip):',
- } as EditorQuestion);
- }
- if (config.steps.footer) {
- questions.push({
- type: 'input',
- name: 'footer',
- message: 'Enter commit footer (optional):',
- } as InputQuestion);
- }
- if (config.steps.ticket) {
- questions.push({
- type: 'input',
- name: 'ticket',
- message: 'Enter ticket ID (optional):',
- } as InputQuestion);
- }
- if (config.steps.runCI) {
- questions.push({
- type: 'confirm',
- name: 'runCI',
- message: 'Run CI tests before commit?',
- default: false,
- } as ConfirmQuestion);
- }
- questions.push({
- type: 'confirm',
- name: 'autoAdd',
- message: 'Stage all changes before commit?',
- default: config.autoAdd,
- } as ConfirmQuestion);
-
- const answers = await inquirer.prompt(questions) as CommitAnswers;
- if (!answers.scope) answers.scope = "";
- if (!answers.body) answers.body = "";
- if (!answers.footer) answers.footer = "";
- if (!answers.ticket) answers.ticket = "";
- if (!answers.runCI) answers.runCI = false;
-
- if (config.steps.ticket && !answers.ticket && config.ticketRegex) {
- try {
- const branchName = execSync("git rev-parse --abbrev-ref HEAD", { encoding: "utf8" }).trim();
- const re = new RegExp(config.ticketRegex);
- const match = branchName.match(re);
- if (match && match[0]) {
- answers.ticket = match[0];
- console.log(chalk.cyan(`Extracted ticket from branch: ${answers.ticket}`));
- }
- } catch { }
- }
-
- if (answers.runCI) {
- try {
- console.log(chalk.blue('Running CI tests...'));
- execSync(config.ciCommand, { stdio: 'inherit' });
- console.log(chalk.green('CI tests passed!'));
- } catch (err: any) {
- console.error(chalk.red('CI tests failed:'), err.message);
- process.exit(1);
- }
- }
-
- if (answers.autoAdd) {
- execSync('git add .', { stdio: 'inherit' });
- }
-
- const stagedFiles = execSync('git diff --cached --name-only', { encoding: 'utf8' })
- .split('\n')
- .filter(f => f.trim() !== '');
- if (stagedFiles.length === 0) {
- console.log(chalk.yellow("No changes staged. Aborting commit."));
- process.exit(0);
- }
-
- const { diffPreview } = await inquirer.prompt([
- {
- type: 'confirm',
- name: 'diffPreview',
- message: 'Would you like to view the staged diff preview?',
- default: false,
- }
- ]);
- if (diffPreview) {
- ensureGitRepo();
- showDiffPreview();
- const { diffConfirm } = await inquirer.prompt([
- {
- type: 'confirm',
- name: 'diffConfirm',
- message: 'Does the staged diff look OK?',
- default: true,
- }
- ]);
- if (!diffConfirm) {
- console.log(chalk.yellow("Commit cancelled due to diff review."));
- process.exit(0);
- }
- }
-
- const scopeFormatted = answers.scope.trim() !== '' ? `(${answers.scope.trim()})` : '';
- const ticketSeparator = answers.ticket.trim() !== '' ? ": " : "";
- let commitMsg = config.templates.defaultTemplate
- .replace('{ticket}', answers.ticket.trim())
- .replace('{ticketSeparator}', ticketSeparator)
- .replace('{type}', answers.type)
- .replace('{scope}', scopeFormatted)
- .replace('{summary}', answers.summary.trim())
- .replace('{body}', answers.body.trim())
- .replace('{footer}', answers.footer.trim());
-
- if (cmdObj.lint !== false && config.enableLint) {
- commitMsg = await previewCommitMessage(commitMsg, config.lintRules);
- } else {
- const { previewChoice } = await inquirer.prompt([
- {
- type: 'confirm',
- name: 'previewChoice',
- message: 'Preview commit message?',
- default: true,
- }
- ]);
- if (previewChoice) {
- console.log(chalk.blue("\nPreview commit message:\n"));
- console.log(commitMsg);
- }
- const { finalConfirm } = await inquirer.prompt([
- {
- type: 'confirm',
- name: 'finalConfirm',
- message: 'Proceed with commit?',
- default: true,
- }
- ]);
- if (!finalConfirm) {
- console.log(chalk.yellow('Commit cancelled after preview.'));
- process.exit(0);
- }
- }
-
- try {
- const commitCommand = cmdObj.sign
- ? `git commit -S -m "${commitMsg.replace(/"/g, '\\"')}"`
- : `git commit -m "${commitMsg.replace(/"/g, '\\"')}"`;
- execSync(commitCommand, { stdio: 'inherit' });
- console.log(chalk.green('Commit successful!'));
- } catch (err: any) {
- console.error(chalk.red('Error during commit:'), err.message);
- process.exit(1);
- }
-
- if (cmdObj.push) {
- try {
- execSync('git push', { stdio: 'inherit' });
- console.log(chalk.green('Pushed successfully!'));
- } catch (err: any) {
- console.error(chalk.red('Push failed:'), err.message);
- }
- }
- });
-
-program
- .command('amend')
- .description('Amend the last commit interactively')
- .action(async () => {
- const config = loadConfig();
- try {
- const currentMsg = execSync('git log -1 --pretty=%B', { encoding: 'utf8' }).trim();
- console.log(chalk.blue("Current commit message:\n") + currentMsg);
- const { amendConfirm } = await inquirer.prompt([
- {
- type: 'confirm',
- name: 'amendConfirm',
- message: 'Do you want to amend the last commit?',
- default: true,
- }
- ]);
- if (!amendConfirm) {
- console.log(chalk.yellow("Amend cancelled."));
- process.exit(0);
- }
- const { newMessage } = await inquirer.prompt([
- {
- type: 'editor',
- name: 'newMessage',
- message: 'Edit the commit message:',
- default: currentMsg,
- }
- ]);
- const errors = config.enableLint ? lintCommitMessage(newMessage, config.lintRules) : [];
- if (errors.length > 0) {
- console.log(chalk.red("Linting errors:"));
- errors.forEach(err => console.log(chalk.red("- " + err)));
- console.log(chalk.red("Amend aborted due to linting errors."));
- process.exit(1);
- }
- execSync(`git commit --amend -m "${newMessage.replace(/"/g, '\\"')}"`, { stdio: 'inherit' });
- console.log(chalk.green("Commit amended successfully!"));
- } catch (err: any) {
- console.error(chalk.red("Error during amend:"), err.message);
- process.exit(1);
- }
- });
-
-program
- .command('rollback')
- .description('Rollback the last commit while choosing between soft and hard reset')
- .action(async () => {
- const { resetType } = await inquirer.prompt([
- {
- type: 'list',
- name: 'resetType',
- message: 'Choose rollback type:',
- choices: [
- { name: 'Soft reset (keep changes staged)', value: 'soft' },
- { name: 'Hard reset (discard changes)', value: 'hard' }
- ],
- }
- ]);
- const { confirmRollback } = await inquirer.prompt([
- {
- type: 'confirm',
- name: 'confirmRollback',
- message: `This will perform a ${resetType} reset on the last commit. Continue?`,
- default: false,
- }
- ]);
- if (!confirmRollback) {
- console.log(chalk.yellow("Rollback cancelled."));
- process.exit(0);
- }
- try {
- if (resetType === 'soft') {
- execSync('git reset --soft HEAD~1', { stdio: 'inherit' });
- } else {
- execSync('git reset --hard HEAD~1', { stdio: 'inherit' });
- }
- console.log(chalk.green("Rollback successful!"));
- } catch (err: any) {
- console.error(chalk.red("Error during rollback:"), err.message);
- process.exit(1);
- }
- });
-
-program
- .command('rebase-helper')
- .description('Launch interactive rebase helper with explanations')
- .action(async () => {
- const { commitCount } = await inquirer.prompt([
- {
- type: 'input',
- name: 'commitCount',
- message: 'Enter the number of commits to rebase (e.g., 3):',
- validate: (input: string) => {
- const num = parseInt(input, 10);
- return (!isNaN(num) && num > 0) || 'Please enter a valid positive number';
- }
- }
- ]);
- try {
- console.log(chalk.blue(`Launching interactive rebase for the last ${commitCount} commits.`));
- console.log(chalk.blue("In the rebase editor, use the following commands as needed:\n- pick: use the commit\n- reword: use the commit, but edit the commit message\n- edit: stop for amending the commit\n- squash: meld the commit into the previous commit\n- fixup: like squash but discard this commit's message\n- exec: run a shell command\n- drop: remove the commit"));
- execSync(`git rebase -i HEAD~${commitCount}`, { stdio: 'inherit' });
- console.log(chalk.green("Interactive rebase completed."));
- } catch (err: any) {
- console.error(chalk.red("Error during interactive rebase:"), err.message);
- process.exit(1);
- }
- });
-
-program
- .command('stats')
- .description('Show enhanced commit statistics with ASCII graphs')
- .action(async () => {
- const { period } = await inquirer.prompt([
- {
- type: 'list',
- name: 'period',
- message: 'Select period for statistics:',
- choices: [
- { name: 'Day', value: '1 day ago' },
- { name: 'Week', value: '1 week ago' },
- { name: 'Month', value: '1 month ago' }
- ],
- }
- ]);
- const { statsType } = await inquirer.prompt([
- {
- type: 'list',
- name: 'statsType',
- message: 'Select type of statistics:',
- choices: [
- { name: 'Shortlog by author', value: 'shortlog' },
- { name: 'Activity by date', value: 'activity' }
- ],
- }
- ]);
- try {
- if (statsType === 'shortlog') {
- execSync(`git shortlog -s -n --since="${period}"`, { stdio: 'inherit' });
- } else if (statsType === 'activity') {
- const datesOutput = execSync(`git log --since="${period}" --pretty=format:"%ad" --date=short`, { encoding: 'utf8' });
- const dates = datesOutput.split('\n').filter(Boolean);
- const counts: { [date: string]: number } = {};
- dates.forEach(date => { counts[date] = (counts[date] || 0) + 1; });
- const sortedDates = Object.keys(counts).sort();
- console.log(chalk.blue("\nCommit Activity:"));
- sortedDates.forEach(date => {
- const count = counts[date];
- const bar = "#".repeat(count);
- console.log(chalk.green(`${date}: ${bar} (${count})`));
- });
- }
- } catch (err: any) {
- console.error(chalk.red("Error retrieving statistics:"), err.message);
- process.exit(1);
- }
- });
-
-program
- .command('history')
- .description('Show commit history with search options')
- .action(async () => {
- const { filterType } = await inquirer.prompt([
- {
- type: 'list',
- name: 'filterType',
- message: 'Select search type:',
- choices: [
- { name: 'Search by keyword in commit message', value: 'keyword' },
- { name: 'By author', value: 'author' },
- { name: 'By date range', value: 'date' }
- ],
- }
- ]);
- let command = 'git log --pretty=oneline';
- if (filterType === 'keyword') {
- const { keyword } = await inquirer.prompt([
- {
- type: 'input',
- name: 'keyword',
- message: 'Enter keyword to search in commit messages:',
- }
- ]);
- command += ` --grep="${keyword}"`;
- } else if (filterType === 'author') {
- const { author } = await inquirer.prompt([
- {
- type: 'input',
- name: 'author',
- message: 'Enter author name or email:',
- }
- ]);
- command += ` --author="${author}"`;
- } else if (filterType === 'date') {
- const { since, until } = await inquirer.prompt([
- {
- type: 'input',
- name: 'since',
- message: 'Enter start date (YYYY-MM-DD):',
- },
- {
- type: 'input',
- name: 'until',
- message: 'Enter end date (YYYY-MM-DD):',
- }
- ]);
- command += ` --since="${since}" --until="${until}"`;
- }
- try {
- const history = execSync(command, { encoding: 'utf8' });
- console.log(chalk.blue("\nCommit History:\n"));
- console.log(chalk.green(history));
- } catch (err: any) {
- console.error(chalk.red("Error retrieving history:"), err.message);
- process.exit(1);
- }
- });
-
-program.parse(process.argv);
\ No newline at end of file
diff --git a/jest.config.js b/jest.config.js
new file mode 100644
index 0000000..0ac7ecf
--- /dev/null
+++ b/jest.config.js
@@ -0,0 +1,9 @@
+/** @type {import('ts-jest').JestConfigWithTsJest} */
+module.exports = {
+ preset: 'ts-jest',
+ testEnvironment: 'node',
+ testMatch: ['**/__tests__/**/*.test.(ts|js)'],
+ transformIgnorePatterns: [
+ '/node_modules/(?!chalk|ansi-styles)/',
+ ],
+};
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index e5f9371..6fde6b0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,723 +1,5460 @@
{
"name": "@el1fe/smart-commit",
- "version": "1.1.1",
+ "version": "1.1.5",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@el1fe/smart-commit",
- "version": "1.1.1",
+ "version": "1.1.5",
"license": "MIT",
"dependencies": {
- "chalk": "^5.4.1",
+ "chalk": "^4.1.2",
"commander": "^13.1.0",
"diff-so-fancy": "^1.4.3",
- "inquirer": "^12.4.2"
+ "inquirer": "^8.2.0",
+ "inquirer-autocomplete-prompt": "^2.0.0",
+ "micromatch": "^4.0.8",
+ "parse-gitignore": "^2.0.0"
},
"bin": {
"sc": "dist/index.js",
"smart-commit": "dist/index.js"
},
"devDependencies": {
+ "@babel/core": "^7.26.9",
+ "@babel/preset-env": "^7.26.9",
"@types/commander": "^2.12.0",
- "@types/inquirer": "^9.0.7",
+ "@types/inquirer": "^8.2.0",
+ "@types/inquirer-autocomplete-prompt": "^2.0.0",
+ "@types/jest": "^29.5.14",
+ "@types/micromatch": "^4.0.9",
"@types/node": "^22.13.4",
+ "@types/parse-gitignore": "^1.0.2",
+ "babel-jest": "^29.7.0",
+ "jest": "^29.7.0",
+ "ts-jest": "^29.2.5",
"ts-node": "^10.9.2",
"typescript": "^5.7.3"
}
},
- "node_modules/@cspotcode/source-map-support": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
- "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+ "node_modules/@ampproject/remapping": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
+ "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
"dev": true,
- "license": "MIT",
+ "license": "Apache-2.0",
"dependencies": {
- "@jridgewell/trace-mapping": "0.3.9"
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
},
"engines": {
- "node": ">=12"
+ "node": ">=6.0.0"
}
},
- "node_modules/@inquirer/checkbox": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.1.2.tgz",
- "integrity": "sha512-PL9ixC5YsPXzXhAZFUPmkXGxfgjkdfZdPEPPmt4kFwQ4LBMDG9n/nHXYRGGZSKZJs+d1sGKWgS2GiPzVRKUdtQ==",
+ "node_modules/@babel/code-frame": {
+ "version": "7.26.2",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
+ "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "@inquirer/core": "^10.1.7",
- "@inquirer/figures": "^1.0.10",
- "@inquirer/type": "^3.0.4",
- "ansi-escapes": "^4.3.2",
- "yoctocolors-cjs": "^2.1.2"
+ "@babel/helper-validator-identifier": "^7.25.9",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.0.0"
},
"engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
+ "node": ">=6.9.0"
}
},
- "node_modules/@inquirer/confirm": {
- "version": "5.1.6",
- "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.6.tgz",
- "integrity": "sha512-6ZXYK3M1XmaVBZX6FCfChgtponnL0R6I7k8Nu+kaoNkT828FVZTcca1MqmWQipaW2oNREQl5AaPCUOOCVNdRMw==",
+ "node_modules/@babel/compat-data": {
+ "version": "7.26.8",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz",
+ "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==",
+ "dev": true,
"license": "MIT",
- "dependencies": {
- "@inquirer/core": "^10.1.7",
- "@inquirer/type": "^3.0.4"
- },
"engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
+ "node": ">=6.9.0"
}
},
- "node_modules/@inquirer/core": {
- "version": "10.1.7",
- "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.7.tgz",
- "integrity": "sha512-AA9CQhlrt6ZgiSy6qoAigiA1izOa751ugX6ioSjqgJ+/Gd+tEN/TORk5sUYNjXuHWfW0r1n/a6ak4u/NqHHrtA==",
+ "node_modules/@babel/core": {
+ "version": "7.26.9",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.9.tgz",
+ "integrity": "sha512-lWBYIrF7qK5+GjY5Uy+/hEgp8OJWOD/rpy74GplYRhEauvbHDeFB8t5hPOZxCZ0Oxf4Cc36tK51/l3ymJysrKw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "@inquirer/figures": "^1.0.10",
- "@inquirer/type": "^3.0.4",
- "ansi-escapes": "^4.3.2",
- "cli-width": "^4.1.0",
- "mute-stream": "^2.0.0",
- "signal-exit": "^4.1.0",
- "wrap-ansi": "^6.2.0",
- "yoctocolors-cjs": "^2.1.2"
+ "@ampproject/remapping": "^2.2.0",
+ "@babel/code-frame": "^7.26.2",
+ "@babel/generator": "^7.26.9",
+ "@babel/helper-compilation-targets": "^7.26.5",
+ "@babel/helper-module-transforms": "^7.26.0",
+ "@babel/helpers": "^7.26.9",
+ "@babel/parser": "^7.26.9",
+ "@babel/template": "^7.26.9",
+ "@babel/traverse": "^7.26.9",
+ "@babel/types": "^7.26.9",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
},
"engines": {
- "node": ">=18"
+ "node": ">=6.9.0"
},
- "peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
}
},
- "node_modules/@inquirer/editor": {
- "version": "4.2.7",
- "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.7.tgz",
- "integrity": "sha512-gktCSQtnSZHaBytkJKMKEuswSk2cDBuXX5rxGFv306mwHfBPjg5UAldw9zWGoEyvA9KpRDkeM4jfrx0rXn0GyA==",
+ "node_modules/@babel/generator": {
+ "version": "7.26.9",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.9.tgz",
+ "integrity": "sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "@inquirer/core": "^10.1.7",
- "@inquirer/type": "^3.0.4",
- "external-editor": "^3.1.0"
+ "@babel/parser": "^7.26.9",
+ "@babel/types": "^7.26.9",
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.25",
+ "jsesc": "^3.0.2"
},
"engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
+ "node": ">=6.9.0"
}
},
- "node_modules/@inquirer/expand": {
- "version": "4.0.9",
- "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.9.tgz",
- "integrity": "sha512-Xxt6nhomWTAmuSX61kVgglLjMEFGa+7+F6UUtdEUeg7fg4r9vaFttUUKrtkViYYrQBA5Ia1tkOJj2koP9BuLig==",
+ "node_modules/@babel/helper-annotate-as-pure": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz",
+ "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "@inquirer/core": "^10.1.7",
- "@inquirer/type": "^3.0.4",
- "yoctocolors-cjs": "^2.1.2"
+ "@babel/types": "^7.25.9"
},
"engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
+ "node": ">=6.9.0"
}
},
- "node_modules/@inquirer/figures": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.10.tgz",
- "integrity": "sha512-Ey6176gZmeqZuY/W/nZiUyvmb1/qInjcpiZjXWi6nON+nxJpD1bxtSoBxNliGISae32n6OwbY+TSXPZ1CfS4bw==",
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.26.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz",
+ "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==",
+ "dev": true,
"license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.26.5",
+ "@babel/helper-validator-option": "^7.25.9",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
"engines": {
- "node": ">=18"
+ "node": ">=6.9.0"
}
},
- "node_modules/@inquirer/input": {
- "version": "4.1.6",
- "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.1.6.tgz",
- "integrity": "sha512-1f5AIsZuVjPT4ecA8AwaxDFNHny/tSershP/cTvTDxLdiIGTeILNcKozB0LaYt6mojJLUbOYhpIxicaYf7UKIQ==",
+ "node_modules/@babel/helper-create-class-features-plugin": {
+ "version": "7.26.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.26.9.tgz",
+ "integrity": "sha512-ubbUqCofvxPRurw5L8WTsCLSkQiVpov4Qx0WMA+jUN+nXBK8ADPlJO1grkFw5CWKC5+sZSOfuGMdX1aI1iT9Sg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "@inquirer/core": "^10.1.7",
- "@inquirer/type": "^3.0.4"
+ "@babel/helper-annotate-as-pure": "^7.25.9",
+ "@babel/helper-member-expression-to-functions": "^7.25.9",
+ "@babel/helper-optimise-call-expression": "^7.25.9",
+ "@babel/helper-replace-supers": "^7.26.5",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9",
+ "@babel/traverse": "^7.26.9",
+ "semver": "^6.3.1"
},
"engines": {
- "node": ">=18"
+ "node": ">=6.9.0"
},
"peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
+ "@babel/core": "^7.0.0"
}
},
- "node_modules/@inquirer/number": {
- "version": "3.0.9",
- "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.9.tgz",
- "integrity": "sha512-iN2xZvH3tyIYXLXBvlVh0npk1q/aVuKXZo5hj+K3W3D4ngAEq/DkLpofRzx6oebTUhBvOgryZ+rMV0yImKnG3w==",
+ "node_modules/@babel/helper-create-regexp-features-plugin": {
+ "version": "7.26.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.26.3.tgz",
+ "integrity": "sha512-G7ZRb40uUgdKOQqPLjfD12ZmGA54PzqDFUv2BKImnC9QIfGhIHKvVML0oN8IUiDq4iRqpq74ABpvOaerfWdong==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "@inquirer/core": "^10.1.7",
- "@inquirer/type": "^3.0.4"
+ "@babel/helper-annotate-as-pure": "^7.25.9",
+ "regexpu-core": "^6.2.0",
+ "semver": "^6.3.1"
},
"engines": {
- "node": ">=18"
+ "node": ">=6.9.0"
},
"peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
+ "@babel/core": "^7.0.0"
}
},
- "node_modules/@inquirer/password": {
- "version": "4.0.9",
- "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.9.tgz",
- "integrity": "sha512-xBEoOw1XKb0rIN208YU7wM7oJEHhIYkfG7LpTJAEW913GZeaoQerzf5U/LSHI45EVvjAdgNXmXgH51cUXKZcJQ==",
+ "node_modules/@babel/helper-define-polyfill-provider": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.3.tgz",
+ "integrity": "sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "@inquirer/core": "^10.1.7",
- "@inquirer/type": "^3.0.4",
- "ansi-escapes": "^4.3.2"
- },
- "engines": {
- "node": ">=18"
+ "@babel/helper-compilation-targets": "^7.22.6",
+ "@babel/helper-plugin-utils": "^7.22.5",
+ "debug": "^4.1.1",
+ "lodash.debounce": "^4.0.8",
+ "resolve": "^1.14.2"
},
"peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
+ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
}
},
- "node_modules/@inquirer/prompts": {
- "version": "7.3.2",
- "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.3.2.tgz",
- "integrity": "sha512-G1ytyOoHh5BphmEBxSwALin3n1KGNYB6yImbICcRQdzXfOGbuJ9Jske/Of5Sebk339NSGGNfUshnzK8YWkTPsQ==",
+ "node_modules/@babel/helper-member-expression-to-functions": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz",
+ "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "@inquirer/checkbox": "^4.1.2",
- "@inquirer/confirm": "^5.1.6",
- "@inquirer/editor": "^4.2.7",
- "@inquirer/expand": "^4.0.9",
- "@inquirer/input": "^4.1.6",
- "@inquirer/number": "^3.0.9",
- "@inquirer/password": "^4.0.9",
- "@inquirer/rawlist": "^4.0.9",
- "@inquirer/search": "^3.0.9",
- "@inquirer/select": "^4.0.9"
+ "@babel/traverse": "^7.25.9",
+ "@babel/types": "^7.25.9"
},
"engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
+ "node": ">=6.9.0"
}
},
- "node_modules/@inquirer/rawlist": {
- "version": "4.0.9",
- "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.0.9.tgz",
- "integrity": "sha512-+5t6ebehKqgoxV8fXwE49HkSF2Rc9ijNiVGEQZwvbMI61/Q5RcD+jWD6Gs1tKdz5lkI8GRBL31iO0HjGK1bv+A==",
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz",
+ "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "@inquirer/core": "^10.1.7",
- "@inquirer/type": "^3.0.4",
- "yoctocolors-cjs": "^2.1.2"
+ "@babel/traverse": "^7.25.9",
+ "@babel/types": "^7.25.9"
},
"engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
+ "node": ">=6.9.0"
}
},
- "node_modules/@inquirer/search": {
- "version": "3.0.9",
- "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.0.9.tgz",
- "integrity": "sha512-DWmKztkYo9CvldGBaRMr0ETUHgR86zE6sPDVOHsqz4ISe9o1LuiWfgJk+2r75acFclA93J/lqzhT0dTjCzHuoA==",
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.26.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz",
+ "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "@inquirer/core": "^10.1.7",
- "@inquirer/figures": "^1.0.10",
- "@inquirer/type": "^3.0.4",
- "yoctocolors-cjs": "^2.1.2"
+ "@babel/helper-module-imports": "^7.25.9",
+ "@babel/helper-validator-identifier": "^7.25.9",
+ "@babel/traverse": "^7.25.9"
},
"engines": {
- "node": ">=18"
+ "node": ">=6.9.0"
},
"peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
+ "@babel/core": "^7.0.0"
}
},
- "node_modules/@inquirer/select": {
- "version": "4.0.9",
- "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.0.9.tgz",
- "integrity": "sha512-BpJyJe7Dkhv2kz7yG7bPSbJLQuu/rqyNlF1CfiiFeFwouegfH+zh13KDyt6+d9DwucKo7hqM3wKLLyJxZMO+Xg==",
+ "node_modules/@babel/helper-optimise-call-expression": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz",
+ "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "@inquirer/core": "^10.1.7",
- "@inquirer/figures": "^1.0.10",
- "@inquirer/type": "^3.0.4",
- "ansi-escapes": "^4.3.2",
- "yoctocolors-cjs": "^2.1.2"
+ "@babel/types": "^7.25.9"
},
"engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
+ "node": ">=6.9.0"
}
},
- "node_modules/@inquirer/type": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.4.tgz",
- "integrity": "sha512-2MNFrDY8jkFYc9Il9DgLsHhMzuHnOYM1+CUYVWbzu9oT0hC7V7EcYvdCKeoll/Fcci04A+ERZ9wcc7cQ8lTkIA==",
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.26.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz",
+ "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==",
+ "dev": true,
"license": "MIT",
"engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@types/node": ">=18"
- },
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
- }
+ "node": ">=6.9.0"
}
},
- "node_modules/@jridgewell/resolve-uri": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
- "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "node_modules/@babel/helper-remap-async-to-generator": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz",
+ "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==",
"dev": true,
"license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.25.9",
+ "@babel/helper-wrap-function": "^7.25.9",
+ "@babel/traverse": "^7.25.9"
+ },
"engines": {
- "node": ">=6.0.0"
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
}
},
- "node_modules/@jridgewell/sourcemap-codec": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
- "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@jridgewell/trace-mapping": {
- "version": "0.3.9",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
- "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+ "node_modules/@babel/helper-replace-supers": {
+ "version": "7.26.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz",
+ "integrity": "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@jridgewell/resolve-uri": "^3.0.3",
- "@jridgewell/sourcemap-codec": "^1.4.10"
+ "@babel/helper-member-expression-to-functions": "^7.25.9",
+ "@babel/helper-optimise-call-expression": "^7.25.9",
+ "@babel/traverse": "^7.26.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
}
},
- "node_modules/@tsconfig/node10": {
- "version": "1.0.11",
- "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
- "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==",
+ "node_modules/@babel/helper-skip-transparent-expression-wrappers": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz",
+ "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.25.9",
+ "@babel/types": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
},
- "node_modules/@tsconfig/node12": {
- "version": "1.0.11",
- "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
- "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
+ "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
},
- "node_modules/@tsconfig/node14": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
- "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
+ "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
},
- "node_modules/@tsconfig/node16": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
- "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz",
+ "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==",
"dev": true,
- "license": "MIT"
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
},
- "node_modules/@types/commander": {
- "version": "2.12.0",
- "resolved": "https://registry.npmjs.org/@types/commander/-/commander-2.12.0.tgz",
- "integrity": "sha512-DDmRkovH7jPjnx7HcbSnqKg2JeNANyxNZeUvB0iE+qKBLN+vzN5iSIwt+J2PFSmBuYEut4mgQvI/fTX9YQH/vw==",
+ "node_modules/@babel/helper-wrap-function": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz",
+ "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "commander": "*"
+ "@babel/template": "^7.25.9",
+ "@babel/traverse": "^7.25.9",
+ "@babel/types": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
}
},
- "node_modules/@types/inquirer": {
- "version": "9.0.7",
- "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-9.0.7.tgz",
- "integrity": "sha512-Q0zyBupO6NxGRZut/JdmqYKOnN95Eg5V8Csg3PGKkP+FnvsUZx1jAyK7fztIszxxMuoBA6E3KXWvdZVXIpx60g==",
+ "node_modules/@babel/helpers": {
+ "version": "7.26.9",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.9.tgz",
+ "integrity": "sha512-Mz/4+y8udxBKdmzt/UjPACs4G3j5SshJJEFFKxlCGPydG4JAHXxjWjAwjd09tf6oINvl1VfMJo+nB7H2YKQ0dA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@types/through": "*",
- "rxjs": "^7.2.0"
+ "@babel/template": "^7.26.9",
+ "@babel/types": "^7.26.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
}
},
- "node_modules/@types/node": {
- "version": "22.13.4",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.4.tgz",
- "integrity": "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==",
- "devOptional": true,
+ "node_modules/@babel/parser": {
+ "version": "7.26.9",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.9.tgz",
+ "integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "undici-types": "~6.20.0"
+ "@babel/types": "^7.26.9"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
}
},
- "node_modules/@types/through": {
- "version": "0.0.33",
- "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.33.tgz",
- "integrity": "sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==",
+ "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz",
+ "integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@types/node": "*"
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/traverse": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
}
},
- "node_modules/acorn": {
- "version": "8.14.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
- "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
+ "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz",
+ "integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==",
"dev": true,
"license": "MIT",
- "bin": {
- "acorn": "bin/acorn"
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
},
"engines": {
- "node": ">=0.4.0"
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
}
},
- "node_modules/acorn-walk": {
- "version": "8.3.4",
- "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
- "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
+ "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz",
+ "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==",
"dev": true,
"license": "MIT",
"dependencies": {
- "acorn": "^8.11.0"
+ "@babel/helper-plugin-utils": "^7.25.9"
},
"engines": {
- "node": ">=0.4.0"
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
}
},
- "node_modules/ansi-escapes": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
- "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
+ "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz",
+ "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "type-fest": "^0.21.3"
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9",
+ "@babel/plugin-transform-optional-chaining": "^7.25.9"
},
"engines": {
- "node": ">=8"
+ "node": ">=6.9.0"
},
- "funding": {
+ "peerDependencies": {
+ "@babel/core": "^7.13.0"
+ }
+ },
+ "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz",
+ "integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/traverse": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-proposal-private-property-in-object": {
+ "version": "7.21.0-placeholder-for-preset-env.2",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz",
+ "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-async-generators": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
+ "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-bigint": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz",
+ "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-class-properties": {
+ "version": "7.12.13",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz",
+ "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.12.13"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-class-static-block": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz",
+ "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-import-assertions": {
+ "version": "7.26.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz",
+ "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-import-attributes": {
+ "version": "7.26.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz",
+ "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-import-meta": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
+ "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-json-strings": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
+ "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-jsx": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz",
+ "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-logical-assignment-operators": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz",
+ "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz",
+ "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-numeric-separator": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz",
+ "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-object-rest-spread": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz",
+ "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-optional-catch-binding": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz",
+ "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-optional-chaining": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz",
+ "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-private-property-in-object": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz",
+ "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-top-level-await": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz",
+ "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-typescript": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz",
+ "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-unicode-sets-regex": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz",
+ "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.18.6",
+ "@babel/helper-plugin-utils": "^7.18.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-arrow-functions": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz",
+ "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-async-generator-functions": {
+ "version": "7.26.8",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.26.8.tgz",
+ "integrity": "sha512-He9Ej2X7tNf2zdKMAGOsmg2MrFc+hfoAhd3po4cWfo/NWjzEAKa0oQruj1ROVUdl0e6fb6/kE/G3SSxE0lRJOg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.26.5",
+ "@babel/helper-remap-async-to-generator": "^7.25.9",
+ "@babel/traverse": "^7.26.8"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-async-to-generator": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz",
+ "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/helper-remap-async-to-generator": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-block-scoped-functions": {
+ "version": "7.26.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.26.5.tgz",
+ "integrity": "sha512-chuTSY+hq09+/f5lMj8ZSYgCFpppV2CbYrhNFJ1BFoXpiWPnnAb7R0MqrafCpN8E1+YRrtM1MXZHJdIx8B6rMQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.26.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-block-scoping": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz",
+ "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-class-properties": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz",
+ "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-class-features-plugin": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-class-static-block": {
+ "version": "7.26.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz",
+ "integrity": "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-class-features-plugin": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.12.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-classes": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz",
+ "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.25.9",
+ "@babel/helper-compilation-targets": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/helper-replace-supers": "^7.25.9",
+ "@babel/traverse": "^7.25.9",
+ "globals": "^11.1.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-computed-properties": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz",
+ "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/template": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-destructuring": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz",
+ "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-dotall-regex": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz",
+ "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-duplicate-keys": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz",
+ "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz",
+ "integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-dynamic-import": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz",
+ "integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-exponentiation-operator": {
+ "version": "7.26.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.26.3.tgz",
+ "integrity": "sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-export-namespace-from": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz",
+ "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-for-of": {
+ "version": "7.26.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.26.9.tgz",
+ "integrity": "sha512-Hry8AusVm8LW5BVFgiyUReuoGzPUpdHQQqJY5bZnbbf+ngOHWuCuYFKw/BqaaWlvEUrF91HMhDtEaI1hZzNbLg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.26.5",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-function-name": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz",
+ "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-compilation-targets": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/traverse": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-json-strings": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz",
+ "integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-literals": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz",
+ "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-logical-assignment-operators": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz",
+ "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-member-expression-literals": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz",
+ "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-modules-amd": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz",
+ "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-transforms": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-modules-commonjs": {
+ "version": "7.26.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz",
+ "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-transforms": "^7.26.0",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-modules-systemjs": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz",
+ "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-transforms": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/helper-validator-identifier": "^7.25.9",
+ "@babel/traverse": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-modules-umd": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz",
+ "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-transforms": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-named-capturing-groups-regex": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz",
+ "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-new-target": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz",
+ "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-nullish-coalescing-operator": {
+ "version": "7.26.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.26.6.tgz",
+ "integrity": "sha512-CKW8Vu+uUZneQCPtXmSBUC6NCAUdya26hWCElAWh5mVSlSRsmiCPUUDKb3Z0szng1hiAJa098Hkhg9o4SE35Qw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.26.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-numeric-separator": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz",
+ "integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-object-rest-spread": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz",
+ "integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-compilation-targets": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/plugin-transform-parameters": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-object-super": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz",
+ "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/helper-replace-supers": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-optional-catch-binding": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz",
+ "integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-optional-chaining": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz",
+ "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-parameters": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz",
+ "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-private-methods": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz",
+ "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-class-features-plugin": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-private-property-in-object": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz",
+ "integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.25.9",
+ "@babel/helper-create-class-features-plugin": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-property-literals": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz",
+ "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-regenerator": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz",
+ "integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "regenerator-transform": "^0.15.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-regexp-modifiers": {
+ "version": "7.26.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz",
+ "integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-reserved-words": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz",
+ "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-shorthand-properties": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz",
+ "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-spread": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz",
+ "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-sticky-regex": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz",
+ "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-template-literals": {
+ "version": "7.26.8",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.26.8.tgz",
+ "integrity": "sha512-OmGDL5/J0CJPJZTHZbi2XpO0tyT2Ia7fzpW5GURwdtp2X3fMmN8au/ej6peC/T33/+CRiIpA8Krse8hFGVmT5Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.26.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-typeof-symbol": {
+ "version": "7.26.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.26.7.tgz",
+ "integrity": "sha512-jfoTXXZTgGg36BmhqT3cAYK5qkmqvJpvNrPhaK/52Vgjhw4Rq29s9UqpWWV0D6yuRmgiFH/BUVlkl96zJWqnaw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.26.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-unicode-escapes": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz",
+ "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-unicode-property-regex": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz",
+ "integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-unicode-regex": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz",
+ "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-unicode-sets-regex": {
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz",
+ "integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.25.9",
+ "@babel/helper-plugin-utils": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/preset-env": {
+ "version": "7.26.9",
+ "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.9.tgz",
+ "integrity": "sha512-vX3qPGE8sEKEAZCWk05k3cpTAE3/nOYca++JA+Rd0z2NCNzabmYvEiSShKzm10zdquOIAVXsy2Ei/DTW34KlKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.26.8",
+ "@babel/helper-compilation-targets": "^7.26.5",
+ "@babel/helper-plugin-utils": "^7.26.5",
+ "@babel/helper-validator-option": "^7.25.9",
+ "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9",
+ "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9",
+ "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9",
+ "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9",
+ "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9",
+ "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2",
+ "@babel/plugin-syntax-import-assertions": "^7.26.0",
+ "@babel/plugin-syntax-import-attributes": "^7.26.0",
+ "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6",
+ "@babel/plugin-transform-arrow-functions": "^7.25.9",
+ "@babel/plugin-transform-async-generator-functions": "^7.26.8",
+ "@babel/plugin-transform-async-to-generator": "^7.25.9",
+ "@babel/plugin-transform-block-scoped-functions": "^7.26.5",
+ "@babel/plugin-transform-block-scoping": "^7.25.9",
+ "@babel/plugin-transform-class-properties": "^7.25.9",
+ "@babel/plugin-transform-class-static-block": "^7.26.0",
+ "@babel/plugin-transform-classes": "^7.25.9",
+ "@babel/plugin-transform-computed-properties": "^7.25.9",
+ "@babel/plugin-transform-destructuring": "^7.25.9",
+ "@babel/plugin-transform-dotall-regex": "^7.25.9",
+ "@babel/plugin-transform-duplicate-keys": "^7.25.9",
+ "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9",
+ "@babel/plugin-transform-dynamic-import": "^7.25.9",
+ "@babel/plugin-transform-exponentiation-operator": "^7.26.3",
+ "@babel/plugin-transform-export-namespace-from": "^7.25.9",
+ "@babel/plugin-transform-for-of": "^7.26.9",
+ "@babel/plugin-transform-function-name": "^7.25.9",
+ "@babel/plugin-transform-json-strings": "^7.25.9",
+ "@babel/plugin-transform-literals": "^7.25.9",
+ "@babel/plugin-transform-logical-assignment-operators": "^7.25.9",
+ "@babel/plugin-transform-member-expression-literals": "^7.25.9",
+ "@babel/plugin-transform-modules-amd": "^7.25.9",
+ "@babel/plugin-transform-modules-commonjs": "^7.26.3",
+ "@babel/plugin-transform-modules-systemjs": "^7.25.9",
+ "@babel/plugin-transform-modules-umd": "^7.25.9",
+ "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9",
+ "@babel/plugin-transform-new-target": "^7.25.9",
+ "@babel/plugin-transform-nullish-coalescing-operator": "^7.26.6",
+ "@babel/plugin-transform-numeric-separator": "^7.25.9",
+ "@babel/plugin-transform-object-rest-spread": "^7.25.9",
+ "@babel/plugin-transform-object-super": "^7.25.9",
+ "@babel/plugin-transform-optional-catch-binding": "^7.25.9",
+ "@babel/plugin-transform-optional-chaining": "^7.25.9",
+ "@babel/plugin-transform-parameters": "^7.25.9",
+ "@babel/plugin-transform-private-methods": "^7.25.9",
+ "@babel/plugin-transform-private-property-in-object": "^7.25.9",
+ "@babel/plugin-transform-property-literals": "^7.25.9",
+ "@babel/plugin-transform-regenerator": "^7.25.9",
+ "@babel/plugin-transform-regexp-modifiers": "^7.26.0",
+ "@babel/plugin-transform-reserved-words": "^7.25.9",
+ "@babel/plugin-transform-shorthand-properties": "^7.25.9",
+ "@babel/plugin-transform-spread": "^7.25.9",
+ "@babel/plugin-transform-sticky-regex": "^7.25.9",
+ "@babel/plugin-transform-template-literals": "^7.26.8",
+ "@babel/plugin-transform-typeof-symbol": "^7.26.7",
+ "@babel/plugin-transform-unicode-escapes": "^7.25.9",
+ "@babel/plugin-transform-unicode-property-regex": "^7.25.9",
+ "@babel/plugin-transform-unicode-regex": "^7.25.9",
+ "@babel/plugin-transform-unicode-sets-regex": "^7.25.9",
+ "@babel/preset-modules": "0.1.6-no-external-plugins",
+ "babel-plugin-polyfill-corejs2": "^0.4.10",
+ "babel-plugin-polyfill-corejs3": "^0.11.0",
+ "babel-plugin-polyfill-regenerator": "^0.6.1",
+ "core-js-compat": "^3.40.0",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/preset-modules": {
+ "version": "0.1.6-no-external-plugins",
+ "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz",
+ "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/types": "^7.4.4",
+ "esutils": "^2.0.2"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0"
+ }
+ },
+ "node_modules/@babel/runtime": {
+ "version": "7.26.9",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.9.tgz",
+ "integrity": "sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "regenerator-runtime": "^0.14.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.26.9",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz",
+ "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.26.2",
+ "@babel/parser": "^7.26.9",
+ "@babel/types": "^7.26.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.26.9",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.9.tgz",
+ "integrity": "sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.26.2",
+ "@babel/generator": "^7.26.9",
+ "@babel/parser": "^7.26.9",
+ "@babel/template": "^7.26.9",
+ "@babel/types": "^7.26.9",
+ "debug": "^4.3.1",
+ "globals": "^11.1.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.26.9",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.9.tgz",
+ "integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.25.9",
+ "@babel/helper-validator-identifier": "^7.25.9"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@bcoe/v8-coverage": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
+ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@cspotcode/source-map-support": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+ "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/trace-mapping": "0.3.9"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+ "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.0.3",
+ "@jridgewell/sourcemap-codec": "^1.4.10"
+ }
+ },
+ "node_modules/@istanbuljs/load-nyc-config": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
+ "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "camelcase": "^5.3.1",
+ "find-up": "^4.1.0",
+ "get-package-type": "^0.1.0",
+ "js-yaml": "^3.13.1",
+ "resolve-from": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@istanbuljs/schema": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
+ "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@jest/console": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz",
+ "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "chalk": "^4.0.0",
+ "jest-message-util": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/core": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz",
+ "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/console": "^29.7.0",
+ "@jest/reporters": "^29.7.0",
+ "@jest/test-result": "^29.7.0",
+ "@jest/transform": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "ansi-escapes": "^4.2.1",
+ "chalk": "^4.0.0",
+ "ci-info": "^3.2.0",
+ "exit": "^0.1.2",
+ "graceful-fs": "^4.2.9",
+ "jest-changed-files": "^29.7.0",
+ "jest-config": "^29.7.0",
+ "jest-haste-map": "^29.7.0",
+ "jest-message-util": "^29.7.0",
+ "jest-regex-util": "^29.6.3",
+ "jest-resolve": "^29.7.0",
+ "jest-resolve-dependencies": "^29.7.0",
+ "jest-runner": "^29.7.0",
+ "jest-runtime": "^29.7.0",
+ "jest-snapshot": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "jest-validate": "^29.7.0",
+ "jest-watcher": "^29.7.0",
+ "micromatch": "^4.0.4",
+ "pretty-format": "^29.7.0",
+ "slash": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ },
+ "peerDependencies": {
+ "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
+ },
+ "peerDependenciesMeta": {
+ "node-notifier": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@jest/environment": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz",
+ "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/fake-timers": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "jest-mock": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/expect": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz",
+ "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "expect": "^29.7.0",
+ "jest-snapshot": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/expect-utils": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz",
+ "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "jest-get-type": "^29.6.3"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/fake-timers": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz",
+ "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "@sinonjs/fake-timers": "^10.0.2",
+ "@types/node": "*",
+ "jest-message-util": "^29.7.0",
+ "jest-mock": "^29.7.0",
+ "jest-util": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/globals": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz",
+ "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/environment": "^29.7.0",
+ "@jest/expect": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "jest-mock": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/reporters": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz",
+ "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@bcoe/v8-coverage": "^0.2.3",
+ "@jest/console": "^29.7.0",
+ "@jest/test-result": "^29.7.0",
+ "@jest/transform": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@jridgewell/trace-mapping": "^0.3.18",
+ "@types/node": "*",
+ "chalk": "^4.0.0",
+ "collect-v8-coverage": "^1.0.0",
+ "exit": "^0.1.2",
+ "glob": "^7.1.3",
+ "graceful-fs": "^4.2.9",
+ "istanbul-lib-coverage": "^3.0.0",
+ "istanbul-lib-instrument": "^6.0.0",
+ "istanbul-lib-report": "^3.0.0",
+ "istanbul-lib-source-maps": "^4.0.0",
+ "istanbul-reports": "^3.1.3",
+ "jest-message-util": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "jest-worker": "^29.7.0",
+ "slash": "^3.0.0",
+ "string-length": "^4.0.1",
+ "strip-ansi": "^6.0.0",
+ "v8-to-istanbul": "^9.0.1"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ },
+ "peerDependencies": {
+ "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
+ },
+ "peerDependenciesMeta": {
+ "node-notifier": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@jest/reporters/node_modules/istanbul-lib-instrument": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz",
+ "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@babel/core": "^7.23.9",
+ "@babel/parser": "^7.23.9",
+ "@istanbuljs/schema": "^0.1.3",
+ "istanbul-lib-coverage": "^3.2.0",
+ "semver": "^7.5.4"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@jest/reporters/node_modules/semver": {
+ "version": "7.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
+ "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@jest/schemas": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
+ "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@sinclair/typebox": "^0.27.8"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/source-map": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz",
+ "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/trace-mapping": "^0.3.18",
+ "callsites": "^3.0.0",
+ "graceful-fs": "^4.2.9"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/test-result": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz",
+ "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/console": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@types/istanbul-lib-coverage": "^2.0.0",
+ "collect-v8-coverage": "^1.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/test-sequencer": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz",
+ "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/test-result": "^29.7.0",
+ "graceful-fs": "^4.2.9",
+ "jest-haste-map": "^29.7.0",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/transform": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz",
+ "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.11.6",
+ "@jest/types": "^29.6.3",
+ "@jridgewell/trace-mapping": "^0.3.18",
+ "babel-plugin-istanbul": "^6.1.1",
+ "chalk": "^4.0.0",
+ "convert-source-map": "^2.0.0",
+ "fast-json-stable-stringify": "^2.1.0",
+ "graceful-fs": "^4.2.9",
+ "jest-haste-map": "^29.7.0",
+ "jest-regex-util": "^29.6.3",
+ "jest-util": "^29.7.0",
+ "micromatch": "^4.0.4",
+ "pirates": "^4.0.4",
+ "slash": "^3.0.0",
+ "write-file-atomic": "^4.0.2"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/types": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz",
+ "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/schemas": "^29.6.3",
+ "@types/istanbul-lib-coverage": "^2.0.0",
+ "@types/istanbul-reports": "^3.0.0",
+ "@types/node": "*",
+ "@types/yargs": "^17.0.8",
+ "chalk": "^4.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.8",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
+ "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/set-array": "^1.2.1",
+ "@jridgewell/sourcemap-codec": "^1.4.10",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/set-array": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
+ "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
+ "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.25",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
+ "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@sinclair/typebox": {
+ "version": "0.27.8",
+ "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
+ "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@sinonjs/commons": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz",
+ "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "type-detect": "4.0.8"
+ }
+ },
+ "node_modules/@sinonjs/fake-timers": {
+ "version": "10.3.0",
+ "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz",
+ "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@sinonjs/commons": "^3.0.0"
+ }
+ },
+ "node_modules/@tsconfig/node10": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
+ "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@tsconfig/node12": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
+ "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@tsconfig/node14": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
+ "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@tsconfig/node16": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
+ "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/babel__core": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.20.7",
+ "@babel/types": "^7.20.7",
+ "@types/babel__generator": "*",
+ "@types/babel__template": "*",
+ "@types/babel__traverse": "*"
+ }
+ },
+ "node_modules/@types/babel__generator": {
+ "version": "7.6.8",
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz",
+ "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__template": {
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__traverse": {
+ "version": "7.20.6",
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz",
+ "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.20.7"
+ }
+ },
+ "node_modules/@types/braces": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/@types/braces/-/braces-3.0.5.tgz",
+ "integrity": "sha512-SQFof9H+LXeWNz8wDe7oN5zu7ket0qwMu5vZubW4GCJ8Kkeh6nBWUz87+KTz/G3Kqsrp0j/W253XJb3KMEeg3w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/commander": {
+ "version": "2.12.0",
+ "resolved": "https://registry.npmjs.org/@types/commander/-/commander-2.12.0.tgz",
+ "integrity": "sha512-DDmRkovH7jPjnx7HcbSnqKg2JeNANyxNZeUvB0iE+qKBLN+vzN5iSIwt+J2PFSmBuYEut4mgQvI/fTX9YQH/vw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "commander": "*"
+ }
+ },
+ "node_modules/@types/graceful-fs": {
+ "version": "4.1.9",
+ "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz",
+ "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/inquirer": {
+ "version": "8.2.10",
+ "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-8.2.10.tgz",
+ "integrity": "sha512-IdD5NmHyVjWM8SHWo/kPBgtzXatwPkfwzyP3fN1jF2g9BWt5WO+8hL2F4o2GKIYsU40PpqeevuUWvkS/roXJkA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/through": "*",
+ "rxjs": "^7.2.0"
+ }
+ },
+ "node_modules/@types/inquirer-autocomplete-prompt": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@types/inquirer-autocomplete-prompt/-/inquirer-autocomplete-prompt-2.0.2.tgz",
+ "integrity": "sha512-Y7RM1dY3KVg11JnFkaQkTT+2Cgmn9K8De/VtrTT2a5grGIoMfkQuYM5Sss+65oiuqg1h1cTsKHG8pkoPsASdbQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/inquirer": "^8"
+ }
+ },
+ "node_modules/@types/istanbul-lib-coverage": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
+ "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/istanbul-lib-report": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz",
+ "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/istanbul-lib-coverage": "*"
+ }
+ },
+ "node_modules/@types/istanbul-reports": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz",
+ "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/istanbul-lib-report": "*"
+ }
+ },
+ "node_modules/@types/jest": {
+ "version": "29.5.14",
+ "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz",
+ "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "expect": "^29.0.0",
+ "pretty-format": "^29.0.0"
+ }
+ },
+ "node_modules/@types/micromatch": {
+ "version": "4.0.9",
+ "resolved": "https://registry.npmjs.org/@types/micromatch/-/micromatch-4.0.9.tgz",
+ "integrity": "sha512-7V+8ncr22h4UoYRLnLXSpTxjQrNUXtWHGeMPRJt1nULXI57G9bIcpyrHlmrQ7QK24EyyuXvYcSSWAM8GA9nqCg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/braces": "*"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "22.13.4",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.4.tgz",
+ "integrity": "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.20.0"
+ }
+ },
+ "node_modules/@types/parse-gitignore": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@types/parse-gitignore/-/parse-gitignore-1.0.2.tgz",
+ "integrity": "sha512-AQwj+lNTWI7y1kkMe8qLByiToXoXs/du70qGFIHJZaJUVrF5jB8QzvWmLyR1VWYqRagpY8ABrqAjs7uHsJnVBQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/stack-utils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz",
+ "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/through": {
+ "version": "0.0.33",
+ "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.33.tgz",
+ "integrity": "sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/yargs": {
+ "version": "17.0.33",
+ "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz",
+ "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/yargs-parser": "*"
+ }
+ },
+ "node_modules/@types/yargs-parser": {
+ "version": "21.0.3",
+ "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz",
+ "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/acorn": {
+ "version": "8.14.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
+ "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-walk": {
+ "version": "8.3.4",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
+ "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.11.0"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/ansi-escapes": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
+ "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
+ "license": "MIT",
+ "dependencies": {
+ "type-fest": "^0.21.3"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "node_modules/async": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
+ "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/babel-jest": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz",
+ "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/transform": "^29.7.0",
+ "@types/babel__core": "^7.1.14",
+ "babel-plugin-istanbul": "^6.1.1",
+ "babel-preset-jest": "^29.6.3",
+ "chalk": "^4.0.0",
+ "graceful-fs": "^4.2.9",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.8.0"
+ }
+ },
+ "node_modules/babel-plugin-istanbul": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz",
+ "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@istanbuljs/load-nyc-config": "^1.0.0",
+ "@istanbuljs/schema": "^0.1.2",
+ "istanbul-lib-instrument": "^5.0.4",
+ "test-exclude": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/babel-plugin-jest-hoist": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz",
+ "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.3.3",
+ "@babel/types": "^7.3.3",
+ "@types/babel__core": "^7.1.14",
+ "@types/babel__traverse": "^7.0.6"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/babel-plugin-polyfill-corejs2": {
+ "version": "0.4.12",
+ "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.12.tgz",
+ "integrity": "sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.22.6",
+ "@babel/helper-define-polyfill-provider": "^0.6.3",
+ "semver": "^6.3.1"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
+ }
+ },
+ "node_modules/babel-plugin-polyfill-corejs3": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz",
+ "integrity": "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-define-polyfill-provider": "^0.6.3",
+ "core-js-compat": "^3.40.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
+ }
+ },
+ "node_modules/babel-plugin-polyfill-regenerator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.3.tgz",
+ "integrity": "sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-define-polyfill-provider": "^0.6.3"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
+ }
+ },
+ "node_modules/babel-preset-current-node-syntax": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz",
+ "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/plugin-syntax-async-generators": "^7.8.4",
+ "@babel/plugin-syntax-bigint": "^7.8.3",
+ "@babel/plugin-syntax-class-properties": "^7.12.13",
+ "@babel/plugin-syntax-class-static-block": "^7.14.5",
+ "@babel/plugin-syntax-import-attributes": "^7.24.7",
+ "@babel/plugin-syntax-import-meta": "^7.10.4",
+ "@babel/plugin-syntax-json-strings": "^7.8.3",
+ "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4",
+ "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
+ "@babel/plugin-syntax-numeric-separator": "^7.10.4",
+ "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
+ "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
+ "@babel/plugin-syntax-optional-chaining": "^7.8.3",
+ "@babel/plugin-syntax-private-property-in-object": "^7.14.5",
+ "@babel/plugin-syntax-top-level-await": "^7.14.5"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/babel-preset-jest": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz",
+ "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "babel-plugin-jest-hoist": "^29.6.3",
+ "babel-preset-current-node-syntax": "^1.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/bl": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+ "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+ "license": "MIT",
+ "dependencies": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.24.4",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz",
+ "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "caniuse-lite": "^1.0.30001688",
+ "electron-to-chromium": "^1.5.73",
+ "node-releases": "^2.0.19",
+ "update-browserslist-db": "^1.1.1"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/bs-logger": {
+ "version": "0.2.6",
+ "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz",
+ "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-json-stable-stringify": "2.x"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/bser": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
+ "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "node-int64": "^0.4.0"
+ }
+ },
+ "node_modules/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001700",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001700.tgz",
+ "integrity": "sha512-2S6XIXwaE7K7erT8dY+kLQcpa5ms63XlRkMkReXjle+kf6c5g38vyMl+Z5y8dSxOFDhcFe+nxnn261PLxBSQsQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/char-regex": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
+ "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/chardet": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+ "license": "MIT"
+ },
+ "node_modules/ci-info": {
+ "version": "3.9.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
+ "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/sibiraj-s"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cjs-module-lexer": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz",
+ "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/cli-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
+ "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
+ "license": "MIT",
+ "dependencies": {
+ "restore-cursor": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cli-spinners": {
+ "version": "2.9.2",
+ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz",
+ "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/cli-width": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
+ "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/cliui/node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/clone": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+ "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/co": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+ "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "iojs": ">= 1.0.0",
+ "node": ">= 0.12.0"
+ }
+ },
+ "node_modules/collect-v8-coverage": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz",
+ "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "license": "MIT"
+ },
+ "node_modules/commander": {
+ "version": "13.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz",
+ "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/core-js-compat": {
+ "version": "3.40.0",
+ "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.40.0.tgz",
+ "integrity": "sha512-0XEDpr5y5mijvw8Lbc6E5AkjrHfp7eEoPlu36SWeAbcL8fn1G1ANe8DBlo2XoNN89oVpxWwOjYIPVzR4ZvsKCQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "browserslist": "^4.24.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/core-js"
+ }
+ },
+ "node_modules/create-jest": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz",
+ "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "chalk": "^4.0.0",
+ "exit": "^0.1.2",
+ "graceful-fs": "^4.2.9",
+ "jest-config": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "prompts": "^2.0.1"
+ },
+ "bin": {
+ "create-jest": "bin/create-jest.js"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/create-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
+ "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/dedent": {
+ "version": "1.5.3",
+ "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz",
+ "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "babel-plugin-macros": "^3.1.0"
+ },
+ "peerDependenciesMeta": {
+ "babel-plugin-macros": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/deepmerge": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
+ "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/defaults": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
+ "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==",
+ "license": "MIT",
+ "dependencies": {
+ "clone": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/detect-newline": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
+ "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/diff-sequences": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
+ "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/diff-so-fancy": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/diff-so-fancy/-/diff-so-fancy-1.4.3.tgz",
+ "integrity": "sha512-ZXNe6ZLdzCHt5cdMPwQOsuNcPI86VYArxloIqmedkTK3qlii59gHe5eR82CrNrc4aZ/A0V1b7askmDzBwftZKA==",
+ "license": "MIT",
+ "bin": {
+ "diff-so-fancy": "third_party/build_fatpack/diff-so-fancy"
+ }
+ },
+ "node_modules/ejs": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz",
+ "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "jake": "^10.8.5"
+ },
+ "bin": {
+ "ejs": "bin/cli.js"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.102",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.102.tgz",
+ "integrity": "sha512-eHhqaja8tE/FNpIiBrvBjFV/SSKpyWHLvxuR9dPTdo+3V9ppdLmFB7ZZQ98qNovcngPLYIz0oOBF9P0FfZef5Q==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/emittery": {
+ "version": "0.13.1",
+ "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz",
+ "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/emittery?sponsor=1"
+ }
+ },
+ "node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "license": "MIT"
+ },
+ "node_modules/error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/execa": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
+ "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cross-spawn": "^7.0.3",
+ "get-stream": "^6.0.0",
+ "human-signals": "^2.1.0",
+ "is-stream": "^2.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^4.0.1",
+ "onetime": "^5.1.2",
+ "signal-exit": "^3.0.3",
+ "strip-final-newline": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/execa?sponsor=1"
+ }
+ },
+ "node_modules/exit": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+ "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/expect": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz",
+ "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/expect-utils": "^29.7.0",
+ "jest-get-type": "^29.6.3",
+ "jest-matcher-utils": "^29.7.0",
+ "jest-message-util": "^29.7.0",
+ "jest-util": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/external-editor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
+ "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
+ "license": "MIT",
+ "dependencies": {
+ "chardet": "^0.7.0",
+ "iconv-lite": "^0.4.24",
+ "tmp": "^0.0.33"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fb-watchman": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz",
+ "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "bser": "2.1.1"
+ }
+ },
+ "node_modules/figures": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
+ "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
+ "license": "MIT",
+ "dependencies": {
+ "escape-string-regexp": "^1.0.5"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/filelist": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
+ "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "minimatch": "^5.0.1"
+ }
+ },
+ "node_modules/filelist/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/filelist/node_modules/minimatch": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "license": "MIT",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/get-package-type": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
+ "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/get-stream": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
+ "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "deprecated": "Glob versions prior to v9 are no longer supported",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/globals": {
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/html-escaper": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
+ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/human-signals": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
+ "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=10.17.0"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/import-local": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz",
+ "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "pkg-dir": "^4.2.0",
+ "resolve-cwd": "^3.0.0"
+ },
+ "bin": {
+ "import-local-fixture": "fixtures/cli.js"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "license": "ISC"
+ },
+ "node_modules/inquirer": {
+ "version": "8.2.6",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz",
+ "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-escapes": "^4.2.1",
+ "chalk": "^4.1.1",
+ "cli-cursor": "^3.1.0",
+ "cli-width": "^3.0.0",
+ "external-editor": "^3.0.3",
+ "figures": "^3.0.0",
+ "lodash": "^4.17.21",
+ "mute-stream": "0.0.8",
+ "ora": "^5.4.1",
+ "run-async": "^2.4.0",
+ "rxjs": "^7.5.5",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0",
+ "through": "^2.3.6",
+ "wrap-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/inquirer-autocomplete-prompt": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/inquirer-autocomplete-prompt/-/inquirer-autocomplete-prompt-2.0.1.tgz",
+ "integrity": "sha512-jUHrH0btO7j5r8DTQgANf2CBkTZChoVySD8zF/wp5fZCOLIuUbleXhf4ZY5jNBOc1owA3gdfWtfZuppfYBhcUg==",
+ "license": "ISC",
+ "dependencies": {
+ "ansi-escapes": "^4.3.2",
+ "figures": "^3.2.0",
+ "picocolors": "^1.0.0",
+ "run-async": "^2.4.1",
+ "rxjs": "^7.5.4"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "peerDependencies": {
+ "inquirer": "^8.0.0"
+ }
+ },
+ "node_modules/is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/is-core-module": {
+ "version": "2.16.1",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
+ "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-generator-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz",
+ "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/is-interactive": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
+ "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-unicode-supported": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/istanbul-lib-coverage": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz",
+ "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-instrument": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz",
+ "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@babel/core": "^7.12.3",
+ "@babel/parser": "^7.14.7",
+ "@istanbuljs/schema": "^0.1.2",
+ "istanbul-lib-coverage": "^3.2.0",
+ "semver": "^6.3.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-report": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
+ "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "istanbul-lib-coverage": "^3.0.0",
+ "make-dir": "^4.0.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/istanbul-lib-source-maps": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
+ "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "debug": "^4.1.1",
+ "istanbul-lib-coverage": "^3.0.0",
+ "source-map": "^0.6.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/istanbul-reports": {
+ "version": "3.1.7",
+ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz",
+ "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "html-escaper": "^2.0.0",
+ "istanbul-lib-report": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jake": {
+ "version": "10.9.2",
+ "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz",
+ "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "async": "^3.2.3",
+ "chalk": "^4.0.2",
+ "filelist": "^1.0.4",
+ "minimatch": "^3.1.2"
+ },
+ "bin": {
+ "jake": "bin/cli.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/jest": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz",
+ "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/core": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "import-local": "^3.0.2",
+ "jest-cli": "^29.7.0"
+ },
+ "bin": {
+ "jest": "bin/jest.js"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ },
+ "peerDependencies": {
+ "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
+ },
+ "peerDependenciesMeta": {
+ "node-notifier": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/jest-changed-files": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz",
+ "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "execa": "^5.0.0",
+ "jest-util": "^29.7.0",
+ "p-limit": "^3.1.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-circus": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz",
+ "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/environment": "^29.7.0",
+ "@jest/expect": "^29.7.0",
+ "@jest/test-result": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "chalk": "^4.0.0",
+ "co": "^4.6.0",
+ "dedent": "^1.0.0",
+ "is-generator-fn": "^2.0.0",
+ "jest-each": "^29.7.0",
+ "jest-matcher-utils": "^29.7.0",
+ "jest-message-util": "^29.7.0",
+ "jest-runtime": "^29.7.0",
+ "jest-snapshot": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "p-limit": "^3.1.0",
+ "pretty-format": "^29.7.0",
+ "pure-rand": "^6.0.0",
+ "slash": "^3.0.0",
+ "stack-utils": "^2.0.3"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-cli": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz",
+ "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/core": "^29.7.0",
+ "@jest/test-result": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "chalk": "^4.0.0",
+ "create-jest": "^29.7.0",
+ "exit": "^0.1.2",
+ "import-local": "^3.0.2",
+ "jest-config": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "jest-validate": "^29.7.0",
+ "yargs": "^17.3.1"
+ },
+ "bin": {
+ "jest": "bin/jest.js"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ },
+ "peerDependencies": {
+ "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
+ },
+ "peerDependenciesMeta": {
+ "node-notifier": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/jest-config": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz",
+ "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.11.6",
+ "@jest/test-sequencer": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "babel-jest": "^29.7.0",
+ "chalk": "^4.0.0",
+ "ci-info": "^3.2.0",
+ "deepmerge": "^4.2.2",
+ "glob": "^7.1.3",
+ "graceful-fs": "^4.2.9",
+ "jest-circus": "^29.7.0",
+ "jest-environment-node": "^29.7.0",
+ "jest-get-type": "^29.6.3",
+ "jest-regex-util": "^29.6.3",
+ "jest-resolve": "^29.7.0",
+ "jest-runner": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "jest-validate": "^29.7.0",
+ "micromatch": "^4.0.4",
+ "parse-json": "^5.2.0",
+ "pretty-format": "^29.7.0",
+ "slash": "^3.0.0",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ },
+ "peerDependencies": {
+ "@types/node": "*",
+ "ts-node": ">=9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "ts-node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/jest-diff": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz",
+ "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^4.0.0",
+ "diff-sequences": "^29.6.3",
+ "jest-get-type": "^29.6.3",
+ "pretty-format": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-docblock": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz",
+ "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "detect-newline": "^3.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-each": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz",
+ "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "chalk": "^4.0.0",
+ "jest-get-type": "^29.6.3",
+ "jest-util": "^29.7.0",
+ "pretty-format": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-environment-node": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz",
+ "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/environment": "^29.7.0",
+ "@jest/fake-timers": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "jest-mock": "^29.7.0",
+ "jest-util": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-get-type": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz",
+ "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-haste-map": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz",
+ "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "@types/graceful-fs": "^4.1.3",
+ "@types/node": "*",
+ "anymatch": "^3.0.3",
+ "fb-watchman": "^2.0.0",
+ "graceful-fs": "^4.2.9",
+ "jest-regex-util": "^29.6.3",
+ "jest-util": "^29.7.0",
+ "jest-worker": "^29.7.0",
+ "micromatch": "^4.0.4",
+ "walker": "^1.0.8"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "^2.3.2"
+ }
+ },
+ "node_modules/jest-leak-detector": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz",
+ "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "jest-get-type": "^29.6.3",
+ "pretty-format": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-matcher-utils": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz",
+ "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^4.0.0",
+ "jest-diff": "^29.7.0",
+ "jest-get-type": "^29.6.3",
+ "pretty-format": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-message-util": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz",
+ "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.12.13",
+ "@jest/types": "^29.6.3",
+ "@types/stack-utils": "^2.0.0",
+ "chalk": "^4.0.0",
+ "graceful-fs": "^4.2.9",
+ "micromatch": "^4.0.4",
+ "pretty-format": "^29.7.0",
+ "slash": "^3.0.0",
+ "stack-utils": "^2.0.3"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-mock": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz",
+ "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "jest-util": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-pnp-resolver": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz",
+ "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "peerDependencies": {
+ "jest-resolve": "*"
+ },
+ "peerDependenciesMeta": {
+ "jest-resolve": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/jest-regex-util": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz",
+ "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-resolve": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz",
+ "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^4.0.0",
+ "graceful-fs": "^4.2.9",
+ "jest-haste-map": "^29.7.0",
+ "jest-pnp-resolver": "^1.2.2",
+ "jest-util": "^29.7.0",
+ "jest-validate": "^29.7.0",
+ "resolve": "^1.20.0",
+ "resolve.exports": "^2.0.0",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-resolve-dependencies": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz",
+ "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "jest-regex-util": "^29.6.3",
+ "jest-snapshot": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-runner": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz",
+ "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/console": "^29.7.0",
+ "@jest/environment": "^29.7.0",
+ "@jest/test-result": "^29.7.0",
+ "@jest/transform": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "chalk": "^4.0.0",
+ "emittery": "^0.13.1",
+ "graceful-fs": "^4.2.9",
+ "jest-docblock": "^29.7.0",
+ "jest-environment-node": "^29.7.0",
+ "jest-haste-map": "^29.7.0",
+ "jest-leak-detector": "^29.7.0",
+ "jest-message-util": "^29.7.0",
+ "jest-resolve": "^29.7.0",
+ "jest-runtime": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "jest-watcher": "^29.7.0",
+ "jest-worker": "^29.7.0",
+ "p-limit": "^3.1.0",
+ "source-map-support": "0.5.13"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-runtime": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz",
+ "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/environment": "^29.7.0",
+ "@jest/fake-timers": "^29.7.0",
+ "@jest/globals": "^29.7.0",
+ "@jest/source-map": "^29.6.3",
+ "@jest/test-result": "^29.7.0",
+ "@jest/transform": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "chalk": "^4.0.0",
+ "cjs-module-lexer": "^1.0.0",
+ "collect-v8-coverage": "^1.0.0",
+ "glob": "^7.1.3",
+ "graceful-fs": "^4.2.9",
+ "jest-haste-map": "^29.7.0",
+ "jest-message-util": "^29.7.0",
+ "jest-mock": "^29.7.0",
+ "jest-regex-util": "^29.6.3",
+ "jest-resolve": "^29.7.0",
+ "jest-snapshot": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "slash": "^3.0.0",
+ "strip-bom": "^4.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-snapshot": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz",
+ "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.11.6",
+ "@babel/generator": "^7.7.2",
+ "@babel/plugin-syntax-jsx": "^7.7.2",
+ "@babel/plugin-syntax-typescript": "^7.7.2",
+ "@babel/types": "^7.3.3",
+ "@jest/expect-utils": "^29.7.0",
+ "@jest/transform": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "babel-preset-current-node-syntax": "^1.0.0",
+ "chalk": "^4.0.0",
+ "expect": "^29.7.0",
+ "graceful-fs": "^4.2.9",
+ "jest-diff": "^29.7.0",
+ "jest-get-type": "^29.6.3",
+ "jest-matcher-utils": "^29.7.0",
+ "jest-message-util": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "natural-compare": "^1.4.0",
+ "pretty-format": "^29.7.0",
+ "semver": "^7.5.3"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-snapshot/node_modules/semver": {
+ "version": "7.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
+ "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/jest-util": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz",
+ "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "chalk": "^4.0.0",
+ "ci-info": "^3.2.0",
+ "graceful-fs": "^4.2.9",
+ "picomatch": "^2.2.3"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-validate": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz",
+ "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "camelcase": "^6.2.0",
+ "chalk": "^4.0.0",
+ "jest-get-type": "^29.6.3",
+ "leven": "^3.1.0",
+ "pretty-format": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-validate/node_modules/camelcase": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/jest-watcher": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz",
+ "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jest/test-result": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "ansi-escapes": "^4.2.1",
+ "chalk": "^4.0.0",
+ "emittery": "^0.13.1",
+ "jest-util": "^29.7.0",
+ "string-length": "^4.0.1"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-worker": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz",
+ "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*",
+ "jest-util": "^29.7.0",
+ "merge-stream": "^2.0.0",
+ "supports-color": "^8.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-worker/node_modules/supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/js-yaml": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/kleur": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
+ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/leven": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
+ "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.debounce": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
+ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.memoize": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
+ "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/log-symbols": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+ "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^4.1.0",
+ "is-unicode-supported": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "node_modules/make-dir": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
+ "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "semver": "^7.5.3"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/make-dir/node_modules/semver": {
+ "version": "7.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
+ "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/make-error": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/makeerror": {
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz",
+ "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "tmpl": "1.0.5"
+ }
+ },
+ "node_modules/merge-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+ "license": "MIT",
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/mute-stream": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
+ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
+ "license": "ISC"
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/node-int64": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
+ "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.19",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
+ "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-run-path": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+ "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/onetime": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "license": "MIT",
+ "dependencies": {
+ "mimic-fn": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ora": {
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
+ "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==",
+ "license": "MIT",
+ "dependencies": {
+ "bl": "^4.1.0",
+ "chalk": "^4.1.0",
+ "cli-cursor": "^3.1.0",
+ "cli-spinners": "^2.5.0",
+ "is-interactive": "^1.0.0",
+ "is-unicode-supported": "^0.1.0",
+ "log-symbols": "^4.1.0",
+ "strip-ansi": "^6.0.0",
+ "wcwidth": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/os-tmpdir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+ "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/p-locate/node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parse-gitignore": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/parse-gitignore/-/parse-gitignore-2.0.0.tgz",
+ "integrity": "sha512-RmVuCHWsfu0QPNW+mraxh/xjQVw/lhUCUru8Zni3Ctq3AoMhpDTq0OVdKS6iesd6Kqb7viCV3isAL43dciOSog==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/parse-json": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+ "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-even-better-errors": "^2.3.0",
+ "lines-and-columns": "^1.1.6"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true,
"license": "MIT",
"engines": {
- "node": ">=8"
+ "node": ">=0.10.0"
}
},
- "node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
"license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
"engines": {
"node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
- "node_modules/arg": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
- "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true,
"license": "MIT"
},
- "node_modules/chalk": {
- "version": "5.4.1",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz",
- "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==",
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "license": "ISC"
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"license": "MIT",
"engines": {
- "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ "node": ">=8.6"
},
"funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
+ "url": "https://github.com/sponsors/jonschlinkert"
}
},
- "node_modules/chardet": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
- "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
- "license": "MIT"
+ "node_modules/pirates": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
+ "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6"
+ }
},
- "node_modules/cli-width": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz",
- "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==",
- "license": "ISC",
+ "node_modules/pkg-dir": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+ "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "find-up": "^4.0.0"
+ },
"engines": {
- "node": ">= 12"
+ "node": ">=8"
}
},
- "node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "node_modules/pretty-format": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
+ "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "color-name": "~1.1.4"
+ "@jest/schemas": "^29.6.3",
+ "ansi-styles": "^5.0.0",
+ "react-is": "^18.0.0"
},
"engines": {
- "node": ">=7.0.0"
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
- "node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "license": "MIT"
+ "node_modules/pretty-format/node_modules/ansi-styles": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
},
- "node_modules/commander": {
- "version": "13.1.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz",
- "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==",
+ "node_modules/prompts": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
+ "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
+ "dev": true,
"license": "MIT",
+ "dependencies": {
+ "kleur": "^3.0.3",
+ "sisteransi": "^1.0.5"
+ },
"engines": {
- "node": ">=18"
+ "node": ">= 6"
}
},
- "node_modules/create-require": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
- "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
+ "node_modules/pure-rand": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz",
+ "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==",
"dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/dubzzz"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fast-check"
+ }
+ ],
"license": "MIT"
},
- "node_modules/diff": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
- "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "node_modules/react-is": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
+ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
"dev": true,
- "license": "BSD-3-Clause",
+ "license": "MIT"
+ },
+ "node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "license": "MIT",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
"engines": {
- "node": ">=0.3.1"
+ "node": ">= 6"
}
},
- "node_modules/diff-so-fancy": {
- "version": "1.4.3",
- "resolved": "https://registry.npmjs.org/diff-so-fancy/-/diff-so-fancy-1.4.3.tgz",
- "integrity": "sha512-ZXNe6ZLdzCHt5cdMPwQOsuNcPI86VYArxloIqmedkTK3qlii59gHe5eR82CrNrc4aZ/A0V1b7askmDzBwftZKA==",
+ "node_modules/regenerate": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
+ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/regenerate-unicode-properties": {
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz",
+ "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==",
+ "dev": true,
"license": "MIT",
- "bin": {
- "diff-so-fancy": "third_party/build_fatpack/diff-so-fancy"
+ "dependencies": {
+ "regenerate": "^1.4.2"
+ },
+ "engines": {
+ "node": ">=4"
}
},
- "node_modules/emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "node_modules/regenerator-runtime": {
+ "version": "0.14.1",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
+ "dev": true,
"license": "MIT"
},
- "node_modules/external-editor": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
- "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
+ "node_modules/regenerator-transform": {
+ "version": "0.15.2",
+ "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz",
+ "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "chardet": "^0.7.0",
- "iconv-lite": "^0.4.24",
- "tmp": "^0.0.33"
+ "@babel/runtime": "^7.8.4"
+ }
+ },
+ "node_modules/regexpu-core": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz",
+ "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "regenerate": "^1.4.2",
+ "regenerate-unicode-properties": "^10.2.0",
+ "regjsgen": "^0.8.0",
+ "regjsparser": "^0.12.0",
+ "unicode-match-property-ecmascript": "^2.0.0",
+ "unicode-match-property-value-ecmascript": "^2.1.0"
},
"engines": {
"node": ">=4"
}
},
- "node_modules/iconv-lite": {
- "version": "0.4.24",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
- "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
- "license": "MIT",
+ "node_modules/regjsgen": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz",
+ "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/regjsparser": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz",
+ "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
- "safer-buffer": ">= 2.1.2 < 3"
+ "jsesc": "~3.0.2"
+ },
+ "bin": {
+ "regjsparser": "bin/parser"
+ }
+ },
+ "node_modules/regjsparser/node_modules/jsesc": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz",
+ "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
},
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "dev": true,
+ "license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
- "node_modules/inquirer": {
- "version": "12.4.2",
- "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-12.4.2.tgz",
- "integrity": "sha512-reyjHcwyK2LObXgTJH4T1Dpfhwu88LNPTZmg/KenmTsy3T8lN/kZT8Oo7UwwkB9q8+ss2qjjN7GV8oFAfyz9Xg==",
+ "node_modules/resolve": {
+ "version": "1.22.10",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
+ "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "@inquirer/core": "^10.1.7",
- "@inquirer/prompts": "^7.3.2",
- "@inquirer/type": "^3.0.4",
- "ansi-escapes": "^4.3.2",
- "mute-stream": "^2.0.0",
- "run-async": "^3.0.0",
- "rxjs": "^7.8.1"
+ "is-core-module": "^2.16.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
},
"engines": {
- "node": ">=18"
+ "node": ">= 0.4"
},
- "peerDependencies": {
- "@types/node": ">=18"
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/resolve-cwd": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
+ "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "resolve-from": "^5.0.0"
},
- "peerDependenciesMeta": {
- "@types/node": {
- "optional": true
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/resolve.exports": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz",
+ "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/restore-cursor": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
+ "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
+ "license": "MIT",
+ "dependencies": {
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/run-async": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
+ "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/rxjs": {
+ "version": "7.8.1",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
+ "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
}
+ ],
+ "license": "MIT"
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
}
},
- "node_modules/is-fullwidth-code-point": {
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "license": "ISC"
+ },
+ "node_modules/sisteransi": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
+ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
}
},
- "node_modules/make-error": {
- "version": "1.3.6",
- "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
- "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-support": {
+ "version": "0.5.13",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz",
+ "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "node_modules/sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
"dev": true,
- "license": "ISC"
- },
- "node_modules/mute-stream": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz",
- "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==",
- "license": "ISC",
- "engines": {
- "node": "^18.17.0 || >=20.5.0"
- }
+ "license": "BSD-3-Clause"
},
- "node_modules/os-tmpdir": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
- "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
+ "node_modules/stack-utils": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz",
+ "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==",
+ "dev": true,
"license": "MIT",
+ "dependencies": {
+ "escape-string-regexp": "^2.0.0"
+ },
"engines": {
- "node": ">=0.10.0"
+ "node": ">=10"
}
},
- "node_modules/run-async": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz",
- "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==",
+ "node_modules/stack-utils/node_modules/escape-string-regexp": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
+ "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
+ "dev": true,
"license": "MIT",
"engines": {
- "node": ">=0.12.0"
+ "node": ">=8"
}
},
- "node_modules/rxjs": {
- "version": "7.8.1",
- "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
- "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
- "license": "Apache-2.0",
+ "node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "license": "MIT",
"dependencies": {
- "tslib": "^2.1.0"
+ "safe-buffer": "~5.2.0"
}
},
- "node_modules/safer-buffer": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
- "license": "MIT"
- },
- "node_modules/signal-exit": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
- "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
- "license": "ISC",
- "engines": {
- "node": ">=14"
+ "node_modules/string-length": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
+ "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "char-regex": "^1.0.2",
+ "strip-ansi": "^6.0.0"
},
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
+ "engines": {
+ "node": ">=10"
}
},
"node_modules/string-width": {
@@ -746,6 +5483,85 @@
"node": ">=8"
}
},
+ "node_modules/strip-bom": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
+ "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-final-newline": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/test-exclude": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
+ "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@istanbuljs/schema": "^0.1.2",
+ "glob": "^7.1.4",
+ "minimatch": "^3.0.4"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
+ "license": "MIT"
+ },
"node_modules/tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@@ -758,6 +5574,87 @@
"node": ">=0.6.0"
}
},
+ "node_modules/tmpl": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
+ "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==",
+ "dev": true,
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "license": "MIT",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/ts-jest": {
+ "version": "29.2.5",
+ "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.5.tgz",
+ "integrity": "sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "bs-logger": "^0.2.6",
+ "ejs": "^3.1.10",
+ "fast-json-stable-stringify": "^2.1.0",
+ "jest-util": "^29.0.0",
+ "json5": "^2.2.3",
+ "lodash.memoize": "^4.1.2",
+ "make-error": "^1.3.6",
+ "semver": "^7.6.3",
+ "yargs-parser": "^21.1.1"
+ },
+ "bin": {
+ "ts-jest": "cli.js"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0"
+ },
+ "peerDependencies": {
+ "@babel/core": ">=7.0.0-beta.0 <8",
+ "@jest/transform": "^29.0.0",
+ "@jest/types": "^29.0.0",
+ "babel-jest": "^29.0.0",
+ "jest": "^29.0.0",
+ "typescript": ">=4.3 <6"
+ },
+ "peerDependenciesMeta": {
+ "@babel/core": {
+ "optional": true
+ },
+ "@jest/transform": {
+ "optional": true
+ },
+ "@jest/types": {
+ "optional": true
+ },
+ "babel-jest": {
+ "optional": true
+ },
+ "esbuild": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ts-jest/node_modules/semver": {
+ "version": "7.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
+ "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/ts-node": {
"version": "10.9.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
@@ -808,6 +5705,16 @@
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
+ "node_modules/type-detect": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/type-fest": {
"version": "0.21.3",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
@@ -838,7 +5745,88 @@
"version": "6.20.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==",
- "devOptional": true,
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/unicode-canonical-property-names-ecmascript": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz",
+ "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/unicode-match-property-ecmascript": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz",
+ "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "unicode-canonical-property-names-ecmascript": "^2.0.0",
+ "unicode-property-aliases-ecmascript": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/unicode-match-property-value-ecmascript": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz",
+ "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/unicode-property-aliases-ecmascript": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz",
+ "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz",
+ "integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT"
},
"node_modules/v8-compile-cache-lib": {
@@ -848,6 +5836,56 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/v8-to-istanbul": {
+ "version": "9.3.0",
+ "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz",
+ "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@jridgewell/trace-mapping": "^0.3.12",
+ "@types/istanbul-lib-coverage": "^2.0.1",
+ "convert-source-map": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10.12.0"
+ }
+ },
+ "node_modules/walker": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",
+ "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "makeerror": "1.0.12"
+ }
+ },
+ "node_modules/wcwidth": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
+ "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==",
+ "license": "MIT",
+ "dependencies": {
+ "defaults": "^1.0.3"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/wrap-ansi": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
@@ -862,6 +5900,73 @@
"node": ">=8"
}
},
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/write-file-atomic": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz",
+ "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "imurmurhash": "^0.1.4",
+ "signal-exit": "^3.0.7"
+ },
+ "engines": {
+ "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+ }
+ },
+ "node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/yargs": {
+ "version": "17.7.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+ "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/yn": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
@@ -872,13 +5977,14 @@
"node": ">=6"
}
},
- "node_modules/yoctocolors-cjs": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz",
- "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==",
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
"license": "MIT",
"engines": {
- "node": ">=18"
+ "node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
diff --git a/package.json b/package.json
index 0864661..a849e73 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "@el1fe/smart-commit",
- "version": "1.1.5",
- "type": "module",
+ "version": "1.2.0",
+ "type": "commonjs",
"description": "A highly customizable CLI tool for creating Git commits interactively.",
"repository": "https://github.com/el1fe/smart-commit.git",
"main": "dist/index.js",
@@ -14,10 +14,10 @@
},
"scripts": {
"build": "tsc",
- "test": "echo \"No tests specified\"",
"prepublishOnly": "npm run build",
"publish-npm": "npm publish --registry https://registry.npmjs.org --access public",
- "publish-gh": "npm publish --registry https://npm.pkg.github.com --access public"
+ "publish-gh": "npm publish --registry https://npm.pkg.github.com --access public",
+ "test": "jest"
},
"files": [
"dist"
@@ -31,15 +31,27 @@
"author": "Pavel Piuro ",
"license": "MIT",
"dependencies": {
- "chalk": "^5.4.1",
+ "chalk": "^4.1.2",
"commander": "^13.1.0",
"diff-so-fancy": "^1.4.3",
- "inquirer": "^12.4.2"
+ "inquirer": "^8.2.0",
+ "inquirer-autocomplete-prompt": "^2.0.0",
+ "micromatch": "^4.0.8",
+ "parse-gitignore": "^2.0.0"
},
"devDependencies": {
+ "@babel/core": "^7.26.9",
+ "@babel/preset-env": "^7.26.9",
"@types/commander": "^2.12.0",
- "@types/inquirer": "^9.0.7",
+ "@types/inquirer": "^8.2.0",
+ "@types/inquirer-autocomplete-prompt": "^2.0.0",
+ "@types/jest": "^29.5.14",
+ "@types/micromatch": "^4.0.9",
"@types/node": "^22.13.4",
+ "@types/parse-gitignore": "^1.0.2",
+ "babel-jest": "^29.7.0",
+ "jest": "^29.7.0",
+ "ts-jest": "^29.2.5",
"ts-node": "^10.9.2",
"typescript": "^5.7.3"
}
diff --git a/src/commands/amend.ts b/src/commands/amend.ts
new file mode 100644
index 0000000..2b31187
--- /dev/null
+++ b/src/commands/amend.ts
@@ -0,0 +1,70 @@
+import { Command } from 'commander';
+import inquirer from 'inquirer';
+import chalk from 'chalk';
+import { execSync } from 'child_process';
+import { loadConfig, ensureGitRepo, lintCommitMessage } from '../utils';
+
+export function registerAmendCommand(program: Command): void {
+ program
+ .command('amend')
+ .description('Amend the last commit interactively')
+ .action(async () => {
+ ensureGitRepo();
+ const config = loadConfig();
+ try {
+ const currentMsg = execSync('git log -1 --pretty=%B', { encoding: 'utf8' }).trim();
+ console.log(chalk.blue("Current commit message:\n") + currentMsg);
+ const { amendConfirm } = await inquirer.prompt([
+ {
+ type: 'confirm',
+ name: 'amendConfirm',
+ message: 'Do you want to amend the last commit?',
+ default: true,
+ }
+ ]);
+ if (!amendConfirm) {
+ console.log(chalk.yellow("Amend cancelled."));
+ return;
+ }
+
+ let newMessage = '';
+ let errors: string[] = [];
+ do {
+ const { newMessage: editedMessage } = await inquirer.prompt([
+ {
+ type: 'editor',
+ name: 'newMessage',
+ message: 'Edit the commit message:',
+ default: currentMsg,
+ }
+ ]);
+ newMessage = editedMessage;
+ if (config.enableLint) {
+ errors = lintCommitMessage(newMessage, config.lintRules);
+ if (errors.length > 0) {
+ console.log(chalk.red("Linting errors:"));
+ errors.forEach(err => console.log(chalk.red("- " + err)));
+ const { retry } = await inquirer.prompt([
+ {
+ type: 'confirm',
+ name: 'retry',
+ message: 'Lint errors found. Would you like to re-edit the commit message?',
+ default: true,
+ }
+ ]);
+ if (!retry) {
+ console.log(chalk.red("Amend cancelled due to lint errors."));
+ process.exit(1);
+ }
+ }
+ }
+ } while (errors.length > 0);
+
+ execSync(`git commit --amend -m "${newMessage.replace(/"/g, '\\"')}"`, { stdio: 'inherit' });
+ console.log(chalk.green("Commit amended successfully!"));
+ } catch (err: any) {
+ console.error(chalk.red("Error during amend:"), err.message);
+ process.exit(1);
+ }
+ });
+}
\ No newline at end of file
diff --git a/src/commands/branch.ts b/src/commands/branch.ts
new file mode 100644
index 0000000..c3e9648
--- /dev/null
+++ b/src/commands/branch.ts
@@ -0,0 +1,256 @@
+import { Command } from 'commander';
+import inquirer from 'inquirer';
+import chalk from 'chalk';
+import { execSync } from 'child_process';
+import { loadConfig, ensureGitRepo } from '../utils';
+import { AutocompleteQuestion } from '../types';
+
+interface ExtendedPlaceholderConfig extends Record {
+ separator?: string;
+ collapseSeparator?: boolean;
+ maxLength?: number;
+ lowercase?: boolean;
+}
+
+/**
+ * Sanitizes a string for a branch name:
+ * - Replaces spaces with separator (default '-')
+ * - Removes "extra" characters (except letters, numbers, _, and the separator itself)
+ * - If lowercase !== false, converts to lowerCase (default: true)
+ * - If collapseSeparator (default true), collapses repeated separators
+ * - If maxLength is set, truncates
+ */
+export function sanitizeForBranch(input: string, options?: ExtendedPlaceholderConfig): string {
+ const separator = options?.separator ?? '-';
+ const collapseSeparator = options?.collapseSeparator ?? true;
+ const maxLength = options?.maxLength;
+
+ let result = input.replace(/\s/g, separator);
+
+ const invalidChars = new RegExp(`[^a-zA-Z0-9_${separator}]`, 'g');
+ result = result.replace(invalidChars, '');
+
+ if (options?.lowercase !== false) {
+ result = result.toLowerCase();
+ }
+
+ if (collapseSeparator) {
+ const reSep = new RegExp(`${separator}{2,}`, 'g');
+ result = result.replace(reSep, separator);
+ }
+
+ if (maxLength && result.length > maxLength) {
+ result = result.substring(0, maxLength);
+ }
+
+ return result;
+}
+
+export function registerBranchCommand(program: Command): void {
+ program
+ .command('branch')
+ .alias('b')
+ .description('Create a new branch from a base branch (or current HEAD) with a naming template and autocomplete search.')
+ .action(async () => {
+ ensureGitRepo();
+ const config = loadConfig();
+
+ const template = config.branch?.template || "{type}/{ticketId}-{shortDesc}";
+ const branchTypes = config.branch?.types || [];
+
+ let localBranches: string[] = [];
+ try {
+ const rawBranches = execSync(
+ 'git branch --sort=-committerdate --format="%(refname:short)"',
+ { encoding: 'utf8' }
+ );
+ localBranches = rawBranches
+ .split('\n')
+ .map(b => b.trim())
+ .filter(Boolean);
+ } catch (err: any) {
+ console.error(chalk.red("Error getting local branches:"), err.message);
+ }
+
+ const baseBranchQuestion: AutocompleteQuestion = {
+ type: 'autocomplete',
+ name: 'baseBranchChoice',
+ message: 'Select a base branch (or type to search). Choose "Manual input..." to enter something else.',
+ source: async (answersSoFar, input) => {
+ if (!input) {
+ let suggestions = localBranches.slice(0, 4);
+ const mainBranch = localBranches.find(branch =>
+ branch.toLowerCase() === 'main' || branch.toLowerCase() === 'master'
+ );
+ if (mainBranch && !suggestions.includes(mainBranch)) {
+ suggestions.push(mainBranch);
+ }
+ suggestions.push('Manual input...');
+ return suggestions;
+ }
+
+ const query = input.toLowerCase();
+ let suggestions = localBranches.filter(branch =>
+ branch.toLowerCase().includes(query)
+ );
+ if (!suggestions.includes('Manual input...')) {
+ suggestions.push('Manual input...');
+ }
+ return suggestions;
+ }
+ };
+
+ const { baseBranchChoice } = await inquirer.prompt([baseBranchQuestion]);
+ let finalBaseBranch = baseBranchChoice;
+ if (baseBranchChoice === 'Manual input...') {
+ const { manualBranch } = await inquirer.prompt([
+ {
+ type: 'input',
+ name: 'manualBranch',
+ message: 'Enter base branch name (any value):',
+ }
+ ]);
+ finalBaseBranch = manualBranch.trim();
+ }
+
+ const placeholderRegex = /{(\w+)}/g;
+ const placeholders: string[] = [];
+ let match;
+ while ((match = placeholderRegex.exec(template)) !== null) {
+ if (!placeholders.includes(match[1])) {
+ placeholders.push(match[1]);
+ }
+ }
+
+ const answers: Record = {};
+ for (const ph of placeholders) {
+ let question;
+ if (ph === 'type') {
+ if (branchTypes.length > 0) {
+ const choices = branchTypes.map(bt => ({
+ name: `${bt.value} (${bt.description})`,
+ value: bt.value
+ }));
+ choices.push({
+ name: "Custom input...",
+ value: "CUSTOM_INPUT"
+ });
+ question = {
+ type: 'list',
+ name: ph,
+ message: 'Select branch type:',
+ choices
+ };
+ } else {
+ question = {
+ type: 'input',
+ name: ph,
+ message: 'Enter branch type (no branch types defined in config):',
+ default: ''
+ };
+ }
+ } else if (ph === 'shortDesc') {
+ question = {
+ type: 'input',
+ name: ph,
+ message: 'Short description for branch name:',
+ validate: (input: string) => input ? true : 'Description cannot be empty'
+ };
+ } else if (ph === 'ticketId') {
+ question = {
+ type: 'input',
+ name: ph,
+ message: 'Enter ticket ID (optional):',
+ default: ''
+ };
+ } else {
+ question = {
+ type: 'input',
+ name: ph,
+ message: `Enter ${ph} (optional):`,
+ default: ''
+ };
+ }
+
+ const singleAnswer = await inquirer.prompt([question]);
+ answers[ph] = singleAnswer[ph] || '';
+
+ if (ph === 'type' && answers.type === 'CUSTOM_INPUT') {
+ const { customType } = await inquirer.prompt([
+ {
+ type: 'input',
+ name: 'customType',
+ message: 'Enter custom branch type:',
+ }
+ ]);
+ answers.type = customType.trim();
+ }
+ }
+
+ for (const ph of placeholders) {
+ if (answers[ph]) {
+ const opts: ExtendedPlaceholderConfig = config.branch?.placeholders?.[ph] || {};
+ answers[ph] = sanitizeForBranch(answers[ph], opts);
+ }
+ }
+
+ let finalBranchName = template;
+ for (const ph of placeholders) {
+ const val = answers[ph] || '';
+ if (!val) {
+ finalBranchName = finalBranchName
+ .replace(`{${ph}}/`, '')
+ .replace(`{${ph}}-`, '')
+ .replace(`{${ph}}`, '');
+ } else {
+ finalBranchName = finalBranchName.replace(`{${ph}}`, val);
+ }
+ }
+
+ finalBranchName = finalBranchName
+ .replace(/\/\/+/g, '/')
+ .replace(/--+/g, '-')
+ .replace(/^-+|-+$/g, '')
+ .replace(/\/+$/, '');
+
+ if (!finalBranchName) {
+ const randomPart = Math.floor(Math.random() * 10000);
+ finalBranchName = `new-branch-${randomPart}`;
+ }
+
+ try {
+ console.log(chalk.blue(`Fetching all refs...`));
+ execSync(`git fetch --all`, { stdio: 'inherit' });
+
+ console.log(chalk.blue(`Creating new branch '${finalBranchName}' from '${finalBaseBranch || "HEAD"}'...`));
+ if (finalBaseBranch) {
+ execSync(`git checkout -b "${finalBranchName}" "${finalBaseBranch}"`, { stdio: 'inherit' });
+ } else {
+ execSync(`git checkout -b "${finalBranchName}"`, { stdio: 'inherit' });
+ }
+ console.log(chalk.green(`Branch created: ${finalBranchName}`));
+ } catch (err: any) {
+ console.error(chalk.red("Error creating branch:"), err.message);
+ process.exit(1);
+ }
+
+ const { stayOnBranch } = await inquirer.prompt([
+ {
+ type: 'confirm',
+ name: 'stayOnBranch',
+ message: `Stay on '${finalBranchName}'? (If 'No', you'll return to '${finalBaseBranch || "HEAD"}')`,
+ default: true
+ }
+ ]);
+ if (!stayOnBranch && finalBaseBranch) {
+ try {
+ execSync(`git checkout "${finalBaseBranch}"`, { stdio: 'inherit' });
+ console.log(chalk.green(`Switched back to '${finalBaseBranch}'.`));
+ } catch (err: any) {
+ console.error(chalk.red("Error switching branch back:"), err.message);
+ }
+ } else if (!stayOnBranch) {
+ console.log(chalk.yellow("No base branch specified, staying on new branch anyway."));
+ }
+ });
+}
\ No newline at end of file
diff --git a/src/commands/commit.ts b/src/commands/commit.ts
new file mode 100644
index 0000000..dd30b81
--- /dev/null
+++ b/src/commands/commit.ts
@@ -0,0 +1,278 @@
+import { Command } from 'commander';
+import inquirer, { ConfirmQuestion, EditorQuestion, InputQuestion, ListQuestion, CheckboxQuestion as InquirerCheckboxQuestion } from 'inquirer';
+import chalk from 'chalk';
+import { execSync } from 'child_process';
+import {
+ loadConfig,
+ getUnstagedFiles,
+ loadGitignorePatterns,
+ stageSelectedFiles,
+ computeAutoSummary,
+ suggestCommitType,
+ previewCommitMessage,
+ ensureGitRepo,
+ showDiffPreview
+} from '../utils';
+import micromatch from 'micromatch';
+
+export function registerCommitCommand(program: Command): void {
+ program
+ .command('commit')
+ .alias('c')
+ .description('Create a commit with interactive prompts')
+ .option('--push', 'Push commit to remote after creation', false)
+ .option('--sign', 'Sign commit with GPG', false)
+ .option('--lint', 'Enable commit message linting')
+ .action(async (cmdObj: { lint?: boolean; sign: any; push: any; }) => {
+ ensureGitRepo();
+ const config = loadConfig();
+ const suggestedType = suggestCommitType();
+
+ const commitTypeChoices = config.commitTypes.map(ct => ({
+ name: config.useEmoji
+ ? `${ct.emoji} ${ct.value} (${ct.description})`
+ : `${ct.value} (${ct.description})`,
+ value: ct.value,
+ }));
+
+ let filesToStage: string[] = [];
+
+ if (!config.autoAdd) {
+ const unstagedFiles = getUnstagedFiles();
+ const ignorePatterns = loadGitignorePatterns();
+ const filtered = unstagedFiles.filter(file => !micromatch.isMatch(file, ignorePatterns));
+
+ if (filtered.length > 0) {
+ const checkboxQuestion: InquirerCheckboxQuestion = {
+ type: 'checkbox',
+ name: 'files',
+ message: 'Select files to stage:',
+ choices: filtered,
+ };
+ const { files } = await inquirer.prompt([checkboxQuestion]);
+ filesToStage = files;
+ stageSelectedFiles(filesToStage);
+ } else {
+ console.log(chalk.yellow("No unstaged files to add (that aren’t ignored)."));
+ }
+ } else {
+ const unstagedFiles = getUnstagedFiles();
+ const ignorePatterns = loadGitignorePatterns();
+ const filtered = unstagedFiles.filter(file => !micromatch.isMatch(file, ignorePatterns));
+
+ if (filtered.length > 0) {
+ console.log(chalk.blue("Auto-adding non-ignored files:"));
+ filtered.forEach(f => console.log(" " + f));
+ stageSelectedFiles(filtered);
+ } else {
+ console.log(chalk.yellow("No files to auto-add (all ignored or none changed)."));
+ }
+ }
+
+ const actuallyStaged = execSync('git diff --cached --name-only', { encoding: 'utf8' })
+ .split('\n')
+ .filter(f => f.trim() !== '');
+
+ if (actuallyStaged.length === 0) {
+ console.log(chalk.yellow("No changes staged. Aborting commit."));
+ return;
+ }
+
+ const autoSummary = computeAutoSummary();
+ const questions: (ListQuestion | InputQuestion | ConfirmQuestion | EditorQuestion)[] = [];
+
+ questions.push({
+ type: 'list',
+ name: 'type',
+ message: 'Select commit type:',
+ choices: commitTypeChoices,
+ default: suggestedType || undefined,
+ } as ListQuestion);
+
+ if (config.steps.scope) {
+ questions.push({
+ type: 'input',
+ name: 'scope',
+ message: 'Enter scope (optional):',
+ } as InputQuestion);
+ }
+
+ questions.push({
+ type: 'input',
+ name: 'summary',
+ message: 'Enter commit summary:',
+ default: autoSummary,
+ validate: (input: string) => input ? true : 'Summary cannot be empty',
+ } as InputQuestion);
+
+ if (config.steps.body) {
+ questions.push({
+ type: 'editor',
+ name: 'body',
+ message: 'Enter commit body (your default editor will open, leave empty to skip):',
+ } as EditorQuestion);
+ }
+ if (config.steps.footer) {
+ questions.push({
+ type: 'input',
+ name: 'footer',
+ message: 'Enter commit footer (optional):',
+ } as InputQuestion);
+ }
+
+ let defaultTicket = "";
+ if (config.steps.ticket && config.ticketRegex) {
+ try {
+ const branchName = execSync("git rev-parse --abbrev-ref HEAD", { encoding: "utf8" }).trim();
+ const re = new RegExp(config.ticketRegex);
+ const match = branchName.match(re);
+ if (match && match[0]) {
+ defaultTicket = match[0];
+ console.log(chalk.cyan(`Extracted ticket from branch: ${defaultTicket}`));
+ }
+ } catch {
+ defaultTicket = "";
+ }
+ }
+ if (config.steps.ticket) {
+ questions.push({
+ type: 'input',
+ name: 'ticket',
+ message: 'Enter ticket ID (optional):',
+ default: defaultTicket,
+ } as InputQuestion);
+ }
+ if (config.steps.runCI) {
+ questions.push({
+ type: 'confirm',
+ name: 'runCI',
+ message: 'Run CI tests before commit?',
+ default: false,
+ } as ConfirmQuestion);
+ }
+
+ questions.push({
+ type: 'confirm',
+ name: 'pushCommit',
+ message: 'Push commit after creation?',
+ default: cmdObj.push || false,
+ } as ConfirmQuestion);
+
+ const answers = await inquirer.prompt(questions) as {
+ type: string; scope: string; summary: string; body: string;
+ footer: string; ticket: string; runCI: boolean; pushCommit: boolean;
+ };
+
+ if (!answers.scope) answers.scope = "";
+ if (!answers.body) answers.body = "";
+ if (!answers.footer) answers.footer = "";
+ if (!answers.ticket) answers.ticket = "";
+ if (!answers.runCI) answers.runCI = false;
+ if (answers.runCI) {
+ try {
+ console.log(chalk.blue('Running CI tests...'));
+ execSync(config.ciCommand, { stdio: 'inherit' });
+ console.log(chalk.green('CI tests passed!'));
+ } catch (err: any) {
+ console.error(chalk.red('CI tests failed:'), err.message);
+ process.exit(1);
+ }
+ }
+
+ const stagedFilesStill = execSync('git diff --cached --name-only', { encoding: 'utf8' })
+ .split('\n')
+ .filter(f => f.trim() !== '');
+ if (stagedFilesStill.length === 0) {
+ console.log(chalk.yellow("No changes staged (anymore). Aborting commit."));
+ return;
+ }
+
+ const { diffPreview } = await inquirer.prompt([
+ {
+ type: 'confirm',
+ name: 'diffPreview',
+ message: 'Would you like to view the staged diff preview?',
+ default: false,
+ }
+ ]);
+ if (diffPreview) {
+ ensureGitRepo();
+ showDiffPreview();
+ const { diffConfirm } = await inquirer.prompt([
+ {
+ type: 'confirm',
+ name: 'diffConfirm',
+ message: 'Does the staged diff look OK?',
+ default: true,
+ }
+ ]);
+ if (!diffConfirm) {
+ console.log(chalk.yellow("Commit cancelled due to diff review."));
+ return;
+ }
+ }
+
+ const scopeFormatted = answers.scope.trim() !== '' ? `(${answers.scope.trim()})` : '';
+ const ticketSeparator = answers.ticket.trim() !== '' ? ": " : "";
+
+ let commitMsg = config.templates.defaultTemplate
+ .replace('{ticket}', answers.ticket.trim())
+ .replace('{ticketSeparator}', ticketSeparator)
+ .replace('{type}', answers.type)
+ .replace('{scope}', scopeFormatted)
+ .replace('{summary}', answers.summary.trim())
+ .replace('{body}', answers.body.trim())
+ .replace('{footer}', answers.footer.trim());
+
+ const lintEnabled = cmdObj.lint !== undefined ? cmdObj.lint : config.enableLint;
+
+ if (lintEnabled) {
+ commitMsg = await previewCommitMessage(commitMsg, config.lintRules);
+ } else {
+ const { previewChoice } = await inquirer.prompt([
+ {
+ type: 'confirm',
+ name: 'previewChoice',
+ message: 'Preview commit message?',
+ default: true,
+ }
+ ]);
+ if (previewChoice) {
+ console.log(chalk.blue("\nPreview commit message:\n"));
+ console.log(commitMsg);
+ }
+ const { finalConfirm } = await inquirer.prompt([
+ {
+ type: 'confirm',
+ name: 'finalConfirm',
+ message: 'Proceed with commit?',
+ default: true,
+ }
+ ]);
+ if (!finalConfirm) {
+ console.log(chalk.yellow('Commit cancelled after preview.'));
+ return;
+ }
+ }
+
+ try {
+ const commitCommand = cmdObj.sign
+ ? `git commit -S -m "${commitMsg.replace(/"/g, '\\"')}"`
+ : `git commit -m "${commitMsg.replace(/"/g, '\\"')}"`;
+ execSync(commitCommand, { stdio: 'inherit' });
+ console.log(chalk.green('Commit successful!'));
+ } catch (err: any) {
+ console.error(chalk.red('Error during commit:'), err.message);
+ process.exit(1);
+ }
+
+ if (answers.pushCommit) {
+ try {
+ execSync('git push', { stdio: 'inherit' });
+ console.log(chalk.green('Pushed successfully!'));
+ } catch (err: any) {
+ console.error(chalk.red('Push failed:'), err.message);
+ }
+ }
+ });
+}
\ No newline at end of file
diff --git a/src/commands/config.ts b/src/commands/config.ts
new file mode 100644
index 0000000..ccac802
--- /dev/null
+++ b/src/commands/config.ts
@@ -0,0 +1,193 @@
+import { Command } from 'commander';
+import chalk from 'chalk';
+import { saveConfig, loadConfig, defaultConfig } from '../utils';
+
+export function registerConfigCommand(program: Command): void {
+ program
+ .command('config')
+ .alias('cfg')
+ .description('Configure or view Smart Commit settings')
+ .option('--reset', 'Reset configuration to default settings')
+ .option('-a, --auto-add ', 'Set auto-add for commits (true/false)', (value: string) => value === 'true')
+ .option('-e, --use-emoji ', 'Use emojis in commit types (true/false)', (value: string) => value === 'true')
+ .option('-c, --ci-command ', 'Set CI command (e.g., "npm test")')
+ .option('-t, --template ', 'Set default commit message template')
+ .option('--enable-scope ', 'Enable scope prompt (true/false)', (value: string) => value === 'true')
+ .option('--enable-body ', 'Enable body prompt (true/false)', (value: string) => value === 'true')
+ .option('--enable-footer ', 'Enable footer prompt (true/false)', (value: string) => value === 'true')
+ .option('--enable-ticket ', 'Enable ticket prompt (true/false)', (value: string) => value === 'true')
+ .option('--enable-run-ci ', 'Enable CI prompt (true/false)', (value: string) => value === 'true')
+ .option('--ticket-regex ', 'Set regex for ticket extraction from branch name')
+ .option('--enable-lint ', 'Enable commit message linting (true/false)', (value: string) => value === 'true')
+ // .option('--enable-hooks ', 'Enable Git Hooks installation (true/false)', (value: string) => value === 'true')
+ .option('--branch-template ', 'Set branch naming template')
+ .option('--branch-type ', 'Set branch types (JSON string)')
+ .option('--branch-placeholder ', 'Set branch placeholder config (JSON string)')
+ .action((options) => {
+ if (options.reset) {
+ saveConfig(defaultConfig);
+ console.log(chalk.green("Configuration has been reset to default settings."));
+ return;
+ }
+
+ const config = loadConfig();
+ let changed = false;
+
+ if (options.autoAdd !== undefined) {
+ config.autoAdd = options.autoAdd;
+ changed = true;
+ }
+ if (options.useEmoji !== undefined) {
+ config.useEmoji = options.useEmoji;
+ changed = true;
+ }
+ if (options.ciCommand) {
+ config.ciCommand = options.ciCommand;
+ changed = true;
+ }
+ if (options.template) {
+ config.templates.defaultTemplate = options.template;
+ changed = true;
+ }
+ if (options.enableScope !== undefined) {
+ config.steps.scope = options.enableScope;
+ changed = true;
+ }
+ if (options.enableBody !== undefined) {
+ config.steps.body = options.enableBody;
+ changed = true;
+ }
+ if (options.enableFooter !== undefined) {
+ config.steps.footer = options.enableFooter;
+ changed = true;
+ }
+ if (options.enableTicket !== undefined) {
+ config.steps.ticket = options.enableTicket;
+ changed = true;
+ }
+ if (options.enableRunCi !== undefined) {
+ config.steps.runCI = options.enableRunCi;
+ changed = true;
+ }
+ if (options.ticketRegex) {
+ config.ticketRegex = options.ticketRegex;
+ changed = true;
+ }
+ if (options.enableLint !== undefined) {
+ config.enableLint = options.enableLint;
+ changed = true;
+ }
+ // if (options.enableHooks !== undefined) {
+ // config.enableHooks = options.enableHooks;
+ // changed = true;
+ // }
+
+ if (options.branchTemplate) {
+ if (!config.branch) {
+ config.branch = {
+ template: "{type}/{ticketId}-{shortDesc}",
+ types: [],
+ placeholders: {}
+ };
+ }
+ config.branch.template = options.branchTemplate;
+ changed = true;
+ }
+
+ if (options.branchType) {
+ try {
+ const parsed = JSON.parse(options.branchType);
+ if (Array.isArray(parsed)) {
+ if (!config.branch) {
+ config.branch = { template: "", types: parsed, placeholders: {} };
+ } else {
+ config.branch.types = parsed;
+ }
+ changed = true;
+ } else {
+ console.error("branch-type JSON must be an array of objects!");
+ }
+ } catch (err) {
+ console.error("Invalid JSON for --branch-type:", err);
+ }
+ }
+
+ if (options.branchPlaceholder) {
+ try {
+ const parsed = JSON.parse(options.branchPlaceholder);
+ if (typeof parsed === 'object' && !Array.isArray(parsed)) {
+ if (!config.branch) {
+ config.branch = { template: "", types: [], placeholders: parsed };
+ } else {
+ config.branch.placeholders = parsed;
+ }
+ changed = true;
+ } else {
+ console.error("branch-placeholder JSON must be an object!");
+ }
+ } catch (err) {
+ console.error("Invalid JSON for --branch-placeholder:", err);
+ }
+ }
+
+ if (changed) {
+ saveConfig(config);
+ } else {
+ console.log(chalk.blue("Current configuration:"));
+
+ console.table([
+ { Key: 'autoAdd', Value: config.autoAdd },
+ { Key: 'useEmoji', Value: config.useEmoji },
+ { Key: 'ciCommand', Value: config.ciCommand },
+ { Key: 'ticketRegex', Value: config.ticketRegex },
+ { Key: 'enableLint', Value: config.enableLint },
+ // { Key: 'enableHooks', Value: config.enableHooks },
+ ]);
+
+ console.log(chalk.blue("\nSteps (prompts enabled):"));
+ console.table([
+ { Step: 'scope', Enabled: config.steps.scope },
+ { Step: 'body', Enabled: config.steps.body },
+ { Step: 'footer', Enabled: config.steps.footer },
+ { Step: 'ticket', Enabled: config.steps.ticket },
+ { Step: 'runCI', Enabled: config.steps.runCI }
+ ]);
+
+ console.log(chalk.blue("\nLint Rules:"));
+ console.table([
+ {
+ summaryMaxLength: config.lintRules.summaryMaxLength,
+ typeCase: config.lintRules.typeCase,
+ requiredTicket: config.lintRules.requiredTicket
+ }
+ ]);
+
+ console.log(chalk.blue("\nCommit Types:"));
+ console.table(config.commitTypes);
+
+ console.log(chalk.blue("\nDefault Commit Template:\n"), config.templates.defaultTemplate);
+
+ if (config.branch) {
+ console.log(chalk.blue("\nBranch Configuration Template:\n"), config.branch.template);
+
+ if (config.branch.types && config.branch.types.length > 0) {
+ console.log(chalk.blue("\nBranch Types:"));
+ console.table(config.branch.types);
+ }
+
+ if (config.branch.placeholders) {
+ console.log(chalk.blue("\nBranch Placeholders:"));
+
+ const placeholdersData = Object.entries(config.branch.placeholders).map(([phName, opts]) => ({
+ placeholder: phName,
+ lowercase: opts.lowercase ?? true,
+ separator: opts.separator ?? '-',
+ collapseSeparator: opts.collapseSeparator ?? true,
+ maxLength: opts.maxLength ?? 'N/A'
+ }));
+ console.table(placeholdersData);
+ }
+ }
+ }
+ });
+}
\ No newline at end of file
diff --git a/src/commands/history.ts b/src/commands/history.ts
new file mode 100644
index 0000000..860f0d8
--- /dev/null
+++ b/src/commands/history.ts
@@ -0,0 +1,127 @@
+import { Command } from 'commander';
+import inquirer from 'inquirer';
+import chalk from 'chalk';
+import { execSync } from 'child_process';
+import { ensureGitRepo } from '../utils';
+
+export function registerHistoryCommand(program: Command): void {
+ program
+ .command('history')
+ .description('Show commit history with search options')
+ .action(async () => {
+ ensureGitRepo();
+ const { filterType, viewMode } = await inquirer.prompt([
+ {
+ type: 'list',
+ name: 'filterType',
+ message: 'Select search type:',
+ choices: [
+ { name: 'Search by keyword in commit message', value: 'keyword' },
+ { name: 'By author', value: 'author' },
+ { name: 'By date range', value: 'date' }
+ ],
+ },
+ {
+ type: 'list',
+ name: 'viewMode',
+ message: 'Select view mode:',
+ choices: [
+ { name: 'Only current branch commits', value: 'current' },
+ { name: 'Include merged commits', value: 'merged' }
+ ],
+ }
+ ]);
+
+ let baseCommand = 'git log --pretty=oneline';
+
+ if (viewMode === 'current') {
+ const currentBranch = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8' }).trim();
+ baseCommand = `git log --pretty=oneline ${currentBranch} --not $(git for-each-ref --format='%(refname)' refs/heads/ | grep -v "refs/heads/${currentBranch}")`;
+ }
+
+ if (filterType === 'keyword') {
+ const { keyword } = await inquirer.prompt([
+ {
+ type: 'input',
+ name: 'keyword',
+ message: 'Enter keyword to search in commit messages:',
+ }
+ ]);
+ baseCommand += ` --grep="${keyword}"`;
+ } else if (filterType === 'author') {
+ const { author } = await inquirer.prompt([
+ {
+ type: 'input',
+ name: 'author',
+ message: 'Enter author name or email:',
+ }
+ ]);
+ baseCommand += ` --author="${author}"`;
+ } else if (filterType === 'date') {
+ const { since, until } = await inquirer.prompt([
+ {
+ type: 'input',
+ name: 'since',
+ message: 'Enter start date (YYYY-MM-DD):',
+ validate: (input: string) => /^\d{4}-\d{2}-\d{2}$/.test(input)
+ ? true
+ : 'Please enter date in YYYY-MM-DD format',
+ },
+ {
+ type: 'input',
+ name: 'until',
+ message: 'Enter end date (YYYY-MM-DD):',
+ validate: (input: string) => /^\d{4}-\d{2}-\d{2}$/.test(input)
+ ? true
+ : 'Please enter date in YYYY-MM-DD format',
+ }
+ ]);
+ baseCommand += ` --since="${since}" --until="${until}"`;
+ }
+
+ const { limit } = await inquirer.prompt([
+ {
+ type: 'input',
+ name: 'limit',
+ message: 'Enter number of commits per page (default 20):',
+ default: '20',
+ validate: (input: string) =>
+ /^\d+$/.test(input) && parseInt(input, 10) > 0
+ ? true
+ : 'Please enter a positive integer',
+ }
+ ]);
+ const perPage = parseInt(limit, 10);
+
+ let skip = 0;
+ while (true) {
+ const paginatedCommand = `${baseCommand} --max-count=${perPage} --skip=${skip}`;
+ let historyOutput = '';
+ try {
+ historyOutput = execSync(paginatedCommand, { encoding: 'utf8' });
+ } catch (err: any) {
+ console.error(chalk.red("Error retrieving history:"), err.message);
+ process.exit(1);
+ }
+ if (!historyOutput.trim()) {
+ console.log(chalk.yellow("No more commits to display."));
+ break;
+ }
+ console.log(chalk.blue("\nCommit History:\n"));
+ console.log(chalk.green(historyOutput));
+
+ const { showMore } = await inquirer.prompt([
+ {
+ type: 'confirm',
+ name: 'showMore',
+ message: 'Show next page?',
+ default: true,
+ }
+ ]);
+ if (!showMore) {
+ break;
+ }
+ skip += perPage;
+ }
+ });
+}
\ No newline at end of file
diff --git a/src/commands/rebaseHelper.ts b/src/commands/rebaseHelper.ts
new file mode 100644
index 0000000..139a907
--- /dev/null
+++ b/src/commands/rebaseHelper.ts
@@ -0,0 +1,75 @@
+import { Command } from 'commander';
+import inquirer from 'inquirer';
+import chalk from 'chalk';
+import { execSync } from 'child_process';
+import { ensureGitRepo } from '../utils';
+
+export function registerRebaseHelperCommand(program: Command): void {
+ program
+ .command('rebase-helper')
+ .alias('rebase')
+ .description('Launch interactive rebase helper with explanations')
+ .action(async () => {
+ ensureGitRepo();
+ const { commitCount } = await inquirer.prompt([
+ {
+ type: 'input',
+ name: 'commitCount',
+ message: 'Enter the number of commits to rebase (e.g., 3):',
+ validate: (input: string) => {
+ const num = parseInt(input, 10);
+ return (!isNaN(num) && num > 0) || 'Please enter a valid positive number';
+ }
+ }
+ ]);
+
+ console.log(chalk.blue(`Launching interactive rebase for the last ${commitCount} commits.\n`));
+
+ console.log(chalk.yellow("### Interactive Rebase Guide ###"));
+ console.log(chalk.yellow("Git interactive rebase allows you to modify, reorder, and squash commits."));
+ console.log(chalk.yellow("When the editor opens, you will see a list of commits. Each line starts with a command and a commit hash."));
+ console.log(chalk.yellow("You can change the command to modify how the commit is handled.\n"));
+
+ console.log(chalk.green("Basic Commands:"));
+ console.log(chalk.cyan(" pick ") + "Use the commit as-is.");
+ console.log(chalk.cyan(" reword ") + "Use the commit, but edit the commit message.");
+ console.log(chalk.cyan(" edit ") + "Stop at the commit for amending.");
+ console.log(chalk.cyan(" squash ") + "Merge the commit into the previous commit.");
+ console.log(chalk.cyan(" fixup ") + "Like squash, but discard this commit’s message.");
+ console.log(chalk.cyan(" drop ") + "Remove the commit.");
+ console.log(chalk.cyan(" exec ") + "Run a shell command.");
+ console.log(chalk.cyan(" break ") + "Pause the rebase (resume later with 'git rebase --continue').\n");
+
+ console.log(chalk.magenta("### How to Use the Editor ###"));
+ console.log(chalk.yellow("1. Use arrow keys to navigate up/down."));
+ console.log(chalk.yellow("2. Press 'i' to enter insert mode and edit commands."));
+ console.log(chalk.yellow("3. Modify 'pick' to another command (e.g., 'reword', 'squash')."));
+ console.log(chalk.yellow("4. Press 'Esc' to exit insert mode."));
+ console.log(chalk.yellow("5. Type ':wq' and press Enter to save and exit."));
+ console.log(chalk.yellow("6. If you make a mistake, use ':q!' to quit without saving.\n"));
+
+ const { confirm } = await inquirer.prompt([
+ {
+ type: 'confirm',
+ name: 'confirm',
+ message: 'Did you read the instructions above? Ready to start the rebase?',
+ default: true
+ }
+ ]);
+
+ if (!confirm) {
+ console.log(chalk.red("Rebase aborted by user."));
+ process.exit(0);
+ }
+
+ console.log(chalk.blue("Opening interactive rebase editor..."));
+
+ try {
+ execSync(`git rebase -i HEAD~${commitCount}`, { stdio: 'inherit' });
+ console.log(chalk.green("Interactive rebase completed."));
+ } catch (err: any) {
+ console.error(chalk.red("Error during interactive rebase:"), err.message);
+ process.exit(1);
+ }
+ });
+}
\ No newline at end of file
diff --git a/src/commands/rollback.ts b/src/commands/rollback.ts
new file mode 100644
index 0000000..38f651f
--- /dev/null
+++ b/src/commands/rollback.ts
@@ -0,0 +1,87 @@
+import { Command } from 'commander';
+import inquirer from 'inquirer';
+import chalk from 'chalk';
+import { execSync } from 'child_process';
+import { ensureGitRepo } from '../utils';
+
+export function registerRollbackCommand(program: Command): void {
+ program
+ .command('rollback')
+ .description('Rollback a commit with options. Soft reset keeps changes staged.')
+ .action(async () => {
+ ensureGitRepo();
+ const { resetType } = await inquirer.prompt([
+ {
+ type: 'list',
+ name: 'resetType',
+ message: 'Choose rollback type:',
+ choices: [
+ { name: 'Soft reset (keep changes staged)', value: 'soft' },
+ { name: 'Hard reset (discard changes)', value: 'hard' }
+ ],
+ }
+ ]);
+
+ let targetCommit = 'HEAD~1';
+ if (resetType === 'soft') {
+ const { chooseSpecific } = await inquirer.prompt([
+ {
+ type: 'confirm',
+ name: 'chooseSpecific',
+ message: 'Would you like to choose a specific commit for rollback? (Soft reset keeps changes staged)',
+ default: false,
+ }
+ ]);
+ if (chooseSpecific) {
+ let commitLog = '';
+ try {
+ commitLog = execSync('git log --oneline -n 10', { encoding: 'utf8' });
+ } catch (err: any) {
+ console.error(chalk.red("Error retrieving commit log:"), err.message);
+ process.exit(1);
+ }
+ const commits = commitLog.split('\n').filter(line => line.trim() !== '');
+ const commitChoices = commits.map(line => {
+ const tokens = line.split(' ');
+ const hash = tokens[0];
+ return { name: line, value: hash };
+ });
+ const { selectedCommit } = await inquirer.prompt([
+ {
+ type: 'list',
+ name: 'selectedCommit',
+ message: 'Select the commit to rollback to:',
+ choices: commitChoices,
+ }
+ ]);
+ targetCommit = selectedCommit;
+ } else {
+ console.log(chalk.yellow("Soft reset selected. Changes will remain staged."));
+ }
+ }
+
+ const { confirmRollback } = await inquirer.prompt([
+ {
+ type: 'confirm',
+ name: 'confirmRollback',
+ message: `This will perform a ${resetType} reset to ${targetCommit}. Continue?`,
+ default: false,
+ }
+ ]);
+ if (!confirmRollback) {
+ console.log(chalk.yellow("Rollback cancelled."));
+ process.exit(0);
+ }
+ try {
+ if (resetType === 'soft') {
+ execSync(`git reset --soft ${targetCommit}`, { stdio: 'inherit' });
+ } else {
+ execSync('git reset --hard HEAD~1', { stdio: 'inherit' });
+ }
+ console.log(chalk.green("Rollback successful!"));
+ } catch (err: any) {
+ console.error(chalk.red("Error during rollback:"), err.message);
+ process.exit(1);
+ }
+ });
+}
\ No newline at end of file
diff --git a/src/commands/setup.ts b/src/commands/setup.ts
new file mode 100644
index 0000000..a6bb6e4
--- /dev/null
+++ b/src/commands/setup.ts
@@ -0,0 +1,170 @@
+import { Command } from 'commander';
+import inquirer from 'inquirer';
+import { saveConfig, defaultConfig } from '../utils';
+import { Config } from '../types';
+
+export function registerSetupCommand(program: Command): void {
+ program
+ .command('setup')
+ .description('Interactive setup for Smart Commit configuration')
+ .action(async () => {
+ console.log("Welcome to Smart Commit setup!");
+ const questions = [
+ {
+ type: 'confirm',
+ name: 'enableScope',
+ message: 'Enable scope prompt?',
+ default: false,
+ },
+ {
+ type: 'confirm',
+ name: 'enableBody',
+ message: 'Enable body prompt?',
+ default: false,
+ },
+ {
+ type: 'confirm',
+ name: 'enableFooter',
+ message: 'Enable footer prompt?',
+ default: false,
+ },
+ {
+ type: 'confirm',
+ name: 'enableTicket',
+ message: 'Enable ticket prompt?',
+ default: false,
+ },
+ {
+ type: 'confirm',
+ name: 'enableRunCi',
+ message: 'Enable CI prompt?',
+ default: false,
+ },
+ {
+ type: 'input',
+ name: 'ticketRegex',
+ message: 'Enter regex for ticket extraction (leave blank for none):',
+ default: ""
+ },
+ {
+ type: 'input',
+ name: 'template',
+ message: 'Enter default commit message template:',
+ default: "[{type}]: {summary}"
+ },
+ {
+ type: 'confirm',
+ name: 'autoAdd',
+ message: 'Enable auto-add by default?',
+ default: false,
+ },
+ {
+ type: 'input',
+ name: 'ciCommand',
+ message: 'Enter CI command (leave blank for none):',
+ default: ""
+ },
+ {
+ type: 'confirm',
+ name: 'enableLint',
+ message: 'Enable commit message linting?',
+ default: false
+ },
+ // {
+ // type: 'confirm',
+ // name: 'enableHooks',
+ // message: 'Enable Git Hooks installation?',
+ // default: false
+ // }
+ {
+ type: 'confirm',
+ name: 'enableBranchConfig',
+ message: 'Would you like to configure branch naming settings?',
+ default: false,
+ },
+ {
+ type: 'input',
+ name: 'branchTemplate',
+ message: 'Enter branch template (e.g. "{type}/{ticketId}-{shortDesc}"):',
+ default: "{type}/{ticketId}-{shortDesc}",
+ when: (answers: any) => answers.enableBranchConfig
+ },
+ {
+ type: 'confirm',
+ name: 'addBranchTypes',
+ message: 'Would you like to configure branch types?',
+ default: false,
+ when: (answers: any) => answers.enableBranchConfig
+ },
+ {
+ type: 'editor',
+ name: 'branchTypes',
+ message: 'Enter your branch types as JSON (array of {value, description}):',
+ default: '[\n {"value":"feature","description":"New feature"},\n {"value":"fix","description":"Bug fix"}\n]',
+ when: (answers: any) => answers.addBranchTypes
+ },
+ {
+ type: 'confirm',
+ name: 'addPlaceholders',
+ message: 'Would you like to configure placeholder rules?',
+ default: false,
+ when: (answers: any) => answers.enableBranchConfig
+ },
+ {
+ type: 'editor',
+ name: 'branchPlaceholders',
+ message: 'Enter placeholder config as JSON (e.g. { "ticketId": {"lowercase": false} })',
+ default: '{\n "ticketId": {"lowercase": false}\n}',
+ when: (answers: any) => answers.addPlaceholders
+ }
+ ];
+ const setupAnswers = await inquirer.prompt(questions as any);
+
+ const newConfig: Config = {
+ ...defaultConfig,
+ autoAdd: setupAnswers.autoAdd,
+ ciCommand: setupAnswers.ciCommand || defaultConfig.ciCommand,
+ templates: {
+ defaultTemplate: setupAnswers.template || defaultConfig.templates.defaultTemplate
+ },
+ steps: {
+ scope: setupAnswers.enableScope,
+ body: setupAnswers.enableBody,
+ footer: setupAnswers.enableFooter,
+ ticket: setupAnswers.enableTicket,
+ runCI: setupAnswers.enableRunCi,
+ },
+ ticketRegex: setupAnswers.ticketRegex || "",
+ enableLint: setupAnswers.enableLint,
+ // enableHooks: setupAnswers.enableHooks,
+ };
+
+ if (setupAnswers.enableBranchConfig) {
+ newConfig.branch = {
+ template: setupAnswers.branchTemplate || defaultConfig.branch?.template || "{type}/{ticketId}-{shortDesc}",
+ types: defaultConfig.branch?.types || [],
+ placeholders: defaultConfig.branch?.placeholders || {}
+ };
+
+ if (setupAnswers.addBranchTypes && setupAnswers.branchTypes) {
+ try {
+ const parsed = JSON.parse(setupAnswers.branchTypes);
+ newConfig.branch.types = parsed;
+ } catch {
+ console.error("Error parsing branch types JSON, ignoring...");
+ }
+ }
+
+ if (setupAnswers.addPlaceholders && setupAnswers.branchPlaceholders) {
+ try {
+ const parsed = JSON.parse(setupAnswers.branchPlaceholders);
+ newConfig.branch.placeholders = parsed;
+ } catch {
+ console.error("Error parsing placeholders JSON, ignoring...");
+ }
+ }
+ }
+ saveConfig(newConfig);
+ console.log("Setup complete!");
+ });
+}
\ No newline at end of file
diff --git a/src/commands/stats.ts b/src/commands/stats.ts
new file mode 100644
index 0000000..97e5b62
--- /dev/null
+++ b/src/commands/stats.ts
@@ -0,0 +1,61 @@
+import { Command } from 'commander';
+import inquirer from 'inquirer';
+import chalk from 'chalk';
+import { execSync } from 'child_process';
+import { ensureGitRepo } from '../utils';
+
+export function registerStatsCommand(program: Command): void {
+ program
+ .command('stats')
+ .description('Show enhanced commit statistics with ASCII graphs')
+ .action(async () => {
+ ensureGitRepo();
+ const { period } = await inquirer.prompt([
+ {
+ type: 'list',
+ name: 'period',
+ message: 'Select period for statistics:',
+ choices: [
+ { name: 'Day', value: '1 day ago' },
+ { name: 'Week', value: '1 week ago' },
+ { name: 'Month', value: '1 month ago' }
+ ],
+ }
+ ]);
+ const { statsType } = await inquirer.prompt([
+ {
+ type: 'list',
+ name: 'statsType',
+ message: 'Select type of statistics:',
+ choices: [
+ { name: 'Shortlog by author', value: 'shortlog' },
+ { name: 'Activity by date', value: 'activity' }
+ ],
+ }
+ ]);
+ try {
+ if (statsType === 'shortlog') {
+ execSync(`git --no-pager shortlog -s -n --since="${period}"`, { stdio: 'inherit' });
+ } else if (statsType === 'activity') {
+ const datesOutput = execSync(`git log --since="${period}" --pretty=format:"%ad" --date=short`, { encoding: 'utf8' });
+ const dates = datesOutput.split('\n').filter(Boolean);
+ if (dates.length === 0) {
+ console.log(chalk.yellow("No commits found for the selected period."));
+ } else {
+ const counts: { [date: string]: number } = {};
+ dates.forEach(date => { counts[date] = (counts[date] || 0) + 1; });
+ const sortedDates = Object.keys(counts).sort();
+ console.log(chalk.blue("\nCommit Activity:"));
+ sortedDates.forEach(date => {
+ const count = counts[date];
+ const bar = "#".repeat(count);
+ console.log(chalk.green(`${date}: ${bar} (${count})`));
+ });
+ }
+ }
+ } catch (err: any) {
+ console.error(chalk.red("Error retrieving statistics:"), err.message);
+ process.exit(1);
+ }
+ });
+}
\ No newline at end of file
diff --git a/src/index.ts b/src/index.ts
new file mode 100644
index 0000000..a245b9e
--- /dev/null
+++ b/src/index.ts
@@ -0,0 +1,53 @@
+#!/usr/bin/env node
+
+import { program } from 'commander';
+import inquirer from 'inquirer';
+import inquirerAutocompletePrompt from 'inquirer-autocomplete-prompt';
+import chalk from 'chalk';
+import { registerSetupCommand } from './commands/setup';
+import { registerConfigCommand } from './commands/config';
+import { registerCommitCommand } from './commands/commit';
+import { registerAmendCommand } from './commands/amend';
+import { registerRollbackCommand } from './commands/rollback';
+import { registerBranchCommand } from './commands/branch';
+import { registerRebaseHelperCommand } from './commands/rebaseHelper';
+import { registerHistoryCommand } from './commands/history';
+import { registerStatsCommand } from './commands/stats';
+
+inquirer.registerPrompt('autocomplete', inquirerAutocompletePrompt);
+
+program
+ .name('sc')
+ .description('Smart Commit CLI Tool - Create customizable Git commits with ease.')
+ .version('1.2.0');
+
+program.addHelpText('beforeAll', chalk.blue(`
+========================================
+ Welcome to Smart Commit CLI!
+========================================
+`));
+
+program.addHelpText('afterAll', chalk.blue(`
+Examples:
+ sc commit # Start interactive commit prompt
+ sc amend # Amend the last commit interactively
+ sc rollback # Rollback the last commit (soft or hard reset)
+ sc rebase-helper # Launch interactive rebase helper
+ sc branch # Create a branch from a base + name template (with autocomplete)
+ sc stats # Show enhanced commit statistics
+ sc history # Show commit history with filtering
+ sc config # Configure or view settings
+ sc setup # Run interactive setup wizard
+`));
+
+registerConfigCommand(program);
+registerSetupCommand(program);
+registerCommitCommand(program);
+registerAmendCommand(program);
+registerRollbackCommand(program);
+registerRebaseHelperCommand(program);
+registerStatsCommand(program);
+registerHistoryCommand(program);
+registerBranchCommand(program);
+
+program.parse(process.argv);
\ No newline at end of file
diff --git a/src/types.ts b/src/types.ts
new file mode 100644
index 0000000..a9becb9
--- /dev/null
+++ b/src/types.ts
@@ -0,0 +1,61 @@
+import { Question } from "inquirer";
+
+export type InputQuestion = Question & { type: 'input' };
+export type ListQuestion = Question & { type: 'list' };
+export type ConfirmQuestion = Question & { type: 'confirm' };
+export type EditorQuestion = Question & { type: 'editor' };
+export type AutocompleteQuestion = Question & { type: 'autocomplete'; source: (answersSoFar: any, input: string) => Promise };
+
+export interface CommitType {
+ emoji: string;
+ value: string;
+ description: string;
+}
+
+export interface Templates {
+ defaultTemplate: string;
+}
+
+export interface LintRules {
+ summaryMaxLength: number;
+ typeCase: string; // e.g. 'lowercase'
+ requiredTicket: boolean;
+}
+
+export interface BranchType {
+ value: string;
+ description: string;
+}
+
+export interface PlaceholderConfig {
+ lowercase?: boolean;
+ separator?: string;
+ collapseSeparator?: boolean;
+ maxLength?: number;
+}
+
+export interface BranchConfig {
+ template: string; // e.g. "{type}/{ticketId}-{shortDesc}"
+ types: BranchType[];
+ placeholders?: Record;
+}
+
+export interface Config {
+ commitTypes: CommitType[];
+ autoAdd: boolean;
+ useEmoji: boolean;
+ ciCommand: string;
+ templates: Templates;
+ steps: {
+ scope: boolean;
+ body: boolean;
+ footer: boolean;
+ ticket: boolean;
+ runCI: boolean;
+ };
+ ticketRegex: string;
+ enableLint: boolean;
+ lintRules: LintRules;
+ branch?: BranchConfig;
+ // enableHooks: boolean; // TODO: implement hooks
+}
\ No newline at end of file
diff --git a/src/utils.ts b/src/utils.ts
new file mode 100644
index 0000000..6abe121
--- /dev/null
+++ b/src/utils.ts
@@ -0,0 +1,340 @@
+import fs from 'fs';
+import path from 'path';
+import os from 'os';
+import chalk from 'chalk';
+import { execSync } from 'child_process';
+import parseGitIgnore from 'parse-gitignore';
+import { Config, LintRules } from './types';
+import inquirer from 'inquirer';
+
+declare const __dirname: string;
+
+const CONFIG_PATH = path.join(os.homedir(), '.smart-commit-config.json');
+
+export const defaultConfig: Config = {
+ commitTypes: [
+ { emoji: "✨", value: "feat", description: "A new feature" },
+ { emoji: "🐛", value: "fix", description: "A bug fix" },
+ { emoji: "📝", value: "docs", description: "Documentation changes" },
+ { emoji: "💄", value: "style", description: "Code style improvements" },
+ { emoji: "♻️", value: "refactor", description: "Code refactoring" },
+ { emoji: "🚀", value: "perf", description: "Performance improvements" },
+ { emoji: "✅", value: "test", description: "Adding tests" },
+ { emoji: "🔧", value: "chore", description: "Maintenance and chores" },
+ { emoji: "🚧", value: "wip", description: "Work in progress" }
+ ],
+ autoAdd: false,
+ useEmoji: true,
+ ciCommand: "",
+ templates: {
+ defaultTemplate: "[{type}]{ticketSeparator}{ticket}: {summary}"
+ },
+ steps: {
+ scope: false,
+ body: false,
+ footer: false,
+ ticket: false,
+ runCI: false,
+ },
+ ticketRegex: "",
+ enableLint: false,
+ lintRules: {
+ summaryMaxLength: 72,
+ typeCase: "lowercase",
+ requiredTicket: false,
+ },
+ branch: {
+ template: "{type}/{ticketId}-{shortDesc}",
+ types: [
+ { value: "feature", description: "New feature" },
+ { value: "fix", description: "Bug fix" },
+ { value: "chore", description: "Chore branch" },
+ { value: "hotfix", description: "Hotfix branch" },
+ { value: "release", description: "Release branch" },
+ { value: "dev", description: "Development branch" }
+ ],
+ placeholders: {
+ ticketId: { lowercase: false }
+ }
+ }
+};
+
+export function loadConfig(): Config {
+ let config: Config = defaultConfig;
+ if (fs.existsSync(CONFIG_PATH)) {
+ try {
+ const data = fs.readFileSync(CONFIG_PATH, 'utf8');
+ config = JSON.parse(data) as Config;
+ } catch {
+ console.error(chalk.red("Error reading global config, using default settings."));
+ }
+ }
+ const localConfigPath = path.join(process.cwd(), '.smartcommitrc.json');
+ if (fs.existsSync(localConfigPath)) {
+ try {
+ const localData = fs.readFileSync(localConfigPath, 'utf8');
+ const localConfig = JSON.parse(localData) as Partial;
+ config = { ...config, ...localConfig };
+ } catch {
+ console.error(chalk.red("Error reading local config, ignoring."));
+ }
+ }
+ if (!config.lintRules) {
+ config.lintRules = { ...defaultConfig.lintRules };
+ }
+ return config;
+}
+
+export function saveConfig(config: Config): void {
+ fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), 'utf8');
+ console.log(chalk.green("Global configuration saved at"), CONFIG_PATH);
+}
+
+export function loadGitignorePatterns(): string[] {
+ const gitignorePath = path.join(process.cwd(), '.gitignore');
+ if (!fs.existsSync(gitignorePath)) {
+ return [];
+ }
+ try {
+ const buf = fs.readFileSync(gitignorePath);
+ const result = parseGitIgnore(buf);
+
+ let patterns: string[] = [];
+ if (Array.isArray(result)) {
+ patterns = result;
+ } else if (result && Array.isArray((result as any).patterns)) {
+ patterns = (result as any).patterns;
+ }
+
+ patterns = patterns.filter(Boolean);
+
+ return patterns;
+ } catch (err) {
+ console.error(chalk.red("Failed to parse .gitignore:"), err);
+ return [];
+ }
+}
+
+export function getUnstagedFiles(): string[] {
+ let unstaged: string[] = [];
+
+ try {
+ const changed = execSync('git diff --name-only', { encoding: 'utf8' })
+ .split('\n')
+ .map(f => f.trim())
+ .filter(Boolean);
+
+ const untracked = execSync('git ls-files --others --exclude-standard', { encoding: 'utf8' })
+ .split('\n')
+ .map(f => f.trim())
+ .filter(Boolean);
+
+ unstaged = Array.from(new Set([...changed, ...untracked]));
+ } catch (err: any) {
+ console.error(chalk.red("Error getting unstaged files:"), err.message);
+ }
+ return unstaged;
+}
+
+export function stageSelectedFiles(files: string[]): void {
+ if (files.length === 0) {
+ return;
+ }
+ for (const file of files) {
+ execSync(`git add "${file}"`, { stdio: 'inherit' });
+ }
+}
+
+export function computeAutoSummary(): string {
+ let summaries: string[] = [];
+ try {
+ const diffFiles = execSync('git diff --cached --name-only', { encoding: 'utf8' })
+ .split('\n')
+ .filter(f => f.trim() !== '');
+ if (diffFiles.length > 0) {
+ if (diffFiles.includes('package.json')) summaries.push('Update dependencies');
+ if (diffFiles.some(f => f.includes('Dockerfile'))) summaries.push('Update Docker configuration');
+ if (diffFiles.some(f => f.endsWith('.md'))) summaries.push('Update documentation');
+ if (diffFiles.some(f => f.startsWith('src/') || f.endsWith('.ts') || f.endsWith('.js'))) summaries.push('Update source code');
+ return summaries.join(', ');
+ }
+ } catch { }
+ return '';
+}
+
+export function suggestCommitType(): string | null {
+ try {
+ const diffFiles = execSync('git diff --cached --name-only', { encoding: 'utf8' })
+ .split('\n')
+ .filter(f => f.trim() !== '');
+
+ if (diffFiles.length > 0) {
+ if (diffFiles.every(f => f.endsWith('.md'))) return 'docs';
+
+ const configFiles = [
+ 'package.json',
+ 'tsconfig.json',
+ '.eslintrc',
+ '.prettierrc',
+ 'babel.config.js',
+ 'webpack.config.js',
+ 'vite.config.ts',
+ '.env',
+ 'docker-compose.yml',
+ 'Dockerfile'
+ ];
+ if (diffFiles.some(f => configFiles.includes(f))) return 'chore';
+
+ if (diffFiles.some(f =>
+ f.includes('__tests__') ||
+ f.endsWith('.test.ts') ||
+ f.endsWith('.spec.ts')
+ )) return 'test';
+
+ const sourcePatterns = [
+ 'src/components/',
+ 'src/hooks/',
+ 'src/utils/',
+ 'src/services/',
+ 'src/context/',
+ 'src/types/',
+ 'src/styles/'
+ ];
+
+ if (diffFiles.some(f => sourcePatterns.some(pattern => f.includes(pattern)))) {
+ if (diffFiles.some(f => f.includes('styles/') || f.endsWith('.css') || f.endsWith('.scss'))) return 'style';
+ if (diffFiles.some(f => f.includes('types/') || f.endsWith('.d.ts'))) return 'refactor';
+ return 'feat';
+ }
+
+ if (diffFiles.some(f =>
+ f.includes('perf/') ||
+ f.includes('performance/') ||
+ f.includes('optimization/')
+ )) return 'perf';
+
+ if (diffFiles.some(f =>
+ f.includes('security/') ||
+ f.endsWith('.lock') ||
+ f.includes('vulnerability')
+ )) return 'security';
+
+ if (diffFiles.some(f =>
+ f.includes('.github/workflows/') ||
+ f.includes('ci/') ||
+ f.includes('cd/') ||
+ f === '.gitlab-ci.yml'
+ )) return 'ci';
+
+ if (diffFiles.some(f =>
+ f === 'package-lock.json' ||
+ f === 'yarn.lock' ||
+ f === 'pnpm-lock.yaml'
+ )) return 'build';
+
+ if (diffFiles.some(f => f.startsWith('src/'))) return 'feat';
+ }
+ } catch { }
+ return null;
+}
+
+export function lintCommitMessage(message: string, rules: LintRules): string[] {
+ const errors: string[] = [];
+ const lines = message.split('\n');
+ const summary = lines[0].trim();
+ if (summary.length > rules.summaryMaxLength) {
+ errors.push(`Summary is too long (${summary.length} characters). Max allowed is ${rules.summaryMaxLength}.`);
+ }
+ if (rules.typeCase === 'lowercase' && summary && summary[0] !== summary[0].toLowerCase()) {
+ errors.push("Summary should start with a lowercase letter.");
+ }
+ if (rules.requiredTicket && !message.includes('#')) {
+ errors.push("A ticket ID is required in the commit message (e.g., '#DEV-123').");
+ }
+ return errors;
+}
+
+export async function previewCommitMessage(message: string, lintRules: LintRules): Promise {
+ let currentMessage = message;
+
+ while (true) {
+ console.log(chalk.blue("\nPreview commit message:\n"));
+ console.log(currentMessage);
+
+ const { confirmPreview } = await inquirer.prompt([
+ {
+ type: 'confirm',
+ name: 'confirmPreview',
+ message: 'Does the commit message look OK?',
+ default: true
+ }
+ ]);
+
+ if (!confirmPreview) {
+ const response = await inquirer.prompt([
+ {
+ type: 'editor',
+ name: 'editedMessage',
+ message: 'Edit the commit message as needed:',
+ default: currentMessage
+ }
+ ]);
+ currentMessage = response.editedMessage || currentMessage;
+ }
+
+ const errors = lintCommitMessage(currentMessage, lintRules);
+
+ if (errors.length === 0) {
+ return currentMessage;
+ }
+
+ console.log(chalk.red("Linting errors:"));
+ errors.forEach(err => console.log(chalk.red("- " + err)));
+
+ const response = await inquirer.prompt([
+ {
+ type: 'confirm',
+ name: 'continueEditing',
+ message: 'Do you want to continue editing?',
+ default: true
+ },
+ {
+ type: 'editor',
+ name: 'editedMessage',
+ message: 'Edit the commit message to fix these issues:',
+ default: currentMessage,
+ when: (answers) => answers.continueEditing
+ }
+ ]);
+
+ if (!response.continueEditing) {
+ throw new Error("Commit message editing cancelled");
+ }
+
+ currentMessage = response.editedMessage;
+ }
+}
+
+export function ensureGitRepo(): void {
+ try {
+ execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' });
+ } catch {
+ console.log(chalk.red("Not a Git repository. Please run 'git init' or navigate to a valid repo."));
+ process.exit(1);
+ }
+}
+
+export function showDiffPreview(): void {
+ try {
+ const diffSoFancyPath = path.join(__dirname, '..', 'node_modules', '.bin', 'diff-so-fancy');
+ const diff = execSync(`git diff --staged | "${diffSoFancyPath}"`, { encoding: 'utf8' });
+ if (diff.trim() === "") {
+ console.log(chalk.yellow("No staged changes to show."));
+ } else {
+ console.log(chalk.green("\nStaged Diff Preview:\n"));
+ console.log(chalk.green(diff));
+ }
+ } catch (err: any) {
+ console.error(chalk.red("Error retrieving diff:"), err.message);
+ }
+}
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
index 6c869ba..2f007c3 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,104 +1,21 @@
{
"compilerOptions": {
- /* Visit https://aka.ms/tsconfig to read more about this file */
- /* Projects */
- // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
- // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
- // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
- // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
- // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
- // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
- /* Language and Environment */
- "target": "ES2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
- // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
- // "jsx": "preserve", /* Specify what JSX code is generated. */
- // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
- // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
- // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
- // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
- // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
- // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
- // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
- // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
- // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
- /* Modules */
- "module": "NodeNext", /* Specify what module code is generated. */
- // "rootDir": "./", /* Specify the root folder within your source files. */
- "moduleResolution": "nodenext", /* Specify how TypeScript looks up a file from a given module specifier. */
- // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
- // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
- // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
- // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
- // "types": [], /* Specify type package names to be included without being referenced in a source file. */
- // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
- // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
- // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
- // "rewriteRelativeImportExtensions": true, /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */
- // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
- // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
- // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
- // "noUncheckedSideEffectImports": true, /* Check side effect imports. */
- "resolveJsonModule": true, /* Enable importing .json files. */
- // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
- // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */
- /* JavaScript Support */
- // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
- // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
- // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
- /* Emit */
- // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
- // "declarationMap": true, /* Create sourcemaps for d.ts files. */
- // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
- // "sourceMap": true, /* Create source map files for emitted JavaScript files. */
- // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
- // "noEmit": true, /* Disable emitting files from a compilation. */
- // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
- // "outDir": "./", /* Specify an output folder for all emitted files. */
- "outDir": "./dist",
- // "removeComments": true, /* Disable emitting comments. */
- // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
- // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
- // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
- // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
- // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
- // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
- // "newLine": "crlf", /* Set the newline character for emitting files. */
- // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
- // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
- // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
- // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
- // "declarationDir": "./", /* Specify the output directory for generated declaration files. */
- /* Interop Constraints */
- // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
- // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
- // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */
- "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
- "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
- // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
- "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
- /* Type Checking */
- "strict": true, /* Enable all strict type-checking options. */
- // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
- // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
- // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
- // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
- // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
- // "strictBuiltinIteratorReturn": true, /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */
- // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
- // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
- // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
- // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
- // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
- // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
- // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
- // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
- // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
- // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
- // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
- // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
- // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
- /* Completeness */
- // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
- "skipLibCheck": true /* Skip type checking all .d.ts files. */
- }
+ "target": "ES2020",
+ "module": "CommonJS",
+ "moduleResolution": "node",
+ "noEmit": false,
+ "rootDir": "src",
+ "outDir": "dist",
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "strict": true,
+ "skipLibCheck": true
+ },
+ "include": [
+ "src/**/*.ts"
+ ],
+ "exclude": [
+ "node_modules",
+ "dist"
+ ]
}
\ No newline at end of file