diff --git a/.eslintrc.js b/.eslintrc.js
index 7231a22..6b352c5 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -5,6 +5,7 @@ module.exports = {
es6: true,
browser: true,
node: true,
+ jest: true,
},
parserOptions: {
sourceType: 'module',
diff --git a/.github/workflows/manage-issue-header.yml b/.github/workflows/manage-issue-header.yml
index 7630a3d..907f2bc 100644
--- a/.github/workflows/manage-issue-header.yml
+++ b/.github/workflows/manage-issue-header.yml
@@ -43,3 +43,34 @@ jobs:
script: |
const script = require('./scripts/manage-issue-header.js');
await script({github, context, core});
+ good-first-issue-comment:
+ runs-on: ubuntu-latest
+ if: >-
+ github.event.action == 'labeled' && github.event.label.name == 'good first issue'
+ steps:
+ - name: Generate GitHub token
+ id: generate-token
+ uses: actions/create-github-app-token@v2
+ with:
+ app-id: ${{ secrets.LE_BOT_APP_ID }}
+ private-key: ${{ secrets.LE_BOT_PRIVATE_KEY }}
+ - name: Checkout .github repository
+ uses: actions/checkout@v6
+ with:
+ repository: learningequality/.github
+ ref: main
+ token: ${{ steps.generate-token.outputs.token }}
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: 20
+ cache: 'yarn'
+ - name: Install dependencies
+ run: yarn install --frozen-lockfile
+ - name: Run script
+ uses: actions/github-script@v8
+ with:
+ github-token: ${{ steps.generate-token.outputs.token }}
+ script: |
+ const script = require('./scripts/good-first-issue-comment.js');
+ await script({github, context, core});
diff --git a/docs/community-automations.md b/docs/community-automations.md
index 2a51041..6352d14 100644
--- a/docs/community-automations.md
+++ b/docs/community-automations.md
@@ -21,6 +21,45 @@ In `scripts/contants.js` set:
- `BOT_MESSAGE_ISSUE_NOT_OPEN`: _Issue not open for contribution_ message text
- `BOT_MESSAGE_ALREADY_ASSIGNED`: _Issue already assigned_ message text
+## `/assign` self-assignment
+
+When a contributor comments `/assign` (exact match, trimmed) on an issue:
+
+| Issue state | Action | Bot message | Slack |
+|-------------|--------|-------------|-------|
+| Not `help wanted` | Decline | `BOT_MESSAGE_ISSUE_NOT_OPEN` | `#support-dev-notifications` |
+| `help wanted` + assigned to commenter | No-op | - | - |
+| `help wanted` + assigned to someone else | Decline | `BOT_MESSAGE_ALREADY_ASSIGNED` | `#support-dev-notifications` |
+| `help wanted` + NOT `good first issue` | Decline | `BOT_MESSAGE_ASSIGN_NOT_GOOD_FIRST_ISSUE` | `#support-dev-notifications` |
+| `help wanted` + `good first issue` + at limit | Decline | Dynamic message with assignments and cooldowns | `#support-dev-notifications` |
+| `help wanted` + `good first issue` + under limit | Assign | `BOT_MESSAGE_ASSIGN_SUCCESS` | `#support-dev-notifications` |
+
+**Cross-repo limit:** Contributors can have up to 2 assigned issues across all community repos (`COMMUNITY_REPOS`).
+
+**7-day cooldown:** Issues unassigned within the last 7 days count toward the limit. The limit check is: `currentAssignments + recentUnassignments >= MAX_ASSIGNED_ISSUES`.
+
+**Slack notifications:** All `/assign` activity goes to `#support-dev-notifications` only. It does not trigger `#support-dev` notifications.
+
+## Keyword detection on `good first issue` issues
+
+When existing keyword detection triggers on an unassigned `good first issue` issue, the bot reply includes guidance about the `/assign` command (`BOT_MESSAGE_KEYWORD_GOOD_FIRST_ISSUE`) instead of the normal no-reply behavior.
+
+In `scripts/constants.js` set:
+- `BOT_MESSAGE_ASSIGN_SUCCESS`: Assignment confirmation message
+- `BOT_MESSAGE_ASSIGN_NOT_GOOD_FIRST_ISSUE`: Decline message for non-GFI issues
+- `BOT_MESSAGE_KEYWORD_GOOD_FIRST_ISSUE`: Keyword reply with `/assign` guidance
+
+# `good-first-issue-comment`
+
+Posts a guidance comment when the `good first issue` label is applied to an issue (triggered via the `manage-issue-header` workflow). Explains the `/assign` command, issue limits, cooldown, and links to contributing guidelines.
+
+- Only posts if the issue also has `help wanted` label
+- Deletes any previous guidance comment from the bot before posting a new one
+- Identified by the `` HTML comment marker
+
+In `scripts/constants.js` set:
+- `BOT_MESSAGE_GOOD_FIRST_ISSUE_GUIDANCE`: Guidance message text
+
# `contributor-pr-reply`
Sends reply to a community pull requests.
diff --git a/package.json b/package.json
index 59c5b27..adf2638 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,8 @@
{
"scripts": {
"lint": "eslint .",
- "format": "prettier --write ."
+ "format": "prettier --write .",
+ "test": "jest"
},
"dependencies": {
"axios": "^1.13.5",
@@ -13,6 +14,7 @@
"devDependencies": {
"eslint": "^8.57.0",
"eslint-config-prettier": "^10.1.8",
+ "jest": "^30.3.0",
"prettier": "^3.8.1"
}
}
diff --git a/scripts/constants.js b/scripts/constants.js
index 851349e..0680b8e 100644
--- a/scripts/constants.js
+++ b/scripts/constants.js
@@ -82,6 +82,10 @@ const KEYWORDS_DETECT_ASSIGNMENT_REQUEST = [
];
const ISSUE_LABEL_HELP_WANTED = 'help wanted';
+const ISSUE_LABEL_GOOD_FIRST_ISSUE = 'good first issue';
+const MAX_ASSIGNED_ISSUES = 2;
+const COOLDOWN_DAYS = 7;
+const ASSIGN_GUIDANCE_MARKER = '';
const LABEL_COMMUNITY_REVIEW = 'community-review';
// Will be attached to bot messages when not empty
@@ -92,7 +96,52 @@ const BOT_MESSAGE_ISSUE_NOT_OPEN = `Hi! š \n\n Thanks so much for your intere
const BOT_MESSAGE_ALREADY_ASSIGNED = `Hi! š \n\n Thanks so much for your interest! **This issue is already assigned. Visit [Contributing guidelines](https://learningequality.org/contributing-to-our-open-code-base) to learn about the contributing process and how to find suitable issues. If there are no unassigned 'help wanted' issues available, please wait until new ones are added.** \n\n We really appreciate your willingness to help. š${GSOC_NOTE}`;
-const BOT_MESSAGE_PULL_REQUEST = (author) => `š Hi @${author}, thanks for contributing! \n\n **For the review process to begin, please verify that the following is satisfied:**\n\n- [ ] **Contribution is aligned with our [contributing guidelines](https://learningequality.org/contributing-to-our-open-code-base)**\n- [ ] **Pull request description has correctly filled _AI usage_ section & follows our AI guidance:**\n\n \n AI guidance
\n\n
\n\n **State explicitly whether you didn't use or used AI & how.**\n\n If you used it, ensure that the PR is aligned with [Using AI](https://learningequality.org/contributing-to-our-open-code-base/#using-generative-ai) as well as our DEEP framework. DEEP asks you:\n\n - **Disclose** ā Be open about when you've used AI for support.\n - **Engage critically** ā Question what is generated. Review code for correctness and unnecessary complexity.\n - **Edit** ā Review and refine AI output. Remove unnecessary code and verify it still works after your edits.\n - **Process sharing** ā Explain how you used the AI so others can learn.\n\n
\n\n Examples of good disclosures:\n\n > "I used Claude Code to implement the component, prompting it to follow the pattern in ComponentX. I reviewed the generated code, removed unnecessary error handling, and verified the tests pass."\n\n > "I brainstormed the approach with Gemini, then had it write failing tests for the feature. After reviewing the tests, I used Claude Code to generate the implementation. I refactored the output to reduce verbosity and ran the full test suite."\n\n \n\nAlso check that issue requirements are satisfied & you ran \`pre-commit\` locally. \n\n**Pull requests that don't follow the guidelines will be closed.**\n\n**Reviewer assignment can take up to 2 weeks.**`;
+const BOT_MESSAGE_GOOD_FIRST_ISSUE_GUIDANCE =
+ `${ASSIGN_GUIDANCE_MARKER}\n\n` +
+ `Hi! š\n\n` +
+ `This issue is available for contribution and supports ` +
+ `**self-assignment**. Here's how to get started:\n\n` +
+ `- **Comment \`/assign\` to assign yourself** to this issue\n` +
+ `- You can have up to **${MAX_ASSIGNED_ISSUES} issues** assigned ` +
+ `at a time across all community repos\n` +
+ `- Dropping an issue has a **${COOLDOWN_DAYS}-day cooldown** ` +
+ `before the slot opens up\n` +
+ `- **Link your pull request** to this issue when you submit it` +
+ `\n\nš **Read the [Contributing guidelines]` +
+ `(https://learningequality.org/contributing-to-our-open-code-base/)` +
+ ` before starting.**${GSOC_NOTE}`;
+
+const BOT_MESSAGE_ASSIGN_SUCCESS =
+ `Hi! š\n\n` +
+ `You've been assigned to this issue. Here's what to do next:\n\n` +
+ `- **Read the issue description** carefully and make sure ` +
+ `you understand the requirements\n` +
+ `- **Link your pull request** to this issue when you submit it\n` +
+ `- If you can no longer work on this, **unassign yourself** ` +
+ `so others can pick it up\n\n` +
+ `Good luck! š${GSOC_NOTE}`;
+
+const BOT_MESSAGE_ASSIGN_NOT_GOOD_FIRST_ISSUE =
+ `Hi! š\n\n` +
+ `Self-assignment via \`/assign\` is only available for issues ` +
+ `labeled **\`good first issue\`**. This issue does not have ` +
+ `that label.\n\n` +
+ `Visit [Contributing guidelines]` +
+ `(https://learningequality.org/contributing-to-our-open-code-base/)` +
+ ` to learn about the contributing process and how to find ` +
+ `suitable issues. š${GSOC_NOTE}`;
+
+const BOT_MESSAGE_KEYWORD_GOOD_FIRST_ISSUE =
+ `Hi! š\n\n` +
+ `Thanks for your interest! This issue supports ` +
+ `**self-assignment**. **Comment \`/assign\` to assign ` +
+ `yourself.**\n\n` +
+ `Visit [Contributing guidelines]` +
+ `(https://learningequality.org/contributing-to-our-open-code-base/)` +
+ ` to learn about the contributing process. š${GSOC_NOTE}`;
+
+const BOT_MESSAGE_PULL_REQUEST = author =>
+ `š Hi @${author}, thanks for contributing! \n\n **For the review process to begin, please verify that the following is satisfied:**\n\n- [ ] **Contribution is aligned with our [contributing guidelines](https://learningequality.org/contributing-to-our-open-code-base)**\n- [ ] **Pull request description has correctly filled _AI usage_ section & follows our AI guidance:**\n\n \n AI guidance
\n\n
\n\n **State explicitly whether you didn't use or used AI & how.**\n\n If you used it, ensure that the PR is aligned with [Using AI](https://learningequality.org/contributing-to-our-open-code-base/#using-generative-ai) as well as our DEEP framework. DEEP asks you:\n\n - **Disclose** ā Be open about when you've used AI for support.\n - **Engage critically** ā Question what is generated. Review code for correctness and unnecessary complexity.\n - **Edit** ā Review and refine AI output. Remove unnecessary code and verify it still works after your edits.\n - **Process sharing** ā Explain how you used the AI so others can learn.\n\n
\n\n Examples of good disclosures:\n\n > "I used Claude Code to implement the component, prompting it to follow the pattern in ComponentX. I reviewed the generated code, removed unnecessary error handling, and verified the tests pass."\n\n > "I brainstormed the approach with Gemini, then had it write failing tests for the feature. After reviewing the tests, I used Claude Code to generate the implementation. I refactored the output to reduce verbosity and ran the full test suite."\n\n \n\nAlso check that issue requirements are satisfied & you ran \`pre-commit\` locally. \n\n**Pull requests that don't follow the guidelines will be closed.**\n\n**Reviewer assignment can take up to 2 weeks.**`;
const HOLIDAY_MESSAGE = `Season's greetings! š \n\n We'd like to thank everyone for another year of fruitful collaborations, engaging discussions, and for the continued support of our work. **Learning Equality will be on holidays from December 22 to January 5.** We look forward to much more in the new year and wish you a very happy holiday season!${GSOC_NOTE}`;
@@ -119,8 +168,17 @@ module.exports = {
CLOSE_CONTRIBUTORS,
KEYWORDS_DETECT_ASSIGNMENT_REQUEST,
ISSUE_LABEL_HELP_WANTED,
+ GSOC_NOTE,
+ ISSUE_LABEL_GOOD_FIRST_ISSUE,
+ MAX_ASSIGNED_ISSUES,
+ COOLDOWN_DAYS,
+ ASSIGN_GUIDANCE_MARKER,
BOT_MESSAGE_ISSUE_NOT_OPEN,
BOT_MESSAGE_ALREADY_ASSIGNED,
+ BOT_MESSAGE_GOOD_FIRST_ISSUE_GUIDANCE,
+ BOT_MESSAGE_ASSIGN_SUCCESS,
+ BOT_MESSAGE_ASSIGN_NOT_GOOD_FIRST_ISSUE,
+ BOT_MESSAGE_KEYWORD_GOOD_FIRST_ISSUE,
BOT_MESSAGE_PULL_REQUEST,
BOT_MESSAGE_RTIBBLESBOT_REVIEW,
RTIBBLESBOT_USERNAME,
diff --git a/scripts/constants.test.js b/scripts/constants.test.js
new file mode 100644
index 0000000..9e67829
--- /dev/null
+++ b/scripts/constants.test.js
@@ -0,0 +1,66 @@
+const constants = require('./constants');
+
+describe('assign-related constants', () => {
+ test('ISSUE_LABEL_GOOD_FIRST_ISSUE is defined', () => {
+ expect(constants.ISSUE_LABEL_GOOD_FIRST_ISSUE).toBe('good first issue');
+ });
+
+ test('MAX_ASSIGNED_ISSUES is 2', () => {
+ expect(constants.MAX_ASSIGNED_ISSUES).toBe(2);
+ });
+
+ test('COOLDOWN_DAYS is 7', () => {
+ expect(constants.COOLDOWN_DAYS).toBe(7);
+ });
+
+ test('ASSIGN_GUIDANCE_MARKER is an HTML comment marker', () => {
+ expect(constants.ASSIGN_GUIDANCE_MARKER).toBe('');
+ });
+
+ test('GSOC_NOTE is exported', () => {
+ expect(constants.GSOC_NOTE).toBeDefined();
+ expect(typeof constants.GSOC_NOTE).toBe('string');
+ });
+});
+
+describe('bot messages for /assign', () => {
+ test('BOT_MESSAGE_GOOD_FIRST_ISSUE_GUIDANCE contains marker and key info', () => {
+ const msg = constants.BOT_MESSAGE_GOOD_FIRST_ISSUE_GUIDANCE;
+ expect(msg).toBeDefined();
+ expect(msg).toContain(constants.ASSIGN_GUIDANCE_MARKER);
+ expect(msg).toContain('/assign');
+ expect(msg).toContain('self-assignment');
+ expect(msg).toContain(String(constants.MAX_ASSIGNED_ISSUES));
+ expect(msg).toContain(String(constants.COOLDOWN_DAYS));
+ expect(msg).toContain('Contributing guidelines');
+ });
+
+ test('BOT_MESSAGE_ASSIGN_SUCCESS contains assignment confirmation', () => {
+ const msg = constants.BOT_MESSAGE_ASSIGN_SUCCESS;
+ expect(msg).toBeDefined();
+ expect(msg).toContain('assigned');
+ expect(msg).toContain('Link your pull request');
+ });
+
+ test('BOT_MESSAGE_ASSIGN_NOT_GOOD_FIRST_ISSUE explains GFI requirement', () => {
+ const msg = constants.BOT_MESSAGE_ASSIGN_NOT_GOOD_FIRST_ISSUE;
+ expect(msg).toBeDefined();
+ expect(msg).toContain('good first issue');
+ expect(msg).toContain('/assign');
+ });
+
+ test('BOT_MESSAGE_KEYWORD_GOOD_FIRST_ISSUE guides to /assign', () => {
+ const msg = constants.BOT_MESSAGE_KEYWORD_GOOD_FIRST_ISSUE;
+ expect(msg).toBeDefined();
+ expect(msg).toContain('/assign');
+ expect(msg).toContain('self-assignment');
+ });
+
+ test('all new bot messages include GSOC_NOTE', () => {
+ const gsoc = constants.GSOC_NOTE;
+ expect(constants.BOT_MESSAGE_GOOD_FIRST_ISSUE_GUIDANCE).toContain(gsoc);
+ expect(constants.BOT_MESSAGE_ASSIGN_SUCCESS).toContain(gsoc);
+ expect(constants.BOT_MESSAGE_ASSIGN_NOT_GOOD_FIRST_ISSUE).toContain(gsoc);
+ expect(constants.BOT_MESSAGE_KEYWORD_GOOD_FIRST_ISSUE).toContain(gsoc);
+ });
+});
diff --git a/scripts/contributor-issue-comment.js b/scripts/contributor-issue-comment.js
index 2f00bf3..5ad7178 100644
--- a/scripts/contributor-issue-comment.js
+++ b/scripts/contributor-issue-comment.js
@@ -4,8 +4,15 @@ const {
LE_BOT_USERNAME,
KEYWORDS_DETECT_ASSIGNMENT_REQUEST,
ISSUE_LABEL_HELP_WANTED,
+ ISSUE_LABEL_GOOD_FIRST_ISSUE,
+ MAX_ASSIGNED_ISSUES,
+ COOLDOWN_DAYS,
+ GSOC_NOTE,
BOT_MESSAGE_ISSUE_NOT_OPEN,
BOT_MESSAGE_ALREADY_ASSIGNED,
+ BOT_MESSAGE_ASSIGN_SUCCESS,
+ BOT_MESSAGE_ASSIGN_NOT_GOOD_FIRST_ISSUE,
+ BOT_MESSAGE_KEYWORD_GOOD_FIRST_ISSUE,
COMMUNITY_REPOS,
} = require('./constants');
const {
@@ -13,9 +20,10 @@ const {
sendBotMessage,
escapeIssueTitleForSlackMessage,
hasRecentBotComment,
- hasLabel,
+ getLabels,
getIssues,
getPullRequests,
+ getRecentUnassignments,
} = require('./utils');
// Format information about author's assigned open issues
@@ -40,6 +48,148 @@ function formatAuthorActivity(issues, pullRequests) {
return `(${parts.join(' | ')})`;
}
+function formatAssignAtLimitMessage(assignedIssues, recentUnassignments) {
+ let message =
+ `Hi! š\n\n` +
+ `You can't be assigned to this issue right now because ` +
+ `you've reached the **${MAX_ASSIGNED_ISSUES}-issue limit**.`;
+
+ if (assignedIssues.length > 0) {
+ message += '\n\n**Your current assignments:**\n';
+ message += assignedIssues.map(i => `- ${i.html_url}`).join('\n');
+ }
+
+ if (recentUnassignments.length > 0) {
+ message += '\n\n**Recently dropped issues (cooldown):**\n';
+ message += recentUnassignments
+ .map(u => {
+ const msRemaining =
+ COOLDOWN_DAYS * 24 * 60 * 60 * 1000 - (Date.now() - new Date(u.unassignedAt).getTime());
+ const daysRemaining = Math.ceil(msRemaining / (24 * 60 * 60 * 1000));
+ return (
+ `- ${u.issueUrl} ` + `(${daysRemaining} day${daysRemaining !== 1 ? 's' : ''} remaining)`
+ );
+ })
+ .join('\n');
+ }
+
+ message +=
+ `\n\nOnce a slot opens up, come back and comment ` + `\`/assign\` again. š${GSOC_NOTE}`;
+ return message;
+}
+
+// Send a bot reply and set the Slack notification output in one step.
+async function sendAssignReplyAndNotify(issueNumber, message, slackSuffix, ctx) {
+ const { repo, issueUrl, issueTitle, github, context, core } = ctx;
+ const url = await sendBotMessage(issueNumber, message, { github, context, core });
+ if (url) {
+ core.setOutput(
+ 'support_dev_notifications_bot',
+ `*[${repo}] <${url}|${slackSuffix}> on issue: <${issueUrl}|${issueTitle}>*`,
+ );
+ }
+}
+
+async function handleAssignCommand({
+ issueNumber,
+ issueUrl,
+ issueTitle,
+ commentAuthor,
+ commentId,
+ issueAssignees,
+ isHelpWanted,
+ isGoodFirstIssue,
+ repo,
+ owner,
+ github,
+ context,
+ core,
+}) {
+ const ctx = { repo, issueUrl, issueTitle, github, context, core };
+ const slackRequest =
+ `*[${repo}] ` +
+ `<${issueUrl}#issuecomment-${commentId}|/assign comment> ` +
+ `on issue: <${issueUrl}|${issueTitle}> ` +
+ `by _${commentAuthor}_*`;
+
+ // Not help wanted
+ if (!isHelpWanted) {
+ core.setOutput('support_dev_notifications_message', slackRequest);
+ await sendAssignReplyAndNotify(
+ issueNumber,
+ BOT_MESSAGE_ISSUE_NOT_OPEN,
+ '/assign rejected - not open',
+ ctx,
+ );
+ return;
+ }
+
+ // Already assigned to commenter ā silent no-op, no Slack
+ if (issueAssignees.includes(commentAuthor)) {
+ core.info(`${commentAuthor} already assigned to #${issueNumber}`);
+ return;
+ }
+
+ // Slack notification: /assign requested (after no-op checks)
+ core.setOutput('support_dev_notifications_message', slackRequest);
+
+ // Assigned to someone else
+ if (issueAssignees.length > 0) {
+ await sendAssignReplyAndNotify(
+ issueNumber,
+ BOT_MESSAGE_ALREADY_ASSIGNED,
+ '/assign rejected - already assigned',
+ ctx,
+ );
+ return;
+ }
+
+ if (!isGoodFirstIssue) {
+ await sendAssignReplyAndNotify(
+ issueNumber,
+ BOT_MESSAGE_ASSIGN_NOT_GOOD_FIRST_ISSUE,
+ '/assign rejected - not good first issue',
+ ctx,
+ );
+ return;
+ }
+
+ // --- Limit check and assignment ---
+
+ // Check cross-repo limits and cooldown
+ const [assignedIssues, recentUnassignments] = await Promise.all([
+ getIssues(commentAuthor, 'open', owner, COMMUNITY_REPOS, github, core),
+ getRecentUnassignments(commentAuthor, COOLDOWN_DAYS, owner, COMMUNITY_REPOS, github, core),
+ ]);
+
+ // Filter unassignments to exclude currently assigned issues
+ const assignedUrls = new Set(assignedIssues.map(i => i.html_url));
+ const filteredUnassignments = recentUnassignments.filter(u => !assignedUrls.has(u.issueUrl));
+
+ const totalSlots = assignedIssues.length + filteredUnassignments.length;
+
+ if (totalSlots >= MAX_ASSIGNED_ISSUES) {
+ const message = formatAssignAtLimitMessage(assignedIssues, filteredUnassignments);
+ await sendAssignReplyAndNotify(issueNumber, message, '/assign rejected - at limit', ctx);
+ return;
+ }
+
+ // Assign the contributor
+ await github.rest.issues.addAssignees({
+ owner,
+ repo,
+ issue_number: issueNumber,
+ assignees: [commentAuthor],
+ });
+
+ await sendAssignReplyAndNotify(
+ issueNumber,
+ BOT_MESSAGE_ASSIGN_SUCCESS,
+ `/assign approved - assigned _${commentAuthor}_`,
+ ctx,
+ );
+}
+
function shouldSendBotReply(
issueCreator,
commentAuthor,
@@ -47,6 +197,8 @@ function shouldSendBotReply(
isHelpWanted,
isAssignmentRequest,
isIssueAssignedToSomeoneElse,
+ isGoodFirstIssue,
+ isUnassigned,
) {
if (commentAuthorIsCloseContributor) {
return [false, null];
@@ -64,6 +216,11 @@ function shouldSendBotReply(
return [true, BOT_MESSAGE_ISSUE_NOT_OPEN];
}
+ // Keyword on unassigned GFI ā guide to /assign
+ if (isHelpWanted && isGoodFirstIssue && isUnassigned && isAssignmentRequest) {
+ return [true, BOT_MESSAGE_KEYWORD_GOOD_FIRST_ISSUE];
+ }
+
return [false, null];
}
@@ -105,20 +262,38 @@ module.exports = async ({ github, context, core }) => {
const isAssignmentRequest = keywordRegexes.find(regex => regex.test(commentBody));
const isIssueAssignedToSomeoneElse =
issueAssignees && issueAssignees.length > 0 && !issueAssignees.includes(commentAuthor);
- const isHelpWanted = await hasLabel(
- ISSUE_LABEL_HELP_WANTED,
- owner,
- repo,
- issueNumber,
- github,
- core,
- );
- const commentAuthorIsCloseContributor = await isCloseContributor(commentAuthor, {
- github,
- context,
- core,
- });
+ const [labels, commentAuthorIsCloseContributor] = await Promise.all([
+ getLabels(owner, repo, issueNumber, github, core),
+ isCloseContributor(commentAuthor, { github, context, core }),
+ ]);
+ const isHelpWanted = labels.includes(ISSUE_LABEL_HELP_WANTED.toLowerCase());
+ const isGoodFirstIssue = labels.includes(ISSUE_LABEL_GOOD_FIRST_ISSUE.toLowerCase());
+
+ // Handle /assign command ā early return skips normal flow.
+ // This intentionally bypasses shouldContactSupport so
+ // /assign activity never reaches #support-dev (only
+ // #support-dev-notifications). See docs/community-automations.md.
+ const isAssignCommand = commentBody.trim().toLowerCase() === '/assign';
+ if (isAssignCommand) {
+ await handleAssignCommand({
+ issueNumber,
+ issueUrl,
+ issueTitle,
+ commentAuthor,
+ commentId,
+ issueAssignees,
+ isHelpWanted,
+ isGoodFirstIssue,
+ repo,
+ owner,
+ github,
+ context,
+ core,
+ });
+ return;
+ }
+ const isUnassigned = issueAssignees.length === 0;
const [shouldPostBot, botMessage] = shouldSendBotReply(
issueCreator,
commentAuthor,
@@ -126,6 +301,8 @@ module.exports = async ({ github, context, core }) => {
isHelpWanted,
isAssignmentRequest,
isIssueAssignedToSomeoneElse,
+ isGoodFirstIssue,
+ isUnassigned,
);
if (shouldPostBot) {
// post bot reply only when there are no same bot comments
diff --git a/scripts/contributor-issue-comment.test.js b/scripts/contributor-issue-comment.test.js
new file mode 100644
index 0000000..7feff50
--- /dev/null
+++ b/scripts/contributor-issue-comment.test.js
@@ -0,0 +1,376 @@
+const {
+ BOT_MESSAGE_ISSUE_NOT_OPEN,
+ BOT_MESSAGE_ALREADY_ASSIGNED,
+ BOT_MESSAGE_ASSIGN_SUCCESS,
+ BOT_MESSAGE_ASSIGN_NOT_GOOD_FIRST_ISSUE,
+ MAX_ASSIGNED_ISSUES,
+} = require('./constants');
+const { mockCore } = require('./test-helpers');
+
+function makeContext({
+ issueNumber = 42,
+ issueAssignees = [],
+ commentBody = '/assign',
+ commentAuthor = 'contributor1',
+ issueCreator = 'creator',
+ repo = 'testrepo',
+ owner = 'testorg',
+} = {}) {
+ return {
+ repo: { owner, repo },
+ payload: {
+ issue: {
+ number: issueNumber,
+ html_url: `https://github.com/${owner}/${repo}/issues/${issueNumber}`,
+ title: 'Test Issue',
+ user: { login: issueCreator },
+ assignees: issueAssignees.map(login => ({ login })),
+ },
+ comment: {
+ id: 999,
+ user: { login: commentAuthor },
+ body: commentBody,
+ },
+ },
+ };
+}
+
+function makeGithub({
+ labels = [],
+ assignedIssues = [],
+ unassignmentEvents = [],
+ searchItems = [],
+} = {}) {
+ const github = {
+ paginate: jest.fn().mockImplementation(method => {
+ if (method === github.rest.issues.listLabelsOnIssue) {
+ return Promise.resolve(labels.map(n => ({ name: n })));
+ }
+ if (method === github.rest.issues.listComments) {
+ return Promise.resolve([]);
+ }
+ if (method === github.rest.issues.listForRepo) {
+ return Promise.resolve(assignedIssues);
+ }
+ if (method === github.rest.pulls.list) {
+ return Promise.resolve([]);
+ }
+ if (method === github.rest.issues.listEventsForTimeline) {
+ return Promise.resolve(unassignmentEvents);
+ }
+ return Promise.resolve([]);
+ }),
+ rest: {
+ issues: {
+ listLabelsOnIssue: jest.fn(),
+ listComments: jest.fn(),
+ listForRepo: jest.fn(),
+ listEventsForTimeline: jest.fn(),
+ createComment: jest.fn().mockResolvedValue({
+ data: { html_url: 'https://example.com/comment-url' },
+ }),
+ deleteComment: jest.fn().mockResolvedValue({}),
+ addAssignees: jest.fn().mockResolvedValue({}),
+ },
+ pulls: {
+ list: jest.fn(),
+ },
+ search: {
+ issuesAndPullRequests: jest.fn().mockResolvedValue({
+ data: { items: searchItems },
+ }),
+ },
+ },
+ };
+ return github;
+}
+
+describe('/assign command handling', () => {
+ let script;
+
+ beforeEach(() => {
+ jest.resetModules();
+ script = require('./contributor-issue-comment');
+ });
+
+ test('/assign on non-help-wanted issue sends BOT_MESSAGE_ISSUE_NOT_OPEN', async () => {
+ const core = mockCore();
+ const context = makeContext({ commentBody: '/assign' });
+ const github = makeGithub({ labels: [] }); // no help wanted
+
+ await script({ github, context, core });
+
+ expect(github.rest.issues.createComment).toHaveBeenCalledWith(
+ expect.objectContaining({
+ body: BOT_MESSAGE_ISSUE_NOT_OPEN,
+ }),
+ );
+ expect(core._outputs).toHaveProperty('support_dev_notifications_message');
+ });
+
+ test('/assign when already assigned to commenter is silent no-op', async () => {
+ const core = mockCore();
+ const context = makeContext({
+ commentBody: '/assign',
+ issueAssignees: ['contributor1'],
+ commentAuthor: 'contributor1',
+ });
+ const github = makeGithub({
+ labels: ['help wanted', 'good first issue'],
+ });
+
+ await script({ github, context, core });
+
+ expect(github.rest.issues.createComment).not.toHaveBeenCalled();
+ expect(github.rest.issues.addAssignees).not.toHaveBeenCalled();
+ expect(core.info).toHaveBeenCalledWith(expect.stringContaining('already assigned'));
+ });
+
+ test('/assign when assigned to someone else sends BOT_MESSAGE_ALREADY_ASSIGNED', async () => {
+ const core = mockCore();
+ const context = makeContext({
+ commentBody: '/assign',
+ issueAssignees: ['other-person'],
+ });
+ const github = makeGithub({
+ labels: ['help wanted', 'good first issue'],
+ });
+
+ await script({ github, context, core });
+
+ expect(github.rest.issues.createComment).toHaveBeenCalledWith(
+ expect.objectContaining({
+ body: BOT_MESSAGE_ALREADY_ASSIGNED,
+ }),
+ );
+ });
+
+ test('/assign on help-wanted but not GFI sends BOT_MESSAGE_ASSIGN_NOT_GOOD_FIRST_ISSUE', async () => {
+ const core = mockCore();
+ const context = makeContext({ commentBody: '/assign' });
+ const github = makeGithub({
+ labels: ['help wanted'], // no 'good first issue'
+ });
+
+ await script({ github, context, core });
+
+ expect(github.rest.issues.createComment).toHaveBeenCalledWith(
+ expect.objectContaining({
+ body: BOT_MESSAGE_ASSIGN_NOT_GOOD_FIRST_ISSUE,
+ }),
+ );
+ });
+
+ test('/assign success: assigns user and posts BOT_MESSAGE_ASSIGN_SUCCESS', async () => {
+ const core = mockCore();
+ const context = makeContext({ commentBody: '/assign' });
+ const github = makeGithub({
+ labels: ['help wanted', 'good first issue'],
+ assignedIssues: [], // under limit
+ });
+
+ await script({ github, context, core });
+
+ expect(github.rest.issues.addAssignees).toHaveBeenCalledWith(
+ expect.objectContaining({
+ assignees: ['contributor1'],
+ issue_number: 42,
+ }),
+ );
+ expect(github.rest.issues.createComment).toHaveBeenCalledWith(
+ expect.objectContaining({
+ body: BOT_MESSAGE_ASSIGN_SUCCESS,
+ }),
+ );
+ expect(core._outputs).toHaveProperty('support_dev_notifications_bot');
+ });
+
+ test('/assign at limit declines with dynamic message', async () => {
+ const core = mockCore();
+ const context = makeContext({ commentBody: '/assign' });
+ const github = makeGithub({
+ labels: ['help wanted', 'good first issue'],
+ assignedIssues: [
+ {
+ html_url: 'https://github.com/org/repo1/issues/1',
+ number: 1,
+ },
+ {
+ html_url: 'https://github.com/org/repo2/issues/2',
+ number: 2,
+ },
+ ],
+ });
+
+ await script({ github, context, core });
+
+ expect(github.rest.issues.addAssignees).not.toHaveBeenCalled();
+ // Should post a message containing the limit number
+ expect(github.rest.issues.createComment).toHaveBeenCalledWith(
+ expect.objectContaining({
+ body: expect.stringContaining(`${MAX_ASSIGNED_ISSUES}-issue limit`),
+ }),
+ );
+ });
+
+ test('/assign at limit via cooldown declines (1 assigned + 1 cooldown)', async () => {
+ const core = mockCore();
+ const context = makeContext({ commentBody: '/assign' });
+ const twoDaysAgo = new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString();
+ const github = makeGithub({
+ labels: ['help wanted', 'good first issue'],
+ assignedIssues: [
+ {
+ html_url: 'https://github.com/org/repo1/issues/1',
+ number: 1,
+ },
+ ],
+ searchItems: [
+ {
+ number: 5,
+ html_url: 'https://github.com/org/repo2/issues/5',
+ title: 'Dropped issue',
+ },
+ ],
+ unassignmentEvents: [
+ {
+ event: 'unassigned',
+ assignee: { login: 'contributor1' },
+ created_at: twoDaysAgo,
+ },
+ ],
+ });
+
+ await script({ github, context, core });
+
+ expect(github.rest.issues.addAssignees).not.toHaveBeenCalled();
+ expect(github.rest.issues.createComment).toHaveBeenCalledWith(
+ expect.objectContaining({
+ body: expect.stringContaining(`${MAX_ASSIGNED_ISSUES}-issue limit`),
+ }),
+ );
+ // Should mention cooldown
+ expect(github.rest.issues.createComment).toHaveBeenCalledWith(
+ expect.objectContaining({
+ body: expect.stringContaining('cooldown'),
+ }),
+ );
+ });
+
+ test('/assign is case-insensitive and trims whitespace', async () => {
+ const core = mockCore();
+ const context = makeContext({ commentBody: ' /Assign ' });
+ const github = makeGithub({
+ labels: ['help wanted', 'good first issue'],
+ });
+
+ await script({ github, context, core });
+
+ // Should be treated as /assign command
+ expect(github.rest.issues.addAssignees).toHaveBeenCalled();
+ });
+
+ test('/assign with extra text is NOT treated as /assign command', async () => {
+ const core = mockCore();
+ const context = makeContext({ commentBody: '/assign please' });
+ const github = makeGithub({
+ labels: ['help wanted', 'good first issue'],
+ });
+
+ await script({ github, context, core });
+
+ // Should NOT be treated as /assign ā falls through to normal flow
+ expect(github.rest.issues.addAssignees).not.toHaveBeenCalled();
+ });
+
+ test('/assign routes Slack to support_dev_notifications only', async () => {
+ const core = mockCore();
+ const context = makeContext({ commentBody: '/assign' });
+ const github = makeGithub({
+ labels: ['help wanted', 'good first issue'],
+ });
+
+ await script({ github, context, core });
+
+ // Should set support_dev_notifications_message, NOT support_dev_message
+ expect(core._outputs).toHaveProperty('support_dev_notifications_message');
+ expect(core._outputs).not.toHaveProperty('support_dev_message');
+ });
+});
+
+describe('keyword detection on GFI issues', () => {
+ let script;
+
+ beforeEach(() => {
+ jest.resetModules();
+ script = require('./contributor-issue-comment');
+ });
+
+ test('keyword on unassigned GFI replies with BOT_MESSAGE_KEYWORD_GOOD_FIRST_ISSUE', async () => {
+ const core = mockCore();
+ const context = makeContext({
+ commentBody: 'Can I work on this issue?',
+ commentAuthor: 'newcontrib',
+ issueCreator: 'creator',
+ });
+ const github = makeGithub({
+ labels: ['help wanted', 'good first issue'],
+ });
+
+ await script({ github, context, core });
+
+ const { BOT_MESSAGE_KEYWORD_GOOD_FIRST_ISSUE } = require('./constants');
+ expect(github.rest.issues.createComment).toHaveBeenCalledWith(
+ expect.objectContaining({
+ body: BOT_MESSAGE_KEYWORD_GOOD_FIRST_ISSUE,
+ }),
+ );
+ });
+
+ test('keyword on non-GFI help-wanted issue does NOT send keyword GFI message', async () => {
+ const core = mockCore();
+ const context = makeContext({
+ commentBody: 'Can I work on this issue?',
+ commentAuthor: 'newcontrib',
+ issueCreator: 'creator',
+ });
+ const github = makeGithub({
+ labels: ['help wanted'], // NOT good first issue
+ });
+
+ await script({ github, context, core });
+
+ const { BOT_MESSAGE_KEYWORD_GOOD_FIRST_ISSUE } = require('./constants');
+ // Should NOT send the GFI keyword message
+ if (github.rest.issues.createComment.mock.calls.length > 0) {
+ expect(github.rest.issues.createComment).not.toHaveBeenCalledWith(
+ expect.objectContaining({
+ body: BOT_MESSAGE_KEYWORD_GOOD_FIRST_ISSUE,
+ }),
+ );
+ }
+ });
+
+ test('keyword on GFI when commenter is already assigned does NOT send keyword GFI message', async () => {
+ const core = mockCore();
+ const context = makeContext({
+ commentBody: 'I am working on this issue',
+ commentAuthor: 'newcontrib',
+ issueCreator: 'creator',
+ issueAssignees: ['newcontrib'],
+ });
+ const github = makeGithub({
+ labels: ['help wanted', 'good first issue'],
+ });
+
+ await script({ github, context, core });
+
+ const { BOT_MESSAGE_KEYWORD_GOOD_FIRST_ISSUE } = require('./constants');
+ // Should NOT tell an already-assigned contributor to use /assign
+ expect(github.rest.issues.createComment).not.toHaveBeenCalledWith(
+ expect.objectContaining({
+ body: BOT_MESSAGE_KEYWORD_GOOD_FIRST_ISSUE,
+ }),
+ );
+ });
+});
diff --git a/scripts/good-first-issue-comment.js b/scripts/good-first-issue-comment.js
new file mode 100644
index 0000000..d33609b
--- /dev/null
+++ b/scripts/good-first-issue-comment.js
@@ -0,0 +1,50 @@
+// See docs/community-automations.md
+
+const {
+ LE_BOT_USERNAME,
+ ISSUE_LABEL_HELP_WANTED,
+ ASSIGN_GUIDANCE_MARKER,
+ BOT_MESSAGE_GOOD_FIRST_ISSUE_GUIDANCE,
+} = require('./constants');
+const { sendBotMessage, deleteBotComments, hasLabel } = require('./utils');
+
+module.exports = async ({ github, context, core }) => {
+ try {
+ const owner = context.repo.owner;
+ const repo = context.repo.repo;
+ const issueNumber = context.payload.issue.number;
+
+ // Only post guidance if the issue is also help wanted
+ const isHelpWanted = await hasLabel(
+ ISSUE_LABEL_HELP_WANTED,
+ owner,
+ repo,
+ issueNumber,
+ github,
+ core,
+ );
+
+ if (!isHelpWanted) {
+ core.info(`Issue #${issueNumber} is not help wanted, ` + `skipping guidance comment`);
+ return;
+ }
+
+ // Delete any previous guidance comments
+ await deleteBotComments(issueNumber, LE_BOT_USERNAME, ASSIGN_GUIDANCE_MARKER, {
+ github,
+ context,
+ core,
+ });
+
+ // Post new guidance comment
+ await sendBotMessage(issueNumber, BOT_MESSAGE_GOOD_FIRST_ISSUE_GUIDANCE, {
+ github,
+ context,
+ core,
+ });
+
+ core.info(`Posted guidance comment on issue #${issueNumber}`);
+ } catch (error) {
+ core.setFailed(`Error: ${error.message}`);
+ }
+};
diff --git a/scripts/good-first-issue-comment.test.js b/scripts/good-first-issue-comment.test.js
new file mode 100644
index 0000000..832b122
--- /dev/null
+++ b/scripts/good-first-issue-comment.test.js
@@ -0,0 +1,163 @@
+const {
+ LE_BOT_USERNAME,
+ ASSIGN_GUIDANCE_MARKER,
+ BOT_MESSAGE_GOOD_FIRST_ISSUE_GUIDANCE,
+} = require('./constants');
+const { mockCore } = require('./test-helpers');
+
+function mockContext(issueNumber = 42) {
+ return {
+ repo: { owner: 'testorg', repo: 'testrepo' },
+ payload: { issue: { number: issueNumber } },
+ };
+}
+
+describe('good-first-issue-comment', () => {
+ let script;
+
+ beforeEach(() => {
+ jest.resetModules();
+ script = require('./good-first-issue-comment');
+ });
+
+ test('posts guidance comment on help wanted + good first issue', async () => {
+ const core = mockCore();
+ const context = mockContext();
+ const labels = [{ name: 'help wanted' }, { name: 'good first issue' }];
+
+ const github = {
+ paginate: jest.fn().mockImplementation(method => {
+ if (method === github.rest.issues.listLabelsOnIssue) {
+ return Promise.resolve(labels);
+ }
+ if (method === github.rest.issues.listComments) {
+ return Promise.resolve([]);
+ }
+ return Promise.resolve([]);
+ }),
+ rest: {
+ issues: {
+ listLabelsOnIssue: jest.fn(),
+ listComments: jest.fn(),
+ createComment: jest.fn().mockResolvedValue({
+ data: { html_url: 'https://example.com/comment' },
+ }),
+ deleteComment: jest.fn(),
+ },
+ },
+ };
+
+ await script({ github, context, core });
+
+ expect(github.rest.issues.createComment).toHaveBeenCalledWith(
+ expect.objectContaining({
+ issue_number: 42,
+ body: BOT_MESSAGE_GOOD_FIRST_ISSUE_GUIDANCE,
+ }),
+ );
+ expect(core.info).toHaveBeenCalledWith(expect.stringContaining('Posted guidance comment'));
+ });
+
+ test('skips posting when issue is not help wanted', async () => {
+ const core = mockCore();
+ const context = mockContext();
+ const labels = [{ name: 'good first issue' }];
+
+ const github = {
+ paginate: jest.fn().mockImplementation(method => {
+ if (method === github.rest.issues.listLabelsOnIssue) {
+ return Promise.resolve(labels);
+ }
+ return Promise.resolve([]);
+ }),
+ rest: {
+ issues: {
+ listLabelsOnIssue: jest.fn(),
+ listComments: jest.fn(),
+ createComment: jest.fn(),
+ deleteComment: jest.fn(),
+ },
+ },
+ };
+
+ await script({ github, context, core });
+
+ expect(github.rest.issues.createComment).not.toHaveBeenCalled();
+ expect(core.info).toHaveBeenCalledWith(expect.stringContaining('not help wanted'));
+ });
+
+ test('deletes previous guidance comments before posting new one', async () => {
+ const core = mockCore();
+ const context = mockContext();
+ const labels = [{ name: 'help wanted' }, { name: 'good first issue' }];
+ const existingComments = [
+ {
+ id: 100,
+ user: { login: LE_BOT_USERNAME },
+ body: `${ASSIGN_GUIDANCE_MARKER}\n\nOld guidance`,
+ },
+ {
+ id: 101,
+ user: { login: 'someone' },
+ body: 'A regular comment',
+ },
+ ];
+
+ const github = {
+ paginate: jest.fn().mockImplementation(method => {
+ if (method === github.rest.issues.listLabelsOnIssue) {
+ return Promise.resolve(labels);
+ }
+ if (method === github.rest.issues.listComments) {
+ return Promise.resolve(existingComments);
+ }
+ return Promise.resolve([]);
+ }),
+ rest: {
+ issues: {
+ listLabelsOnIssue: jest.fn(),
+ listComments: jest.fn(),
+ createComment: jest.fn().mockResolvedValue({
+ data: { html_url: 'https://example.com/comment' },
+ }),
+ deleteComment: jest.fn().mockResolvedValue({}),
+ },
+ },
+ };
+
+ await script({ github, context, core });
+
+ // Should delete only the bot's guidance comment
+ expect(github.rest.issues.deleteComment).toHaveBeenCalledWith(
+ expect.objectContaining({ comment_id: 100 }),
+ );
+ expect(github.rest.issues.deleteComment).toHaveBeenCalledTimes(1);
+ // Should still post new guidance
+ expect(github.rest.issues.createComment).toHaveBeenCalled();
+ });
+
+ test('calls setFailed on error', async () => {
+ const core = mockCore();
+ // Missing payload.issue causes a TypeError in the script
+ const context = {
+ repo: { owner: 'testorg', repo: 'testrepo' },
+ payload: {},
+ };
+
+ const github = {
+ paginate: jest.fn(),
+ rest: {
+ issues: {
+ listLabelsOnIssue: jest.fn(),
+ listComments: jest.fn(),
+ createComment: jest.fn(),
+ deleteComment: jest.fn(),
+ },
+ },
+ };
+
+ await script({ github, context, core });
+
+ expect(core.setFailed).toHaveBeenCalledWith(expect.stringContaining('Error'));
+ });
+});
diff --git a/scripts/test-helpers.js b/scripts/test-helpers.js
new file mode 100644
index 0000000..2b5eabb
--- /dev/null
+++ b/scripts/test-helpers.js
@@ -0,0 +1,18 @@
+/**
+ * Shared test helper factories for mock GitHub Actions objects.
+ */
+
+function mockCore() {
+ const outputs = {};
+ return {
+ info: jest.fn(),
+ warning: jest.fn(),
+ setFailed: jest.fn(),
+ setOutput: jest.fn((key, val) => {
+ outputs[key] = val;
+ }),
+ _outputs: outputs,
+ };
+}
+
+module.exports = { mockCore };
diff --git a/scripts/utils.js b/scripts/utils.js
index c9e4510..7825ab9 100644
--- a/scripts/utils.js
+++ b/scripts/utils.js
@@ -171,22 +171,28 @@ async function hasRecentBotComment(
}
/**
- * Checks if an issue has a label with the given name (case-insensitive).
+ * Fetches all label names for an issue. Returns an array of lowercase label strings.
*/
-async function hasLabel(name, owner, repo, issueNumber, github, core) {
- let labels = [];
+async function getLabels(owner, repo, issueNumber, github, core) {
try {
const allLabels = await github.paginate(github.rest.issues.listLabelsOnIssue, {
owner,
repo,
issue_number: issueNumber,
});
- labels = allLabels.map(label => label.name);
+ return allLabels.map(label => label.name.toLowerCase());
} catch (error) {
core.warning(`Failed to fetch labels on issue #${issueNumber}: ${error.message}`);
- labels = [];
+ return [];
}
- return labels.some(label => label.toLowerCase() === name.toLowerCase());
+}
+
+/**
+ * Checks if an issue has a label with the given name (case-insensitive).
+ */
+async function hasLabel(name, owner, repo, issueNumber, github, core) {
+ const labels = await getLabels(owner, repo, issueNumber, github, core);
+ return labels.includes(name.toLowerCase());
}
/**
@@ -234,6 +240,102 @@ async function getPullRequests(author, state, owner, repos, github, core) {
return results.flat();
}
+/**
+ * Deletes bot comments on an issue that contain a specific marker string.
+ */
+async function deleteBotComments(issueNumber, botUsername, marker, { github, context, core }) {
+ const owner = context.repo.owner;
+ const repo = context.repo.repo;
+
+ try {
+ const comments = await github.paginate(github.rest.issues.listComments, {
+ owner,
+ repo,
+ issue_number: issueNumber,
+ });
+
+ for (const comment of comments) {
+ if (comment.user?.login === botUsername && comment.body?.includes(marker)) {
+ await github.rest.issues.deleteComment({
+ owner,
+ repo,
+ comment_id: comment.id,
+ });
+ core.info(`Deleted bot comment ${comment.id} on issue #${issueNumber}`);
+ }
+ }
+ } catch (error) {
+ core.warning(`Failed to delete bot comments on #${issueNumber}: ` + error.message);
+ }
+}
+
+/**
+ * Finds recent unassignment events for a user across repos.
+ * Uses the search API to find candidate issues, then checks
+ * timeline events for unassigned events within the cutoff.
+ */
+async function getRecentUnassignments(username, daysAgo, owner, repos, github, core) {
+ const cutoff = new Date(Date.now() - daysAgo * 24 * 60 * 60 * 1000);
+ const since = cutoff.toISOString().split('T')[0];
+
+ const promises = repos.map(async repo => {
+ const repoUnassignments = [];
+ try {
+ const q = `involves:${username} repo:${owner}/${repo} ` + `is:issue updated:>=${since}`;
+ const { data } = await github.rest.search.issuesAndPullRequests({ q });
+
+ for (const issue of data.items || []) {
+ try {
+ const events = await github.paginate(github.rest.issues.listEventsForTimeline, {
+ owner,
+ repo,
+ issue_number: issue.number,
+ per_page: 100,
+ });
+
+ for (const event of events) {
+ if (
+ event.event === 'unassigned' &&
+ event.assignee?.login?.toLowerCase() === username.toLowerCase() &&
+ new Date(event.created_at) >= cutoff
+ ) {
+ repoUnassignments.push({
+ repo,
+ issueNumber: issue.number,
+ issueUrl: issue.html_url,
+ issueTitle: issue.title,
+ unassignedAt: event.created_at,
+ });
+ }
+ }
+ } catch (tlError) {
+ core.warning(
+ `Failed to fetch timeline for ` + `${repo}#${issue.number}: ${tlError.message}`,
+ );
+ }
+ }
+ } catch (error) {
+ core.warning(`Failed to search issues in ${repo}: ${error.message}`);
+ }
+ return repoUnassignments;
+ });
+
+ const results = await Promise.all(promises);
+ const unassignments = results.flat();
+
+ // Deduplicate by issueUrl, keeping the most recent unassignment event.
+ // A user could be assigned/unassigned multiple times on the same issue
+ // within the cooldown window, and each event should only count once.
+ const byIssue = new Map();
+ for (const u of unassignments) {
+ const existing = byIssue.get(u.issueUrl);
+ if (!existing || new Date(u.unassignedAt) > new Date(existing.unassignedAt)) {
+ byIssue.set(u.issueUrl, u);
+ }
+ }
+ return [...byIssue.values()];
+}
+
module.exports = {
isContributor,
isCloseContributor,
@@ -241,7 +343,10 @@ module.exports = {
sendBotMessage,
escapeIssueTitleForSlackMessage,
hasRecentBotComment,
+ getLabels,
hasLabel,
getIssues,
getPullRequests,
+ deleteBotComments,
+ getRecentUnassignments,
};
diff --git a/scripts/utils.test.js b/scripts/utils.test.js
new file mode 100644
index 0000000..53e3a8d
--- /dev/null
+++ b/scripts/utils.test.js
@@ -0,0 +1,344 @@
+const { deleteBotComments, getRecentUnassignments } = require('./utils');
+const { mockCore } = require('./test-helpers');
+
+// Helper to create mock context
+function mockContext(owner = 'testorg', repo = 'testrepo') {
+ return {
+ repo: { owner, repo },
+ };
+}
+
+describe('deleteBotComments', () => {
+ test('deletes comments from bot that contain marker', async () => {
+ const core = mockCore();
+ const context = mockContext();
+ const github = {
+ paginate: jest.fn().mockResolvedValue([
+ {
+ id: 1,
+ user: { login: 'le-bot' },
+ body: ' guidance text',
+ },
+ {
+ id: 2,
+ user: { login: 'someone-else' },
+ body: ' other text',
+ },
+ {
+ id: 3,
+ user: { login: 'le-bot' },
+ body: 'regular comment without marker',
+ },
+ ]),
+ rest: {
+ issues: {
+ listComments: jest.fn(),
+ deleteComment: jest.fn().mockResolvedValue({}),
+ },
+ },
+ };
+
+ await deleteBotComments(42, 'le-bot', '', {
+ github,
+ context,
+ core,
+ });
+
+ // Should only delete comment 1 (bot + marker)
+ expect(github.rest.issues.deleteComment).toHaveBeenCalledTimes(1);
+ expect(github.rest.issues.deleteComment).toHaveBeenCalledWith({
+ owner: 'testorg',
+ repo: 'testrepo',
+ comment_id: 1,
+ });
+ expect(core.info).toHaveBeenCalled();
+ });
+
+ test('handles API errors gracefully with warning', async () => {
+ const core = mockCore();
+ const context = mockContext();
+ const github = {
+ paginate: jest.fn().mockRejectedValue(new Error('API error')),
+ rest: { issues: { listComments: jest.fn() } },
+ };
+
+ await deleteBotComments(42, 'le-bot', '', {
+ github,
+ context,
+ core,
+ });
+
+ expect(core.warning).toHaveBeenCalledWith(
+ expect.stringContaining('Failed to delete bot comments'),
+ );
+ });
+
+ test('does nothing when no matching comments exist', async () => {
+ const core = mockCore();
+ const context = mockContext();
+ const github = {
+ paginate: jest.fn().mockResolvedValue([
+ {
+ id: 1,
+ user: { login: 'someone' },
+ body: 'unrelated comment',
+ },
+ ]),
+ rest: {
+ issues: {
+ listComments: jest.fn(),
+ deleteComment: jest.fn(),
+ },
+ },
+ };
+
+ await deleteBotComments(42, 'le-bot', '', {
+ github,
+ context,
+ core,
+ });
+
+ expect(github.rest.issues.deleteComment).not.toHaveBeenCalled();
+ });
+});
+
+describe('getRecentUnassignments', () => {
+ test('finds unassignment events within cutoff window', async () => {
+ const core = mockCore();
+ const now = Date.now();
+ const twoDaysAgo = new Date(now - 2 * 24 * 60 * 60 * 1000).toISOString();
+
+ const github = {
+ rest: {
+ search: {
+ issuesAndPullRequests: jest.fn().mockResolvedValue({
+ data: {
+ items: [
+ {
+ number: 10,
+ html_url: 'https://github.com/org/repo1/issues/10',
+ title: 'Test issue',
+ },
+ ],
+ },
+ }),
+ },
+ issues: {
+ listEventsForTimeline: jest.fn(),
+ },
+ },
+ paginate: jest.fn().mockResolvedValue([
+ {
+ event: 'unassigned',
+ assignee: { login: 'testuser' },
+ created_at: twoDaysAgo,
+ },
+ {
+ event: 'assigned',
+ assignee: { login: 'testuser' },
+ created_at: twoDaysAgo,
+ },
+ ]),
+ };
+
+ const result = await getRecentUnassignments('testuser', 7, 'org', ['repo1'], github, core);
+
+ expect(result).toHaveLength(1);
+ expect(result[0]).toEqual({
+ repo: 'repo1',
+ issueNumber: 10,
+ issueUrl: 'https://github.com/org/repo1/issues/10',
+ issueTitle: 'Test issue',
+ unassignedAt: twoDaysAgo,
+ });
+ });
+
+ test('ignores unassignment events outside cutoff window', async () => {
+ const core = mockCore();
+ const tenDaysAgo = new Date(Date.now() - 10 * 24 * 60 * 60 * 1000).toISOString();
+
+ const github = {
+ rest: {
+ search: {
+ issuesAndPullRequests: jest.fn().mockResolvedValue({
+ data: {
+ items: [
+ {
+ number: 10,
+ html_url: 'https://github.com/org/repo1/issues/10',
+ title: 'Old issue',
+ },
+ ],
+ },
+ }),
+ },
+ issues: {
+ listEventsForTimeline: jest.fn(),
+ },
+ },
+ paginate: jest.fn().mockResolvedValue([
+ {
+ event: 'unassigned',
+ assignee: { login: 'testuser' },
+ created_at: tenDaysAgo,
+ },
+ ]),
+ };
+
+ const result = await getRecentUnassignments('testuser', 7, 'org', ['repo1'], github, core);
+
+ expect(result).toHaveLength(0);
+ });
+
+ test('case-insensitive username matching', async () => {
+ const core = mockCore();
+ const twoDaysAgo = new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString();
+
+ const github = {
+ rest: {
+ search: {
+ issuesAndPullRequests: jest.fn().mockResolvedValue({
+ data: {
+ items: [
+ {
+ number: 5,
+ html_url: 'https://github.com/org/repo1/issues/5',
+ title: 'Case test',
+ },
+ ],
+ },
+ }),
+ },
+ issues: {
+ listEventsForTimeline: jest.fn(),
+ },
+ },
+ paginate: jest.fn().mockResolvedValue([
+ {
+ event: 'unassigned',
+ assignee: { login: 'TestUser' },
+ created_at: twoDaysAgo,
+ },
+ ]),
+ };
+
+ const result = await getRecentUnassignments('testuser', 7, 'org', ['repo1'], github, core);
+
+ expect(result).toHaveLength(1);
+ });
+
+ test('handles search API errors gracefully', async () => {
+ const core = mockCore();
+ const github = {
+ rest: {
+ search: {
+ issuesAndPullRequests: jest.fn().mockRejectedValue(new Error('Search failed')),
+ },
+ issues: {
+ listEventsForTimeline: jest.fn(),
+ },
+ },
+ paginate: jest.fn(),
+ };
+
+ const result = await getRecentUnassignments('testuser', 7, 'org', ['repo1'], github, core);
+
+ expect(result).toEqual([]);
+ expect(core.warning).toHaveBeenCalledWith(expect.stringContaining('Failed to search issues'));
+ });
+
+ test('searches across multiple repos', async () => {
+ const core = mockCore();
+ const twoDaysAgo = new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString();
+ let callCount = 0;
+
+ const github = {
+ rest: {
+ search: {
+ issuesAndPullRequests: jest.fn().mockImplementation(() => {
+ callCount++;
+ return Promise.resolve({
+ data: {
+ items: [
+ {
+ number: callCount,
+ html_url: `https://github.com/org/repo${callCount}/issues/${callCount}`,
+ title: `Issue in repo${callCount}`,
+ },
+ ],
+ },
+ });
+ }),
+ },
+ issues: {
+ listEventsForTimeline: jest.fn(),
+ },
+ },
+ paginate: jest.fn().mockResolvedValue([
+ {
+ event: 'unassigned',
+ assignee: { login: 'testuser' },
+ created_at: twoDaysAgo,
+ },
+ ]),
+ };
+
+ const result = await getRecentUnassignments(
+ 'testuser',
+ 7,
+ 'org',
+ ['repo1', 'repo2'],
+ github,
+ core,
+ );
+
+ expect(github.rest.search.issuesAndPullRequests).toHaveBeenCalledTimes(2);
+ // Both repos return distinct results
+ expect(result).toHaveLength(2);
+ });
+
+ test('deduplicates multiple unassignment events for the same issue', async () => {
+ const core = mockCore();
+ const twoDaysAgo = new Date(Date.now() - 2 * 24 * 60 * 60 * 1000).toISOString();
+ const oneDayAgo = new Date(Date.now() - 1 * 24 * 60 * 60 * 1000).toISOString();
+
+ const github = {
+ rest: {
+ search: {
+ issuesAndPullRequests: jest.fn().mockResolvedValue({
+ data: {
+ items: [
+ {
+ number: 10,
+ html_url: 'https://github.com/org/repo1/issues/10',
+ title: 'Reassigned issue',
+ },
+ ],
+ },
+ }),
+ },
+ issues: {
+ listEventsForTimeline: jest.fn(),
+ },
+ },
+ paginate: jest.fn().mockResolvedValue([
+ {
+ event: 'unassigned',
+ assignee: { login: 'testuser' },
+ created_at: twoDaysAgo,
+ },
+ {
+ event: 'unassigned',
+ assignee: { login: 'testuser' },
+ created_at: oneDayAgo,
+ },
+ ]),
+ };
+
+ const result = await getRecentUnassignments('testuser', 7, 'org', ['repo1'], github, core);
+
+ // Should deduplicate to 1 entry, keeping the most recent
+ expect(result).toHaveLength(1);
+ expect(result[0].unassignedAt).toBe(oneDayAgo);
+ });
+});
diff --git a/yarn.lock b/yarn.lock
index 6208faa..eaf4f8c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,21 +2,289 @@
# yarn lockfile v1
+"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.27.1", "@babel/code-frame@^7.28.6", "@babel/code-frame@^7.29.0":
+ version "7.29.0"
+ resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz"
+ integrity sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.28.5"
+ js-tokens "^4.0.0"
+ picocolors "^1.1.1"
+
+"@babel/compat-data@^7.28.6":
+ version "7.29.0"
+ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz"
+ integrity sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==
+
+"@babel/core@^7.0.0", "@babel/core@^7.0.0 || ^8.0.0-0", "@babel/core@^7.0.0-0", "@babel/core@^7.11.0 || ^8.0.0-0", "@babel/core@^7.11.0 || ^8.0.0-beta.1", "@babel/core@^7.23.9", "@babel/core@^7.27.4":
+ version "7.29.0"
+ resolved "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz"
+ integrity sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==
+ dependencies:
+ "@babel/code-frame" "^7.29.0"
+ "@babel/generator" "^7.29.0"
+ "@babel/helper-compilation-targets" "^7.28.6"
+ "@babel/helper-module-transforms" "^7.28.6"
+ "@babel/helpers" "^7.28.6"
+ "@babel/parser" "^7.29.0"
+ "@babel/template" "^7.28.6"
+ "@babel/traverse" "^7.29.0"
+ "@babel/types" "^7.29.0"
+ "@jridgewell/remapping" "^2.3.5"
+ convert-source-map "^2.0.0"
+ debug "^4.1.0"
+ gensync "^1.0.0-beta.2"
+ json5 "^2.2.3"
+ semver "^6.3.1"
+
+"@babel/generator@^7.27.5", "@babel/generator@^7.29.0":
+ version "7.29.1"
+ resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz"
+ integrity sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==
+ dependencies:
+ "@babel/parser" "^7.29.0"
+ "@babel/types" "^7.29.0"
+ "@jridgewell/gen-mapping" "^0.3.12"
+ "@jridgewell/trace-mapping" "^0.3.28"
+ jsesc "^3.0.2"
+
+"@babel/helper-compilation-targets@^7.28.6":
+ version "7.28.6"
+ resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz"
+ integrity sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==
+ dependencies:
+ "@babel/compat-data" "^7.28.6"
+ "@babel/helper-validator-option" "^7.27.1"
+ browserslist "^4.24.0"
+ lru-cache "^5.1.1"
+ semver "^6.3.1"
+
+"@babel/helper-globals@^7.28.0":
+ version "7.28.0"
+ resolved "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz"
+ integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==
+
+"@babel/helper-module-imports@^7.28.6":
+ version "7.28.6"
+ resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz"
+ integrity sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==
+ dependencies:
+ "@babel/traverse" "^7.28.6"
+ "@babel/types" "^7.28.6"
+
+"@babel/helper-module-transforms@^7.28.6":
+ version "7.28.6"
+ resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz"
+ integrity sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==
+ dependencies:
+ "@babel/helper-module-imports" "^7.28.6"
+ "@babel/helper-validator-identifier" "^7.28.5"
+ "@babel/traverse" "^7.28.6"
+
+"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.28.6", "@babel/helper-plugin-utils@^7.8.0":
+ version "7.28.6"
+ resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz"
+ integrity sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==
+
+"@babel/helper-string-parser@^7.27.1":
+ version "7.27.1"
+ resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz"
+ integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==
+
+"@babel/helper-validator-identifier@^7.28.5":
+ version "7.28.5"
+ resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz"
+ integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==
+
+"@babel/helper-validator-option@^7.27.1":
+ version "7.27.1"
+ resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz"
+ integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==
+
+"@babel/helpers@^7.28.6":
+ version "7.29.2"
+ resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz"
+ integrity sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==
+ dependencies:
+ "@babel/template" "^7.28.6"
+ "@babel/types" "^7.29.0"
+
+"@babel/parser@^7.1.0", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.28.6", "@babel/parser@^7.29.0":
+ version "7.29.2"
+ resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz"
+ integrity sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==
+ dependencies:
+ "@babel/types" "^7.29.0"
+
+"@babel/plugin-syntax-async-generators@^7.8.4":
+ 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==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-bigint@^7.8.3":
+ 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==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-class-properties@^7.12.13":
+ 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==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.12.13"
+
+"@babel/plugin-syntax-class-static-block@^7.14.5":
+ 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==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.14.5"
+
+"@babel/plugin-syntax-import-attributes@^7.24.7":
+ version "7.28.6"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz"
+ integrity sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.28.6"
+
+"@babel/plugin-syntax-import-meta@^7.10.4":
+ 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==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-syntax-json-strings@^7.8.3":
+ 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==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-jsx@^7.27.1":
+ version "7.28.6"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz"
+ integrity sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.28.6"
+
+"@babel/plugin-syntax-logical-assignment-operators@^7.10.4":
+ 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==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3":
+ 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==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-numeric-separator@^7.10.4":
+ 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==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-syntax-object-rest-spread@^7.8.3":
+ 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==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-optional-catch-binding@^7.8.3":
+ 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==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-optional-chaining@^7.8.3":
+ 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==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-private-property-in-object@^7.14.5":
+ 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==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.14.5"
+
+"@babel/plugin-syntax-top-level-await@^7.14.5":
+ 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==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.14.5"
+
+"@babel/plugin-syntax-typescript@^7.27.1":
+ version "7.28.6"
+ resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz"
+ integrity sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.28.6"
+
+"@babel/template@^7.28.6":
+ version "7.28.6"
+ resolved "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz"
+ integrity sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==
+ dependencies:
+ "@babel/code-frame" "^7.28.6"
+ "@babel/parser" "^7.28.6"
+ "@babel/types" "^7.28.6"
+
+"@babel/traverse@^7.28.6", "@babel/traverse@^7.29.0":
+ version "7.29.0"
+ resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz"
+ integrity sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==
+ dependencies:
+ "@babel/code-frame" "^7.29.0"
+ "@babel/generator" "^7.29.0"
+ "@babel/helper-globals" "^7.28.0"
+ "@babel/parser" "^7.29.0"
+ "@babel/template" "^7.28.6"
+ "@babel/types" "^7.29.0"
+ debug "^4.3.1"
+
+"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.27.3", "@babel/types@^7.28.2", "@babel/types@^7.28.6", "@babel/types@^7.29.0":
+ version "7.29.0"
+ resolved "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz"
+ integrity sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==
+ dependencies:
+ "@babel/helper-string-parser" "^7.27.1"
+ "@babel/helper-validator-identifier" "^7.28.5"
+
+"@bcoe/v8-coverage@^0.2.3":
+ version "0.2.3"
+ resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz"
+ integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
+
"@eslint-community/eslint-utils@^4.2.0":
version "4.9.0"
- resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz#7308df158e064f0dd8b8fdb58aa14fa2a7f913b3"
+ resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz"
integrity sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==
dependencies:
eslint-visitor-keys "^3.4.3"
"@eslint-community/regexpp@^4.6.1":
version "4.12.2"
- resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.2.tgz#bccdf615bcf7b6e8db830ec0b8d21c9a25de597b"
+ resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz"
integrity sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==
"@eslint/eslintrc@^2.1.4":
version "2.1.4"
- resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad"
+ resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz"
integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==
dependencies:
ajv "^6.12.4"
@@ -31,12 +299,12 @@
"@eslint/js@8.57.1":
version "8.57.1"
- resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2"
+ resolved "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz"
integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==
"@humanwhocodes/config-array@^0.13.0":
version "0.13.0"
- resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748"
+ resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz"
integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==
dependencies:
"@humanwhocodes/object-schema" "^2.0.3"
@@ -50,12 +318,292 @@
"@humanwhocodes/object-schema@^2.0.3":
version "2.0.3"
- resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3"
+ resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz"
integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==
+"@isaacs/cliui@^8.0.2":
+ version "8.0.2"
+ resolved "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz"
+ integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==
+ dependencies:
+ string-width "^5.1.2"
+ string-width-cjs "npm:string-width@^4.2.0"
+ strip-ansi "^7.0.1"
+ strip-ansi-cjs "npm:strip-ansi@^6.0.1"
+ wrap-ansi "^8.1.0"
+ wrap-ansi-cjs "npm:wrap-ansi@^7.0.0"
+
+"@istanbuljs/load-nyc-config@^1.0.0":
+ version "1.1.0"
+ resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz"
+ integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==
+ 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"
+
+"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3":
+ version "0.1.3"
+ resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz"
+ integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==
+
+"@jest/console@30.3.0":
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/@jest/console/-/console-30.3.0.tgz"
+ integrity sha512-PAwCvFJ4696XP2qZj+LAn1BWjZaJ6RjG6c7/lkMaUJnkyMS34ucuIsfqYvfskVNvUI27R/u4P1HMYFnlVXG/Ww==
+ dependencies:
+ "@jest/types" "30.3.0"
+ "@types/node" "*"
+ chalk "^4.1.2"
+ jest-message-util "30.3.0"
+ jest-util "30.3.0"
+ slash "^3.0.0"
+
+"@jest/core@30.3.0":
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/@jest/core/-/core-30.3.0.tgz"
+ integrity sha512-U5mVPsBxLSO6xYbf+tgkymLx+iAhvZX43/xI1+ej2ZOPnPdkdO1CzDmFKh2mZBn2s4XZixszHeQnzp1gm/DIxw==
+ dependencies:
+ "@jest/console" "30.3.0"
+ "@jest/pattern" "30.0.1"
+ "@jest/reporters" "30.3.0"
+ "@jest/test-result" "30.3.0"
+ "@jest/transform" "30.3.0"
+ "@jest/types" "30.3.0"
+ "@types/node" "*"
+ ansi-escapes "^4.3.2"
+ chalk "^4.1.2"
+ ci-info "^4.2.0"
+ exit-x "^0.2.2"
+ graceful-fs "^4.2.11"
+ jest-changed-files "30.3.0"
+ jest-config "30.3.0"
+ jest-haste-map "30.3.0"
+ jest-message-util "30.3.0"
+ jest-regex-util "30.0.1"
+ jest-resolve "30.3.0"
+ jest-resolve-dependencies "30.3.0"
+ jest-runner "30.3.0"
+ jest-runtime "30.3.0"
+ jest-snapshot "30.3.0"
+ jest-util "30.3.0"
+ jest-validate "30.3.0"
+ jest-watcher "30.3.0"
+ pretty-format "30.3.0"
+ slash "^3.0.0"
+
+"@jest/diff-sequences@30.3.0":
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.3.0.tgz"
+ integrity sha512-cG51MVnLq1ecVUaQ3fr6YuuAOitHK1S4WUJHnsPFE/quQr33ADUx1FfrTCpMCRxvy0Yr9BThKpDjSlcTi91tMA==
+
+"@jest/environment@30.3.0":
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/@jest/environment/-/environment-30.3.0.tgz"
+ integrity sha512-SlLSF4Be735yQXyh2+mctBOzNDx5s5uLv88/j8Qn1wH679PDcwy67+YdADn8NJnGjzlXtN62asGH/T4vWOkfaw==
+ dependencies:
+ "@jest/fake-timers" "30.3.0"
+ "@jest/types" "30.3.0"
+ "@types/node" "*"
+ jest-mock "30.3.0"
+
+"@jest/expect-utils@30.3.0":
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.3.0.tgz"
+ integrity sha512-j0+W5iQQ8hBh7tHZkTQv3q2Fh/M7Je72cIsYqC4OaktgtO7v1So9UTjp6uPBHIaB6beoF/RRsCgMJKvti0wADA==
+ dependencies:
+ "@jest/get-type" "30.1.0"
+
+"@jest/expect@30.3.0":
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/@jest/expect/-/expect-30.3.0.tgz"
+ integrity sha512-76Nlh4xJxk2D/9URCn3wFi98d2hb19uWE1idLsTt2ywhvdOldbw3S570hBgn25P4ICUZ/cBjybrBex2g17IDbg==
+ dependencies:
+ expect "30.3.0"
+ jest-snapshot "30.3.0"
+
+"@jest/fake-timers@30.3.0":
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.3.0.tgz"
+ integrity sha512-WUQDs8SOP9URStX1DzhD425CqbN/HxUYCTwVrT8sTVBfMvFqYt/s61EK5T05qnHu0po6RitXIvP9otZxYDzTGQ==
+ dependencies:
+ "@jest/types" "30.3.0"
+ "@sinonjs/fake-timers" "^15.0.0"
+ "@types/node" "*"
+ jest-message-util "30.3.0"
+ jest-mock "30.3.0"
+ jest-util "30.3.0"
+
+"@jest/get-type@30.1.0":
+ version "30.1.0"
+ resolved "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz"
+ integrity sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==
+
+"@jest/globals@30.3.0":
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/@jest/globals/-/globals-30.3.0.tgz"
+ integrity sha512-+owLCBBdfpgL3HU+BD5etr1SvbXpSitJK0is1kiYjJxAAJggYMRQz5hSdd5pq1sSggfxPbw2ld71pt4x5wwViA==
+ dependencies:
+ "@jest/environment" "30.3.0"
+ "@jest/expect" "30.3.0"
+ "@jest/types" "30.3.0"
+ jest-mock "30.3.0"
+
+"@jest/pattern@30.0.1":
+ version "30.0.1"
+ resolved "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz"
+ integrity sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==
+ dependencies:
+ "@types/node" "*"
+ jest-regex-util "30.0.1"
+
+"@jest/reporters@30.3.0":
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-30.3.0.tgz"
+ integrity sha512-a09z89S+PkQnL055bVj8+pe2Caed2PBOaczHcXCykW5ngxX9EWx/1uAwncxc/HiU0oZqfwseMjyhxgRjS49qPw==
+ dependencies:
+ "@bcoe/v8-coverage" "^0.2.3"
+ "@jest/console" "30.3.0"
+ "@jest/test-result" "30.3.0"
+ "@jest/transform" "30.3.0"
+ "@jest/types" "30.3.0"
+ "@jridgewell/trace-mapping" "^0.3.25"
+ "@types/node" "*"
+ chalk "^4.1.2"
+ collect-v8-coverage "^1.0.2"
+ exit-x "^0.2.2"
+ glob "^10.5.0"
+ graceful-fs "^4.2.11"
+ istanbul-lib-coverage "^3.0.0"
+ istanbul-lib-instrument "^6.0.0"
+ istanbul-lib-report "^3.0.0"
+ istanbul-lib-source-maps "^5.0.0"
+ istanbul-reports "^3.1.3"
+ jest-message-util "30.3.0"
+ jest-util "30.3.0"
+ jest-worker "30.3.0"
+ slash "^3.0.0"
+ string-length "^4.0.2"
+ v8-to-istanbul "^9.0.1"
+
+"@jest/schemas@30.0.5":
+ version "30.0.5"
+ resolved "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz"
+ integrity sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==
+ dependencies:
+ "@sinclair/typebox" "^0.34.0"
+
+"@jest/snapshot-utils@30.3.0":
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.3.0.tgz"
+ integrity sha512-ORbRN9sf5PP82v3FXNSwmO1OTDR2vzR2YTaR+E3VkSBZ8zadQE6IqYdYEeFH1NIkeB2HIGdF02dapb6K0Mj05g==
+ dependencies:
+ "@jest/types" "30.3.0"
+ chalk "^4.1.2"
+ graceful-fs "^4.2.11"
+ natural-compare "^1.4.0"
+
+"@jest/source-map@30.0.1":
+ version "30.0.1"
+ resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz"
+ integrity sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==
+ dependencies:
+ "@jridgewell/trace-mapping" "^0.3.25"
+ callsites "^3.1.0"
+ graceful-fs "^4.2.11"
+
+"@jest/test-result@30.3.0":
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-30.3.0.tgz"
+ integrity sha512-e/52nJGuD74AKTSe0P4y5wFRlaXP0qmrS17rqOMHeSwm278VyNyXE3gFO/4DTGF9w+65ra3lo3VKj0LBrzmgdQ==
+ dependencies:
+ "@jest/console" "30.3.0"
+ "@jest/types" "30.3.0"
+ "@types/istanbul-lib-coverage" "^2.0.6"
+ collect-v8-coverage "^1.0.2"
+
+"@jest/test-sequencer@30.3.0":
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.3.0.tgz"
+ integrity sha512-dgbWy9b8QDlQeRZcv7LNF+/jFiiYHTKho1xirauZ7kVwY7avjFF6uTT0RqlgudB5OuIPagFdVtfFMosjVbk1eA==
+ dependencies:
+ "@jest/test-result" "30.3.0"
+ graceful-fs "^4.2.11"
+ jest-haste-map "30.3.0"
+ slash "^3.0.0"
+
+"@jest/transform@30.3.0":
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/@jest/transform/-/transform-30.3.0.tgz"
+ integrity sha512-TLKY33fSLVd/lKB2YI1pH69ijyUblO/BQvCj566YvnwuzoTNr648iE0j22vRvVNk2HsPwByPxATg3MleS3gf5A==
+ dependencies:
+ "@babel/core" "^7.27.4"
+ "@jest/types" "30.3.0"
+ "@jridgewell/trace-mapping" "^0.3.25"
+ babel-plugin-istanbul "^7.0.1"
+ chalk "^4.1.2"
+ convert-source-map "^2.0.0"
+ fast-json-stable-stringify "^2.1.0"
+ graceful-fs "^4.2.11"
+ jest-haste-map "30.3.0"
+ jest-regex-util "30.0.1"
+ jest-util "30.3.0"
+ pirates "^4.0.7"
+ slash "^3.0.0"
+ write-file-atomic "^5.0.1"
+
+"@jest/types@30.3.0":
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/@jest/types/-/types-30.3.0.tgz"
+ integrity sha512-JHm87k7bA33hpBngtU8h6UBub/fqqA9uXfw+21j5Hmk7ooPHlboRNxHq0JcMtC+n8VJGP1mcfnD3Mk+XKe1oSw==
+ dependencies:
+ "@jest/pattern" "30.0.1"
+ "@jest/schemas" "30.0.5"
+ "@types/istanbul-lib-coverage" "^2.0.6"
+ "@types/istanbul-reports" "^3.0.4"
+ "@types/node" "*"
+ "@types/yargs" "^17.0.33"
+ chalk "^4.1.2"
+
+"@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5":
+ version "0.3.13"
+ resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz"
+ integrity sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==
+ dependencies:
+ "@jridgewell/sourcemap-codec" "^1.5.0"
+ "@jridgewell/trace-mapping" "^0.3.24"
+
+"@jridgewell/remapping@^2.3.5":
+ version "2.3.5"
+ resolved "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz"
+ integrity sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==
+ dependencies:
+ "@jridgewell/gen-mapping" "^0.3.5"
+ "@jridgewell/trace-mapping" "^0.3.24"
+
+"@jridgewell/resolve-uri@^3.1.0":
+ version "3.1.2"
+ resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz"
+ integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==
+
+"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0":
+ version "1.5.5"
+ resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz"
+ integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==
+
+"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.23", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25", "@jridgewell/trace-mapping@^0.3.28":
+ version "0.3.31"
+ resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz"
+ integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==
+ dependencies:
+ "@jridgewell/resolve-uri" "^3.1.0"
+ "@jridgewell/sourcemap-codec" "^1.4.14"
+
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
+ resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz"
integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
dependencies:
"@nodelib/fs.stat" "2.0.5"
@@ -63,30 +611,140 @@
"@nodelib/fs.stat@2.0.5":
version "2.0.5"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
+ resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
"@nodelib/fs.walk@^1.2.8":
version "1.2.8"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
+ resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz"
integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
dependencies:
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
-"@ungap/structured-clone@^1.2.0":
+"@pkgjs/parseargs@^0.11.0":
+ version "0.11.0"
+ resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz"
+ integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
+
+"@pkgr/core@^0.2.9":
+ version "0.2.9"
+ resolved "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz"
+ integrity sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==
+
+"@sinclair/typebox@^0.34.0":
+ version "0.34.48"
+ resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.48.tgz"
+ integrity sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==
+
+"@sinonjs/commons@^3.0.1":
+ version "3.0.1"
+ resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz"
+ integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==
+ dependencies:
+ type-detect "4.0.8"
+
+"@sinonjs/fake-timers@^15.0.0":
+ version "15.1.1"
+ resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.1.1.tgz"
+ integrity sha512-cO5W33JgAPbOh07tvZjUOJ7oWhtaqGHiZw+11DPbyqh2kHTBc3eF/CjJDeQ4205RLQsX6rxCuYOroFQwl7JDRw==
+ dependencies:
+ "@sinonjs/commons" "^3.0.1"
+
+"@types/babel__core@^7.20.5":
+ version "7.20.5"
+ resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz"
+ integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==
+ dependencies:
+ "@babel/parser" "^7.20.7"
+ "@babel/types" "^7.20.7"
+ "@types/babel__generator" "*"
+ "@types/babel__template" "*"
+ "@types/babel__traverse" "*"
+
+"@types/babel__generator@*":
+ version "7.27.0"
+ resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz"
+ integrity sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==
+ dependencies:
+ "@babel/types" "^7.0.0"
+
+"@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==
+ dependencies:
+ "@babel/parser" "^7.1.0"
+ "@babel/types" "^7.0.0"
+
+"@types/babel__traverse@*":
+ version "7.28.0"
+ resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz"
+ integrity sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==
+ dependencies:
+ "@babel/types" "^7.28.2"
+
+"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.1", "@types/istanbul-lib-coverage@^2.0.6":
+ 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==
+
+"@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==
+ dependencies:
+ "@types/istanbul-lib-coverage" "*"
+
+"@types/istanbul-reports@^3.0.4":
+ 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==
+ dependencies:
+ "@types/istanbul-lib-report" "*"
+
+"@types/node@*":
+ version "25.5.0"
+ resolved "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz"
+ integrity sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==
+ dependencies:
+ undici-types "~7.18.0"
+
+"@types/stack-utils@^2.0.3":
+ version "2.0.3"
+ resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz"
+ integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==
+
+"@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==
+
+"@types/yargs@^17.0.33":
+ version "17.0.35"
+ resolved "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz"
+ integrity sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==
+ dependencies:
+ "@types/yargs-parser" "*"
+
+"@ungap/structured-clone@^1.2.0", "@ungap/structured-clone@^1.3.0":
version "1.3.0"
- resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8"
+ resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz"
integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==
+"@unrs/resolver-binding-linux-x64-gnu@1.11.1":
+ version "1.11.1"
+ resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz"
+ integrity sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==
+
acorn-jsx@^5.3.2:
version "5.3.2"
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
-acorn@^8.9.0:
+"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.9.0:
version "8.15.0"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816"
+ resolved "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz"
integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==
agent-base@^7.1.2:
@@ -104,18 +762,55 @@ ajv@^6.12.4:
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
+ansi-escapes@^4.3.2:
+ version "4.3.2"
+ resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz"
+ integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==
+ dependencies:
+ type-fest "^0.21.3"
+
ansi-regex@^5.0.1:
version "5.0.1"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
+ resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz"
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
-ansi-styles@^4.1.0:
+ansi-regex@^6.2.2:
+ version "6.2.2"
+ resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz"
+ integrity sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==
+
+ansi-styles@^4.0.0, ansi-styles@^4.1.0:
version "4.3.0"
resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz"
integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
dependencies:
color-convert "^2.0.1"
+ansi-styles@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz"
+ integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==
+
+ansi-styles@^6.1.0:
+ version "6.2.3"
+ resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz"
+ integrity sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==
+
+anymatch@^3.1.3:
+ version "3.1.3"
+ resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz"
+ integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
+ dependencies:
+ normalize-path "^3.0.0"
+ picomatch "^2.0.4"
+
+argparse@^1.0.7:
+ version "1.0.10"
+ resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz"
+ integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
+ dependencies:
+ sprintf-js "~1.0.2"
+
argparse@^2.0.1:
version "2.0.1"
resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz"
@@ -128,13 +823,73 @@ asynckit@^0.4.0:
axios@^1.13.5:
version "1.13.5"
- resolved "https://registry.yarnpkg.com/axios/-/axios-1.13.5.tgz#5e464688fa127e11a660a2c49441c009f6567a43"
+ resolved "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz"
integrity sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==
dependencies:
follow-redirects "^1.15.11"
form-data "^4.0.5"
proxy-from-env "^1.1.0"
+babel-jest@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-30.3.0.tgz"
+ integrity sha512-gRpauEU2KRrCox5Z296aeVHR4jQ98BCnu0IO332D/xpHNOsIH/bgSRk9k6GbKIbBw8vFeN6ctuu6tV8WOyVfYQ==
+ dependencies:
+ "@jest/transform" "30.3.0"
+ "@types/babel__core" "^7.20.5"
+ babel-plugin-istanbul "^7.0.1"
+ babel-preset-jest "30.3.0"
+ chalk "^4.1.2"
+ graceful-fs "^4.2.11"
+ slash "^3.0.0"
+
+babel-plugin-istanbul@^7.0.1:
+ version "7.0.1"
+ resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz"
+ integrity sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.0.0"
+ "@istanbuljs/load-nyc-config" "^1.0.0"
+ "@istanbuljs/schema" "^0.1.3"
+ istanbul-lib-instrument "^6.0.2"
+ test-exclude "^6.0.0"
+
+babel-plugin-jest-hoist@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.3.0.tgz"
+ integrity sha512-+TRkByhsws6sfPjVaitzadk1I0F5sPvOVUH5tyTSzhePpsGIVrdeunHSw/C36QeocS95OOk8lunc4rlu5Anwsg==
+ dependencies:
+ "@types/babel__core" "^7.20.5"
+
+babel-preset-current-node-syntax@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz"
+ integrity sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==
+ 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"
+
+babel-preset-jest@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.3.0.tgz"
+ integrity sha512-6ZcUbWHC+dMz2vfzdNwi87Z1gQsLNK2uLuK1Q89R11xdvejcivlYYwDlEv0FHX3VwEXpbBQ9uufB/MUNpZGfhQ==
+ dependencies:
+ babel-plugin-jest-hoist "30.3.0"
+ babel-preset-current-node-syntax "^1.2.0"
+
balanced-match@^1.0.0:
version "1.0.2"
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
@@ -145,6 +900,11 @@ base64-js@^1.3.0:
resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
+baseline-browser-mapping@^2.9.0:
+ version "2.10.9"
+ resolved "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.9.tgz"
+ integrity sha512-OZd0e2mU11ClX8+IdXe3r0dbqMEznRiT4TfbhYIbcRPZkqJ7Qwer8ij3GZAmLsRKa+II9V1v5czCkvmHH3XZBg==
+
bignumber.js@^9.0.0:
version "9.3.1"
resolved "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz"
@@ -158,11 +918,41 @@ brace-expansion@^1.1.7:
balanced-match "^1.0.0"
concat-map "0.0.1"
+brace-expansion@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz"
+ integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==
+ dependencies:
+ balanced-match "^1.0.0"
+
+browserslist@^4.24.0, "browserslist@>= 4.21.0":
+ version "4.28.1"
+ resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz"
+ integrity sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==
+ dependencies:
+ baseline-browser-mapping "^2.9.0"
+ caniuse-lite "^1.0.30001759"
+ electron-to-chromium "^1.5.263"
+ node-releases "^2.0.27"
+ update-browserslist-db "^1.2.0"
+
+bser@2.1.1:
+ version "2.1.1"
+ resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz"
+ integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==
+ dependencies:
+ node-int64 "^0.4.0"
+
buffer-equal-constant-time@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz"
integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==
+buffer-from@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz"
+ integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
+
call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz"
@@ -179,12 +969,27 @@ call-bound@^1.0.2:
call-bind-apply-helpers "^1.0.2"
get-intrinsic "^1.3.0"
-callsites@^3.0.0:
+callsites@^3.0.0, callsites@^3.1.0:
version "3.1.0"
resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz"
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
-chalk@^4.0.0:
+camelcase@^5.3.1:
+ version "5.3.1"
+ resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz"
+ integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
+
+camelcase@^6.3.0:
+ version "6.3.0"
+ resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz"
+ integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
+
+caniuse-lite@^1.0.30001759:
+ version "1.0.30001780"
+ resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001780.tgz"
+ integrity sha512-llngX0E7nQci5BPJDqoZSbuZ5Bcs9F5db7EtgfwBerX9XGtkkiO4NwfDDIRzHTTwcYC8vC7bmeUEPGrKlR/TkQ==
+
+chalk@^4.0.0, chalk@^4.1.2:
version "4.1.2"
resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
@@ -192,6 +997,40 @@ chalk@^4.0.0:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
+char-regex@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz"
+ integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==
+
+ci-info@^4.2.0:
+ version "4.4.0"
+ resolved "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz"
+ integrity sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==
+
+cjs-module-lexer@^2.1.0:
+ version "2.2.0"
+ resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz"
+ integrity sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==
+
+cliui@^8.0.1:
+ 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==
+ dependencies:
+ string-width "^4.2.0"
+ strip-ansi "^6.0.1"
+ wrap-ansi "^7.0.0"
+
+co@^4.6.0:
+ version "4.6.0"
+ resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz"
+ integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==
+
+collect-v8-coverage@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz"
+ integrity sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==
+
color-convert@^2.0.1:
version "2.0.1"
resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz"
@@ -216,42 +1055,62 @@ concat-map@0.0.1:
resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
-cross-spawn@^7.0.2:
+convert-source-map@^2.0.0:
+ 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==
+
+cross-spawn@^7.0.2, cross-spawn@^7.0.3, cross-spawn@^7.0.6:
version "7.0.6"
- resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
+ resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz"
integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
dependencies:
path-key "^3.1.0"
shebang-command "^2.0.0"
which "^2.0.1"
-debug@4, debug@^4.3.1, debug@^4.3.2:
+debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@4:
version "4.4.1"
resolved "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz"
integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==
dependencies:
ms "^2.1.3"
+dedent@^1.6.0:
+ version "1.7.2"
+ resolved "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz"
+ integrity sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==
+
deep-is@^0.1.3:
version "0.1.4"
resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz"
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
+deepmerge@^4.3.1:
+ 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==
+
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
+detect-newline@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz"
+ integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==
+
doctrine@^3.0.0:
version "3.0.0"
- resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
+ resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz"
integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
dependencies:
esutils "^2.0.2"
dotenv@^17.3.1:
version "17.3.1"
- resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-17.3.1.tgz#2706f5b0165e45a1503348187b8468f87fe6aae2"
+ resolved "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz"
integrity sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==
dunder-proto@^1.0.1:
@@ -263,13 +1122,45 @@ dunder-proto@^1.0.1:
es-errors "^1.3.0"
gopd "^1.2.0"
-ecdsa-sig-formatter@1.0.11, ecdsa-sig-formatter@^1.0.11:
+eastasianwidth@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz"
+ integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
+
+ecdsa-sig-formatter@^1.0.11, ecdsa-sig-formatter@1.0.11:
version "1.0.11"
resolved "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz"
integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==
dependencies:
safe-buffer "^5.0.1"
+electron-to-chromium@^1.5.263:
+ version "1.5.321"
+ resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.321.tgz"
+ integrity sha512-L2C7Q279W2D/J4PLZLk7sebOILDSWos7bMsMNN06rK482umHUrh/3lM8G7IlHFOYip2oAg5nha1rCMxr/rs6ZQ==
+
+emittery@^0.13.1:
+ version "0.13.1"
+ resolved "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz"
+ integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==
+
+emoji-regex@^8.0.0:
+ version "8.0.0"
+ resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz"
+ integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
+
+emoji-regex@^9.2.2:
+ version "9.2.2"
+ resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz"
+ integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
+
+error-ex@^1.3.1:
+ version "1.3.4"
+ resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz"
+ integrity sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==
+ dependencies:
+ is-arrayish "^0.2.1"
+
es-define-property@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz"
@@ -297,6 +1188,16 @@ es-set-tostringtag@^2.1.0:
has-tostringtag "^1.0.2"
hasown "^2.0.2"
+escalade@^3.1.1, escalade@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz"
+ integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==
+
+escape-string-regexp@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz"
+ integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==
+
escape-string-regexp@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz"
@@ -309,7 +1210,7 @@ eslint-config-prettier@^10.1.8:
eslint-scope@^7.2.2:
version "7.2.2"
- resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f"
+ resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz"
integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==
dependencies:
esrecurse "^4.3.0"
@@ -320,9 +1221,9 @@ eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3:
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz"
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
-eslint@^8.57.0:
+"eslint@^6.0.0 || ^7.0.0 || >=8.0.0", eslint@^8.57.0, eslint@>=7.0.0:
version "8.57.1"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9"
+ resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz"
integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==
dependencies:
"@eslint-community/eslint-utils" "^4.2.0"
@@ -366,16 +1267,21 @@ eslint@^8.57.0:
espree@^9.6.0, espree@^9.6.1:
version "9.6.1"
- resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f"
+ resolved "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz"
integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==
dependencies:
acorn "^8.9.0"
acorn-jsx "^5.3.2"
eslint-visitor-keys "^3.4.1"
+esprima@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz"
+ integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
+
esquery@^1.4.2:
version "1.6.0"
- resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7"
+ resolved "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz"
integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==
dependencies:
estraverse "^5.1.0"
@@ -397,6 +1303,38 @@ esutils@^2.0.2:
resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz"
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
+execa@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz"
+ integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==
+ 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"
+
+exit-x@^0.2.2:
+ version "0.2.2"
+ resolved "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz"
+ integrity sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==
+
+expect@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/expect/-/expect-30.3.0.tgz"
+ integrity sha512-1zQrciTiQfRdo7qJM1uG4navm8DayFa2TgCSRlzUyNkhcJ6XUZF3hjnpkyr3VhAqPH7i/9GkG7Tv5abz6fqz0Q==
+ dependencies:
+ "@jest/expect-utils" "30.3.0"
+ "@jest/get-type" "30.1.0"
+ jest-matcher-utils "30.3.0"
+ jest-message-util "30.3.0"
+ jest-mock "30.3.0"
+ jest-util "30.3.0"
+
extend@^3.0.2:
version "3.0.2"
resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz"
@@ -407,7 +1345,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
-fast-json-stable-stringify@^2.0.0:
+fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0:
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==
@@ -419,18 +1357,41 @@ fast-levenshtein@^2.0.6:
fastq@^1.6.0:
version "1.19.1"
- resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.1.tgz#d50eaba803c8846a883c16492821ebcd2cda55f5"
+ resolved "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz"
integrity sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==
dependencies:
reusify "^1.0.4"
+fb-watchman@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz"
+ integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==
+ dependencies:
+ bser "2.1.1"
+
file-entry-cache@^6.0.1:
version "6.0.1"
- resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
+ resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz"
integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==
dependencies:
flat-cache "^3.0.4"
+find-up@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz"
+ integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
+ dependencies:
+ locate-path "^5.0.0"
+ path-exists "^4.0.0"
+
+find-up@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz"
+ integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
+ dependencies:
+ locate-path "^5.0.0"
+ path-exists "^4.0.0"
+
find-up@^5.0.0:
version "5.0.0"
resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz"
@@ -441,7 +1402,7 @@ find-up@^5.0.0:
flat-cache@^3.0.4:
version "3.2.0"
- resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee"
+ resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz"
integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==
dependencies:
flatted "^3.2.9"
@@ -455,12 +1416,20 @@ flatted@^3.2.9:
follow-redirects@^1.15.11:
version "1.15.11"
- resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.11.tgz#777d73d72a92f8ec4d2e410eb47352a56b8e8340"
+ resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz"
integrity sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==
+foreground-child@^3.1.0:
+ version "3.3.1"
+ resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz"
+ integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==
+ dependencies:
+ cross-spawn "^7.0.6"
+ signal-exit "^4.0.1"
+
form-data@^4.0.5:
version "4.0.5"
- resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.5.tgz#b49e48858045ff4cbf6b03e1805cebcad3679053"
+ resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz"
integrity sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==
dependencies:
asynckit "^0.4.0"
@@ -471,7 +1440,7 @@ form-data@^4.0.5:
fs.realpath@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+ resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
function-bind@^1.1.2:
@@ -499,6 +1468,16 @@ gcp-metadata@^6.1.0:
google-logging-utils "^0.0.2"
json-bigint "^1.0.0"
+gensync@^1.0.0-beta.2:
+ 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==
+
+get-caller-file@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz"
+ integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
+
get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.3.0:
version "1.3.0"
resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz"
@@ -515,6 +1494,11 @@ get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.3.0:
hasown "^2.0.2"
math-intrinsics "^1.1.0"
+get-package-type@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz"
+ integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==
+
get-proto@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz"
@@ -523,6 +1507,11 @@ get-proto@^1.0.1:
dunder-proto "^1.0.1"
es-object-atoms "^1.0.0"
+get-stream@^6.0.0:
+ version "6.0.1"
+ resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz"
+ integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
+
glob-parent@^6.0.2:
version "6.0.2"
resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz"
@@ -530,9 +1519,33 @@ glob-parent@^6.0.2:
dependencies:
is-glob "^4.0.3"
+glob@^10.5.0:
+ version "10.5.0"
+ resolved "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz"
+ integrity sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==
+ dependencies:
+ foreground-child "^3.1.0"
+ jackspeak "^3.1.2"
+ minimatch "^9.0.4"
+ minipass "^7.1.2"
+ package-json-from-dist "^1.0.0"
+ path-scurry "^1.11.1"
+
glob@^7.1.3:
version "7.2.3"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
+ resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz"
+ integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
+ 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"
+
+glob@^7.1.4:
+ version "7.2.3"
+ resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz"
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
dependencies:
fs.realpath "^1.0.0"
@@ -544,7 +1557,7 @@ glob@^7.1.3:
globals@^13.19.0:
version "13.24.0"
- resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171"
+ resolved "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz"
integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==
dependencies:
type-fest "^0.20.2"
@@ -591,9 +1604,14 @@ gopd@^1.2.0:
resolved "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz"
integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==
+graceful-fs@^4.2.11:
+ 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==
+
graphemer@^1.4.0:
version "1.4.0"
- resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
+ resolved "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz"
integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
gtoken@^7.0.0:
@@ -628,6 +1646,11 @@ hasown@^2.0.2:
dependencies:
function-bind "^1.1.2"
+html-escaper@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz"
+ integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
+
https-proxy-agent@^7.0.1:
version "7.0.6"
resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz"
@@ -636,6 +1659,11 @@ https-proxy-agent@^7.0.1:
agent-base "^7.1.2"
debug "4"
+human-signals@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz"
+ integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
+
ignore@^5.2.0:
version "5.3.2"
resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz"
@@ -649,6 +1677,14 @@ import-fresh@^3.2.1:
parent-module "^1.0.0"
resolve-from "^4.0.0"
+import-local@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz"
+ integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==
+ dependencies:
+ pkg-dir "^4.2.0"
+ resolve-cwd "^3.0.0"
+
imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz"
@@ -656,27 +1692,37 @@ imurmurhash@^0.1.4:
inflight@^1.0.4:
version "1.0.6"
- resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz"
integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
dependencies:
once "^1.3.0"
wrappy "1"
-inherits@2:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
- integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
-
-inherits@2.0.3:
+inherits@2, inherits@2.0.3:
version "2.0.3"
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz"
integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==
+is-arrayish@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz"
+ integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
+
is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz"
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+is-fullwidth-code-point@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz"
+ integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
+
+is-generator-fn@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz"
+ integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==
+
is-glob@^4.0.0, is-glob@^4.0.3:
version "4.0.3"
resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz"
@@ -686,7 +1732,7 @@ is-glob@^4.0.0, is-glob@^4.0.3:
is-path-inside@^3.0.3:
version "3.0.3"
- resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
+ resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz"
integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
is-stream@^2.0.0:
@@ -699,6 +1745,425 @@ isexe@^2.0.0:
resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz"
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
+istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0:
+ 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==
+
+istanbul-lib-instrument@^6.0.0, istanbul-lib-instrument@^6.0.2:
+ 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==
+ 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"
+
+istanbul-lib-report@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz"
+ integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==
+ dependencies:
+ istanbul-lib-coverage "^3.0.0"
+ make-dir "^4.0.0"
+ supports-color "^7.1.0"
+
+istanbul-lib-source-maps@^5.0.0:
+ version "5.0.6"
+ resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz"
+ integrity sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==
+ dependencies:
+ "@jridgewell/trace-mapping" "^0.3.23"
+ debug "^4.1.1"
+ istanbul-lib-coverage "^3.0.0"
+
+istanbul-reports@^3.1.3:
+ version "3.2.0"
+ resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz"
+ integrity sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==
+ dependencies:
+ html-escaper "^2.0.0"
+ istanbul-lib-report "^3.0.0"
+
+jackspeak@^3.1.2:
+ version "3.4.3"
+ resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz"
+ integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==
+ dependencies:
+ "@isaacs/cliui" "^8.0.2"
+ optionalDependencies:
+ "@pkgjs/parseargs" "^0.11.0"
+
+jest-changed-files@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.3.0.tgz"
+ integrity sha512-B/7Cny6cV5At6M25EWDgf9S617lHivamL8vl6KEpJqkStauzcG4e+WPfDgMMF+H4FVH4A2PLRyvgDJan4441QA==
+ dependencies:
+ execa "^5.1.1"
+ jest-util "30.3.0"
+ p-limit "^3.1.0"
+
+jest-circus@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/jest-circus/-/jest-circus-30.3.0.tgz"
+ integrity sha512-PyXq5szeSfR/4f1lYqCmmQjh0vqDkURUYi9N6whnHjlRz4IUQfMcXkGLeEoiJtxtyPqgUaUUfyQlApXWBSN1RA==
+ dependencies:
+ "@jest/environment" "30.3.0"
+ "@jest/expect" "30.3.0"
+ "@jest/test-result" "30.3.0"
+ "@jest/types" "30.3.0"
+ "@types/node" "*"
+ chalk "^4.1.2"
+ co "^4.6.0"
+ dedent "^1.6.0"
+ is-generator-fn "^2.1.0"
+ jest-each "30.3.0"
+ jest-matcher-utils "30.3.0"
+ jest-message-util "30.3.0"
+ jest-runtime "30.3.0"
+ jest-snapshot "30.3.0"
+ jest-util "30.3.0"
+ p-limit "^3.1.0"
+ pretty-format "30.3.0"
+ pure-rand "^7.0.0"
+ slash "^3.0.0"
+ stack-utils "^2.0.6"
+
+jest-cli@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-30.3.0.tgz"
+ integrity sha512-l6Tqx+j1fDXJEW5bqYykDQQ7mQg+9mhWXtnj+tQZrTWYHyHoi6Be8HPumDSA+UiX2/2buEgjA58iJzdj146uCw==
+ dependencies:
+ "@jest/core" "30.3.0"
+ "@jest/test-result" "30.3.0"
+ "@jest/types" "30.3.0"
+ chalk "^4.1.2"
+ exit-x "^0.2.2"
+ import-local "^3.2.0"
+ jest-config "30.3.0"
+ jest-util "30.3.0"
+ jest-validate "30.3.0"
+ yargs "^17.7.2"
+
+jest-config@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/jest-config/-/jest-config-30.3.0.tgz"
+ integrity sha512-WPMAkMAtNDY9P/oKObtsRG/6KTrhtgPJoBTmk20uDn4Uy6/3EJnnaZJre/FMT1KVRx8cve1r7/FlMIOfRVWL4w==
+ dependencies:
+ "@babel/core" "^7.27.4"
+ "@jest/get-type" "30.1.0"
+ "@jest/pattern" "30.0.1"
+ "@jest/test-sequencer" "30.3.0"
+ "@jest/types" "30.3.0"
+ babel-jest "30.3.0"
+ chalk "^4.1.2"
+ ci-info "^4.2.0"
+ deepmerge "^4.3.1"
+ glob "^10.5.0"
+ graceful-fs "^4.2.11"
+ jest-circus "30.3.0"
+ jest-docblock "30.2.0"
+ jest-environment-node "30.3.0"
+ jest-regex-util "30.0.1"
+ jest-resolve "30.3.0"
+ jest-runner "30.3.0"
+ jest-util "30.3.0"
+ jest-validate "30.3.0"
+ parse-json "^5.2.0"
+ pretty-format "30.3.0"
+ slash "^3.0.0"
+ strip-json-comments "^3.1.1"
+
+jest-diff@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-30.3.0.tgz"
+ integrity sha512-n3q4PDQjS4LrKxfWB3Z5KNk1XjXtZTBwQp71OP0Jo03Z6V60x++K5L8k6ZrW8MY8pOFylZvHM0zsjS1RqlHJZQ==
+ dependencies:
+ "@jest/diff-sequences" "30.3.0"
+ "@jest/get-type" "30.1.0"
+ chalk "^4.1.2"
+ pretty-format "30.3.0"
+
+jest-docblock@30.2.0:
+ version "30.2.0"
+ resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz"
+ integrity sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==
+ dependencies:
+ detect-newline "^3.1.0"
+
+jest-each@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/jest-each/-/jest-each-30.3.0.tgz"
+ integrity sha512-V8eMndg/aZ+3LnCJgSm13IxS5XSBM22QSZc9BtPK8Dek6pm+hfUNfwBdvsB3d342bo1q7wnSkC38zjX259qZNA==
+ dependencies:
+ "@jest/get-type" "30.1.0"
+ "@jest/types" "30.3.0"
+ chalk "^4.1.2"
+ jest-util "30.3.0"
+ pretty-format "30.3.0"
+
+jest-environment-node@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.3.0.tgz"
+ integrity sha512-4i6HItw/JSiJVsC5q0hnKIe/hbYfZLVG9YJ/0pU9Hz2n/9qZe3Rhn5s5CUZA5ORZlcdT/vmAXRMyONXJwPrmYQ==
+ dependencies:
+ "@jest/environment" "30.3.0"
+ "@jest/fake-timers" "30.3.0"
+ "@jest/types" "30.3.0"
+ "@types/node" "*"
+ jest-mock "30.3.0"
+ jest-util "30.3.0"
+ jest-validate "30.3.0"
+
+jest-haste-map@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.3.0.tgz"
+ integrity sha512-mMi2oqG4KRU0R9QEtscl87JzMXfUhbKaFqOxmjb2CKcbHcUGFrJCBWHmnTiUqi6JcnzoBlO4rWfpdl2k/RfLCA==
+ dependencies:
+ "@jest/types" "30.3.0"
+ "@types/node" "*"
+ anymatch "^3.1.3"
+ fb-watchman "^2.0.2"
+ graceful-fs "^4.2.11"
+ jest-regex-util "30.0.1"
+ jest-util "30.3.0"
+ jest-worker "30.3.0"
+ picomatch "^4.0.3"
+ walker "^1.0.8"
+ optionalDependencies:
+ fsevents "^2.3.3"
+
+jest-leak-detector@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.3.0.tgz"
+ integrity sha512-cuKmUUGIjfXZAiGJ7TbEMx0bcqNdPPI6P1V+7aF+m/FUJqFDxkFR4JqkTu8ZOiU5AaX/x0hZ20KaaIPXQzbMGQ==
+ dependencies:
+ "@jest/get-type" "30.1.0"
+ pretty-format "30.3.0"
+
+jest-matcher-utils@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.3.0.tgz"
+ integrity sha512-HEtc9uFQgaUHkC7nLSlQL3Tph4Pjxt/yiPvkIrrDCt9jhoLIgxaubo1G+CFOnmHYMxHwwdaSN7mkIFs6ZK8OhA==
+ dependencies:
+ "@jest/get-type" "30.1.0"
+ chalk "^4.1.2"
+ jest-diff "30.3.0"
+ pretty-format "30.3.0"
+
+jest-message-util@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.3.0.tgz"
+ integrity sha512-Z/j4Bo+4ySJ+JPJN3b2Qbl9hDq3VrXmnjjGEWD/x0BCXeOXPTV1iZYYzl2X8c1MaCOL+ewMyNBcm88sboE6YWw==
+ dependencies:
+ "@babel/code-frame" "^7.27.1"
+ "@jest/types" "30.3.0"
+ "@types/stack-utils" "^2.0.3"
+ chalk "^4.1.2"
+ graceful-fs "^4.2.11"
+ picomatch "^4.0.3"
+ pretty-format "30.3.0"
+ slash "^3.0.0"
+ stack-utils "^2.0.6"
+
+jest-mock@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-30.3.0.tgz"
+ integrity sha512-OTzICK8CpE+t4ndhKrwlIdbM6Pn8j00lvmSmq5ejiO+KxukbLjgOflKWMn3KE34EZdQm5RqTuKj+5RIEniYhog==
+ dependencies:
+ "@jest/types" "30.3.0"
+ "@types/node" "*"
+ jest-util "30.3.0"
+
+jest-pnp-resolver@^1.2.3:
+ version "1.2.3"
+ resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz"
+ integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==
+
+jest-regex-util@30.0.1:
+ version "30.0.1"
+ resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz"
+ integrity sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==
+
+jest-resolve-dependencies@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.3.0.tgz"
+ integrity sha512-9ev8s3YN6Hsyz9LV75XUwkCVFlwPbaFn6Wp75qnI0wzAINYWY8Fb3+6y59Rwd3QaS3kKXffHXsZMziMavfz/nw==
+ dependencies:
+ jest-regex-util "30.0.1"
+ jest-snapshot "30.3.0"
+
+jest-resolve@*, jest-resolve@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.3.0.tgz"
+ integrity sha512-NRtTAHQlpd15F9rUR36jqwelbrDV/dY4vzNte3S2kxCKUJRYNd5/6nTSbYiak1VX5g8IoFF23Uj5TURkUW8O5g==
+ dependencies:
+ chalk "^4.1.2"
+ graceful-fs "^4.2.11"
+ jest-haste-map "30.3.0"
+ jest-pnp-resolver "^1.2.3"
+ jest-util "30.3.0"
+ jest-validate "30.3.0"
+ slash "^3.0.0"
+ unrs-resolver "^1.7.11"
+
+jest-runner@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-30.3.0.tgz"
+ integrity sha512-gDv6C9LGKWDPLia9TSzZwf4h3kMQCqyTpq+95PODnTRDO0g9os48XIYYkS6D236vjpBir2fF63YmJFtqkS5Duw==
+ dependencies:
+ "@jest/console" "30.3.0"
+ "@jest/environment" "30.3.0"
+ "@jest/test-result" "30.3.0"
+ "@jest/transform" "30.3.0"
+ "@jest/types" "30.3.0"
+ "@types/node" "*"
+ chalk "^4.1.2"
+ emittery "^0.13.1"
+ exit-x "^0.2.2"
+ graceful-fs "^4.2.11"
+ jest-docblock "30.2.0"
+ jest-environment-node "30.3.0"
+ jest-haste-map "30.3.0"
+ jest-leak-detector "30.3.0"
+ jest-message-util "30.3.0"
+ jest-resolve "30.3.0"
+ jest-runtime "30.3.0"
+ jest-util "30.3.0"
+ jest-watcher "30.3.0"
+ jest-worker "30.3.0"
+ p-limit "^3.1.0"
+ source-map-support "0.5.13"
+
+jest-runtime@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.3.0.tgz"
+ integrity sha512-CgC+hIBJbuh78HEffkhNKcbXAytQViplcl8xupqeIWyKQF50kCQA8J7GeJCkjisC6hpnC9Muf8jV5RdtdFbGng==
+ dependencies:
+ "@jest/environment" "30.3.0"
+ "@jest/fake-timers" "30.3.0"
+ "@jest/globals" "30.3.0"
+ "@jest/source-map" "30.0.1"
+ "@jest/test-result" "30.3.0"
+ "@jest/transform" "30.3.0"
+ "@jest/types" "30.3.0"
+ "@types/node" "*"
+ chalk "^4.1.2"
+ cjs-module-lexer "^2.1.0"
+ collect-v8-coverage "^1.0.2"
+ glob "^10.5.0"
+ graceful-fs "^4.2.11"
+ jest-haste-map "30.3.0"
+ jest-message-util "30.3.0"
+ jest-mock "30.3.0"
+ jest-regex-util "30.0.1"
+ jest-resolve "30.3.0"
+ jest-snapshot "30.3.0"
+ jest-util "30.3.0"
+ slash "^3.0.0"
+ strip-bom "^4.0.0"
+
+jest-snapshot@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.3.0.tgz"
+ integrity sha512-f14c7atpb4O2DeNhwcvS810Y63wEn8O1HqK/luJ4F6M4NjvxmAKQwBUWjbExUtMxWJQ0wVgmCKymeJK6NZMnfQ==
+ dependencies:
+ "@babel/core" "^7.27.4"
+ "@babel/generator" "^7.27.5"
+ "@babel/plugin-syntax-jsx" "^7.27.1"
+ "@babel/plugin-syntax-typescript" "^7.27.1"
+ "@babel/types" "^7.27.3"
+ "@jest/expect-utils" "30.3.0"
+ "@jest/get-type" "30.1.0"
+ "@jest/snapshot-utils" "30.3.0"
+ "@jest/transform" "30.3.0"
+ "@jest/types" "30.3.0"
+ babel-preset-current-node-syntax "^1.2.0"
+ chalk "^4.1.2"
+ expect "30.3.0"
+ graceful-fs "^4.2.11"
+ jest-diff "30.3.0"
+ jest-matcher-utils "30.3.0"
+ jest-message-util "30.3.0"
+ jest-util "30.3.0"
+ pretty-format "30.3.0"
+ semver "^7.7.2"
+ synckit "^0.11.8"
+
+jest-util@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/jest-util/-/jest-util-30.3.0.tgz"
+ integrity sha512-/jZDa00a3Sz7rdyu55NLrQCIrbyIkbBxareejQI315f/i8HjYN+ZWsDLLpoQSiUIEIyZF/R8fDg3BmB8AtHttg==
+ dependencies:
+ "@jest/types" "30.3.0"
+ "@types/node" "*"
+ chalk "^4.1.2"
+ ci-info "^4.2.0"
+ graceful-fs "^4.2.11"
+ picomatch "^4.0.3"
+
+jest-validate@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-30.3.0.tgz"
+ integrity sha512-I/xzC8h5G+SHCb2P2gWkJYrNiTbeL47KvKeW5EzplkyxzBRBw1ssSHlI/jXec0ukH2q7x2zAWQm7015iusg62Q==
+ dependencies:
+ "@jest/get-type" "30.1.0"
+ "@jest/types" "30.3.0"
+ camelcase "^6.3.0"
+ chalk "^4.1.2"
+ leven "^3.1.0"
+ pretty-format "30.3.0"
+
+jest-watcher@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.3.0.tgz"
+ integrity sha512-PJ1d9ThtTR8aMiBWUdcownq9mDdLXsQzJayTk4kmaBRHKvwNQn+ANveuhEBUyNI2hR1TVhvQ8D5kHubbzBHR/w==
+ dependencies:
+ "@jest/test-result" "30.3.0"
+ "@jest/types" "30.3.0"
+ "@types/node" "*"
+ ansi-escapes "^4.3.2"
+ chalk "^4.1.2"
+ emittery "^0.13.1"
+ jest-util "30.3.0"
+ string-length "^4.0.2"
+
+jest-worker@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-30.3.0.tgz"
+ integrity sha512-DrCKkaQwHexjRUFTmPzs7sHQe0TSj9nvDALKGdwmK5mW9v7j90BudWirKAJHt3QQ9Dhrg1F7DogPzhChppkJpQ==
+ dependencies:
+ "@types/node" "*"
+ "@ungap/structured-clone" "^1.3.0"
+ jest-util "30.3.0"
+ merge-stream "^2.0.0"
+ supports-color "^8.1.1"
+
+jest@^30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/jest/-/jest-30.3.0.tgz"
+ integrity sha512-AkXIIFcaazymvey2i/+F94XRnM6TsVLZDhBMLsd1Sf/W0wzsvvpjeyUrCZD6HGG4SDYPgDJDBKeiJTBb10WzMg==
+ dependencies:
+ "@jest/core" "30.3.0"
+ "@jest/types" "30.3.0"
+ import-local "^3.2.0"
+ jest-cli "30.3.0"
+
+js-tokens@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz"
+ integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+
+js-yaml@^3.13.1:
+ version "3.14.2"
+ resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz"
+ integrity sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==
+ dependencies:
+ argparse "^1.0.7"
+ esprima "^4.0.0"
+
js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz"
@@ -706,6 +2171,11 @@ js-yaml@^4.1.0:
dependencies:
argparse "^2.0.1"
+jsesc@^3.0.2:
+ version "3.1.0"
+ resolved "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz"
+ integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==
+
json-bigint@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz"
@@ -718,6 +2188,11 @@ json-buffer@3.0.1:
resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz"
integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
+json-parse-even-better-errors@^2.3.0:
+ 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==
+
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz"
@@ -728,6 +2203,11 @@ json-stable-stringify-without-jsonify@^1.0.1:
resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz"
integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
+json5@^2.2.3:
+ version "2.2.3"
+ resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz"
+ integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
+
jwa@^2.0.0:
version "2.0.1"
resolved "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz"
@@ -747,11 +2227,16 @@ jws@^4.0.0:
keyv@^4.5.3:
version "4.5.4"
- resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
+ resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz"
integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==
dependencies:
json-buffer "3.0.1"
+leven@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz"
+ integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==
+
levn@^0.4.1:
version "0.4.1"
resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz"
@@ -760,6 +2245,18 @@ levn@^0.4.1:
prelude-ls "^1.2.1"
type-check "~0.4.0"
+lines-and-columns@^1.1.6:
+ version "1.2.4"
+ resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz"
+ integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
+
+locate-path@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz"
+ integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
+ dependencies:
+ p-locate "^4.1.0"
+
locate-path@^6.0.0:
version "6.0.0"
resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz"
@@ -772,11 +2269,42 @@ lodash.merge@^4.6.2:
resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
+lru-cache@^10.2.0:
+ version "10.4.3"
+ resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz"
+ integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==
+
+lru-cache@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz"
+ integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==
+ dependencies:
+ yallist "^3.0.2"
+
+make-dir@^4.0.0:
+ 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==
+ dependencies:
+ semver "^7.5.3"
+
+makeerror@1.0.12:
+ version "1.0.12"
+ resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz"
+ integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==
+ dependencies:
+ tmpl "1.0.5"
+
math-intrinsics@^1.1.0:
version "1.1.0"
resolved "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz"
integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==
+merge-stream@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz"
+ integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
+
mime-db@1.52.0:
version "1.52.0"
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz"
@@ -789,18 +2317,40 @@ mime-types@^2.1.12:
dependencies:
mime-db "1.52.0"
-minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
+mimic-fn@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz"
+ integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
+
+minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
version "3.1.2"
resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"
integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
dependencies:
brace-expansion "^1.1.7"
+minimatch@^9.0.4:
+ version "9.0.9"
+ resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz"
+ integrity sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==
+ dependencies:
+ brace-expansion "^2.0.2"
+
+"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2:
+ version "7.1.3"
+ resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz"
+ integrity sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==
+
ms@^2.1.3:
version "2.1.3"
resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+napi-postinstall@^0.3.0:
+ version "0.3.4"
+ resolved "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz"
+ integrity sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==
+
natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz"
@@ -808,7 +2358,7 @@ natural-compare@^1.4.0:
node-fetch-native@^1.6.7:
version "1.6.7"
- resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.6.7.tgz#9d09ca63066cc48423211ed4caf5d70075d76a71"
+ resolved "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz"
integrity sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==
node-fetch@^2.6.9:
@@ -818,6 +2368,28 @@ node-fetch@^2.6.9:
dependencies:
whatwg-url "^5.0.0"
+node-int64@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz"
+ integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==
+
+node-releases@^2.0.27:
+ version "2.0.36"
+ resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz"
+ integrity sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==
+
+normalize-path@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz"
+ integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+
+npm-run-path@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz"
+ integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
+ dependencies:
+ path-key "^3.0.0"
+
object-inspect@^1.13.3:
version "1.13.4"
resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz"
@@ -825,11 +2397,18 @@ object-inspect@^1.13.3:
once@^1.3.0:
version "1.4.0"
- resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+ resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz"
integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
dependencies:
wrappy "1"
+onetime@^5.1.2:
+ version "5.1.2"
+ resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz"
+ integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
+ dependencies:
+ mimic-fn "^2.1.0"
+
optionator@^0.9.3:
version "0.9.4"
resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz"
@@ -842,13 +2421,27 @@ optionator@^0.9.3:
type-check "^0.4.0"
word-wrap "^1.2.5"
-p-limit@^3.0.2:
+p-limit@^2.2.0:
+ version "2.3.0"
+ resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz"
+ integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
+ dependencies:
+ p-try "^2.0.0"
+
+p-limit@^3.0.2, p-limit@^3.1.0:
version "3.1.0"
resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz"
integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
dependencies:
yocto-queue "^0.1.0"
+p-locate@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz"
+ integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
+ dependencies:
+ p-limit "^2.2.0"
+
p-locate@^5.0.0:
version "5.0.0"
resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz"
@@ -856,6 +2449,16 @@ p-locate@^5.0.0:
dependencies:
p-limit "^3.0.2"
+p-try@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz"
+ integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
+
+package-json-from-dist@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz"
+ integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==
+
parent-module@^1.0.0:
version "1.0.1"
resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz"
@@ -863,6 +2466,16 @@ parent-module@^1.0.0:
dependencies:
callsites "^3.0.0"
+parse-json@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz"
+ integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
+ 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"
+
path-exists@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz"
@@ -870,14 +2483,22 @@ path-exists@^4.0.0:
path-is-absolute@^1.0.0:
version "1.0.1"
- resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+ resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz"
integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
-path-key@^3.1.0:
+path-key@^3.0.0, path-key@^3.1.0:
version "3.1.1"
resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
+path-scurry@^1.11.1:
+ version "1.11.1"
+ resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz"
+ integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==
+ dependencies:
+ lru-cache "^10.2.0"
+ minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
+
path@^0.12.7:
version "0.12.7"
resolved "https://registry.npmjs.org/path/-/path-0.12.7.tgz"
@@ -886,6 +2507,33 @@ path@^0.12.7:
process "^0.11.1"
util "^0.10.3"
+picocolors@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz"
+ integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
+
+picomatch@^2.0.4:
+ version "2.3.1"
+ resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
+ integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
+
+picomatch@^4.0.3:
+ version "4.0.3"
+ resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz"
+ integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==
+
+pirates@^4.0.7:
+ version "4.0.7"
+ resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz"
+ integrity sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==
+
+pkg-dir@^4.2.0:
+ 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==
+ dependencies:
+ find-up "^4.0.0"
+
prelude-ls@^1.2.1:
version "1.2.1"
resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz"
@@ -893,9 +2541,18 @@ prelude-ls@^1.2.1:
prettier@^3.8.1:
version "3.8.1"
- resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.8.1.tgz#edf48977cf991558f4fcbd8a3ba6015ba2a3a173"
+ resolved "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz"
integrity sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==
+pretty-format@30.3.0:
+ version "30.3.0"
+ resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-30.3.0.tgz"
+ integrity sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==
+ dependencies:
+ "@jest/schemas" "30.0.5"
+ ansi-styles "^5.2.0"
+ react-is "^18.3.1"
+
process@^0.11.1:
version "0.11.10"
resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz"
@@ -911,6 +2568,11 @@ punycode@^2.1.0:
resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz"
integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
+pure-rand@^7.0.0:
+ version "7.0.1"
+ resolved "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz"
+ integrity sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==
+
qs@^6.7.0:
version "6.14.0"
resolved "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz"
@@ -920,29 +2582,51 @@ qs@^6.7.0:
queue-microtask@^1.2.2:
version "1.2.3"
- resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
+ resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
+react-is@^18.3.1:
+ 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==
+
+require-directory@^2.1.1:
+ 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==
+
+resolve-cwd@^3.0.0:
+ 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==
+ dependencies:
+ resolve-from "^5.0.0"
+
resolve-from@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz"
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
+resolve-from@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz"
+ integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
+
reusify@^1.0.4:
version "1.1.0"
- resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.1.0.tgz#0fe13b9522e1473f51b558ee796e08f11f9b489f"
+ resolved "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz"
integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==
rimraf@^3.0.2:
version "3.0.2"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
+ resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz"
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
dependencies:
glob "^7.1.3"
run-parallel@^1.1.9:
version "1.2.0"
- resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
+ resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz"
integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
dependencies:
queue-microtask "^1.2.2"
@@ -952,6 +2636,26 @@ safe-buffer@^5.0.1:
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+semver@^6.3.1:
+ version "6.3.1"
+ resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz"
+ integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
+
+semver@^7.5.3:
+ version "7.7.4"
+ resolved "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz"
+ integrity sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==
+
+semver@^7.5.4:
+ version "7.7.4"
+ resolved "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz"
+ integrity sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==
+
+semver@^7.7.2:
+ version "7.7.4"
+ resolved "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz"
+ integrity sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==
+
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz"
@@ -1004,13 +2708,121 @@ side-channel@^1.1.0:
side-channel-map "^1.0.1"
side-channel-weakmap "^1.0.2"
-strip-ansi@^6.0.1:
+signal-exit@^3.0.3:
+ version "3.0.7"
+ resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz"
+ integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
+
+signal-exit@^4.0.1:
+ version "4.1.0"
+ resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz"
+ integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==
+
+slash@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz"
+ integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
+
+source-map-support@0.5.13:
+ version "0.5.13"
+ resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz"
+ integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==
+ dependencies:
+ buffer-from "^1.0.0"
+ source-map "^0.6.0"
+
+source-map@^0.6.0:
+ version "0.6.1"
+ resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
+ integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
+sprintf-js@~1.0.2:
+ version "1.0.3"
+ resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz"
+ integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
+
+stack-utils@^2.0.6:
+ version "2.0.6"
+ resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz"
+ integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==
+ dependencies:
+ escape-string-regexp "^2.0.0"
+
+string-length@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz"
+ integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==
+ dependencies:
+ char-regex "^1.0.2"
+ strip-ansi "^6.0.0"
+
+"string-width-cjs@npm:string-width@^4.2.0":
+ version "4.2.3"
+ resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
+ integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+ dependencies:
+ emoji-regex "^8.0.0"
+ is-fullwidth-code-point "^3.0.0"
+ strip-ansi "^6.0.1"
+
+string-width@^4.1.0, string-width@^4.2.0:
+ version "4.2.3"
+ resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
+ integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+ dependencies:
+ emoji-regex "^8.0.0"
+ is-fullwidth-code-point "^3.0.0"
+ strip-ansi "^6.0.1"
+
+string-width@^4.2.3:
+ version "4.2.3"
+ resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
+ integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+ dependencies:
+ emoji-regex "^8.0.0"
+ is-fullwidth-code-point "^3.0.0"
+ strip-ansi "^6.0.1"
+
+string-width@^5.0.1, string-width@^5.1.2:
+ version "5.1.2"
+ resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz"
+ integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==
+ dependencies:
+ eastasianwidth "^0.2.0"
+ emoji-regex "^9.2.2"
+ strip-ansi "^7.0.1"
+
+"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+ resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
+strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
+ integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
+ dependencies:
+ ansi-regex "^5.0.1"
+
+strip-ansi@^7.0.1:
+ version "7.2.0"
+ resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz"
+ integrity sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==
+ dependencies:
+ ansi-regex "^6.2.2"
+
+strip-bom@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz"
+ integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==
+
+strip-final-newline@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz"
+ integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
+
strip-json-comments@^3.1.1:
version "3.1.1"
resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz"
@@ -1023,11 +2835,39 @@ supports-color@^7.1.0:
dependencies:
has-flag "^4.0.0"
+supports-color@^8.1.1:
+ version "8.1.1"
+ resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz"
+ integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
+ dependencies:
+ has-flag "^4.0.0"
+
+synckit@^0.11.8:
+ version "0.11.12"
+ resolved "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz"
+ integrity sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==
+ dependencies:
+ "@pkgr/core" "^0.2.9"
+
+test-exclude@^6.0.0:
+ 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==
+ dependencies:
+ "@istanbuljs/schema" "^0.1.2"
+ glob "^7.1.4"
+ minimatch "^3.0.4"
+
text-table@^0.2.0:
version "0.2.0"
- resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
+ resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz"
integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
+tmpl@1.0.5:
+ version "1.0.5"
+ resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz"
+ integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==
+
tr46@~0.0.3:
version "0.0.3"
resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz"
@@ -1040,11 +2880,61 @@ type-check@^0.4.0, type-check@~0.4.0:
dependencies:
prelude-ls "^1.2.1"
+type-detect@4.0.8:
+ 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==
+
type-fest@^0.20.2:
version "0.20.2"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
+ resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz"
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
+type-fest@^0.21.3:
+ version "0.21.3"
+ resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz"
+ integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
+
+undici-types@~7.18.0:
+ version "7.18.2"
+ resolved "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz"
+ integrity sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==
+
+unrs-resolver@^1.7.11:
+ version "1.11.1"
+ resolved "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz"
+ integrity sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==
+ dependencies:
+ napi-postinstall "^0.3.0"
+ optionalDependencies:
+ "@unrs/resolver-binding-android-arm-eabi" "1.11.1"
+ "@unrs/resolver-binding-android-arm64" "1.11.1"
+ "@unrs/resolver-binding-darwin-arm64" "1.11.1"
+ "@unrs/resolver-binding-darwin-x64" "1.11.1"
+ "@unrs/resolver-binding-freebsd-x64" "1.11.1"
+ "@unrs/resolver-binding-linux-arm-gnueabihf" "1.11.1"
+ "@unrs/resolver-binding-linux-arm-musleabihf" "1.11.1"
+ "@unrs/resolver-binding-linux-arm64-gnu" "1.11.1"
+ "@unrs/resolver-binding-linux-arm64-musl" "1.11.1"
+ "@unrs/resolver-binding-linux-ppc64-gnu" "1.11.1"
+ "@unrs/resolver-binding-linux-riscv64-gnu" "1.11.1"
+ "@unrs/resolver-binding-linux-riscv64-musl" "1.11.1"
+ "@unrs/resolver-binding-linux-s390x-gnu" "1.11.1"
+ "@unrs/resolver-binding-linux-x64-gnu" "1.11.1"
+ "@unrs/resolver-binding-linux-x64-musl" "1.11.1"
+ "@unrs/resolver-binding-wasm32-wasi" "1.11.1"
+ "@unrs/resolver-binding-win32-arm64-msvc" "1.11.1"
+ "@unrs/resolver-binding-win32-ia32-msvc" "1.11.1"
+ "@unrs/resolver-binding-win32-x64-msvc" "1.11.1"
+
+update-browserslist-db@^1.2.0:
+ version "1.2.3"
+ resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz"
+ integrity sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==
+ dependencies:
+ escalade "^3.2.0"
+ picocolors "^1.1.1"
+
uri-js@^4.2.2:
version "4.4.1"
resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz"
@@ -1069,6 +2959,22 @@ uuid@^9.0.0, uuid@^9.0.1:
resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz"
integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==
+v8-to-istanbul@^9.0.1:
+ 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==
+ dependencies:
+ "@jridgewell/trace-mapping" "^0.3.12"
+ "@types/istanbul-lib-coverage" "^2.0.1"
+ convert-source-map "^2.0.0"
+
+walker@^1.0.8:
+ version "1.0.8"
+ resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz"
+ integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==
+ dependencies:
+ makeerror "1.0.12"
+
webidl-conversions@^3.0.0:
version "3.0.1"
resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz"
@@ -1094,11 +3000,74 @@ word-wrap@^1.2.5:
resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz"
integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
+"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
+ version "7.0.0"
+ resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz"
+ integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
+wrap-ansi@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz"
+ integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
+wrap-ansi@^8.1.0:
+ version "8.1.0"
+ resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz"
+ integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==
+ dependencies:
+ ansi-styles "^6.1.0"
+ string-width "^5.0.1"
+ strip-ansi "^7.0.1"
+
wrappy@1:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+ resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
+write-file-atomic@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz"
+ integrity sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==
+ dependencies:
+ imurmurhash "^0.1.4"
+ signal-exit "^4.0.1"
+
+y18n@^5.0.5:
+ version "5.0.8"
+ resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz"
+ integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
+
+yallist@^3.0.2:
+ version "3.1.1"
+ resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz"
+ integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
+
+yargs-parser@^21.1.1:
+ version "21.1.1"
+ resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz"
+ integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
+
+yargs@^17.7.2:
+ version "17.7.2"
+ resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz"
+ integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
+ 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"
+
yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz"