From a1692b37ed8352d87ef43de9fbb9e3fb345f599b Mon Sep 17 00:00:00 2001 From: Diogo Ribeiro Date: Wed, 16 Apr 2025 08:53:33 +0100 Subject: [PATCH 1/7] work --- README.md | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cd815a6..0100a23 100644 --- a/README.md +++ b/README.md @@ -1 +1,101 @@ -# smart-todo-action \ No newline at end of file +# 🧠 smart-todo-action + +A GitHub Action that scans your codebase for inline TODOs, FIXMEs, and BUG comments, and automatically creates GitHub Issues β€” with support for labels, metadata parsing, and semantic enrichment. + +--- + +## πŸš€ Features + +- βœ… Detects `TODO`, `FIXME`, `BUG`, and `HACK` comments +- βœ… Supports multiple languages: `.ts`, `.js`, `.py`, `.go`, `.html`, etc. +- βœ… Extracts metadata like `priority`, `due`, etc. +- βœ… Automatically labels issues based on type and metadata +- βœ… Creates labels on the fly if they don't exist + +--- + +## βš™οΈ Usage + +### 1. Add the Action to your workflow + +```yaml +name: Smart TODO Tracker + +on: + push: + branches: [main] + +jobs: + smart-todo: + runs-on: ubuntu-latest + permissions: + issues: write + + steps: + - uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: 20 + + - run: yarn install + - run: yarn prepare + + - name: Run Smart TODO Action + uses: ./ + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} +``` + +## πŸ“ Example TODOs + +```ts +// TODO(priority=high, due=2025-06-01): Refactor this method for performance +// FIXME: Handle null input properly +// BUG: This causes a crash when file is empty +``` + +## 🏷️ Automatic Labels + +Based on your TODO comment, the following labels will be applied: + +| Tag | Label(s) | +|--------|-----------------------------------------------| +| TODO | `enhancement`, `priority:high`, `due:2025-06-01` | +| FIXME | `bug` | +| BUG | `bug` | +| HACK | `technical-debt` | + +If a label like `priority:high` or `due:2025-06-01` doesn't exist, it will be automatically created. + +--- + +## πŸ“Œ Notes + +- Max **5 issues** are created per run to avoid rate limiting +- **Duplicate detection** is not yet implemented _(coming soon)_ +- All labels are **auto-created with default colors** if missing + +--- + +## πŸ“€ Coming Soon + +- βœ… Issue deduplication +- βœ… Custom templates for issue bodies +- βœ… CLI usage outside GitHub +- βœ… LLM-powered summarization and classification +- βœ… Support for more languages and comment styles +- βœ… Customizable label creation and management +- βœ… Integration with project management tools (e.g., Jira, Trello) +- βœ… Support for multiple repositories in a single run +- βœ… Rate limiting and error handling improvements +- βœ… Customizable issue creation frequency (e.g., daily, weekly) +- βœ… Support for user-defined metadata tags +- βœ… Customizable issue assignment (e.g., to specific users or teams) +- βœ… Support for issue templates and custom fields +- βœ… Integration with CI/CD pipelines for automated issue tracking +- βœ… Support for issue comments and discussions +- βœ… Customizable notification settings (e.g., email, Slack) +- βœ… Support for issue closing and resolution tracking +- βœ… Customizable issue lifecycle management (e.g., open, in progress, closed) \ No newline at end of file From b4f7898a1c564c79b41c3cecdadf5ff256ab40dc Mon Sep 17 00:00:00 2001 From: Diogo Ribeiro Date: Wed, 16 Apr 2025 17:08:01 +0100 Subject: [PATCH 2/7] chore: more development --- .github/workflows/todo.yml | 21 ++- .gitignore | 5 +- ROADMAP.md | 103 +-------------- action.yml | 6 +- package.json | 3 +- src/ActionMain.ts | 91 +++---------- src/core/__tests__/extractTodos.test.ts | 46 +++++++ .../__tests__/extractTodosFromDir.test.ts | 28 ++++ src/core/__tests__/fixtures/nested/inner.py | 2 + src/core/__tests__/fixtures/one-file.ts | 2 + src/core/__tests__/issueManager.test.ts | 79 ++++++++++++ src/core/__tests__/labelManager.test.ts | 61 +++++++++ src/core/issueManager.ts | 89 +++++++++++++ src/core/labelManager.ts | 51 ++++++++ src/core/report.ts | 72 +++++++++++ src/core/todoUtils.ts | 17 +++ src/parser/types.ts | 14 +- src/templates/issueBody.md | 1 + src/templates/issueTitle.txt | 1 + src/templates/utils.ts | 25 ++++ yarn.lock | 121 ++++++++++++++++++ 21 files changed, 656 insertions(+), 182 deletions(-) create mode 100644 src/core/__tests__/extractTodos.test.ts create mode 100644 src/core/__tests__/extractTodosFromDir.test.ts create mode 100644 src/core/__tests__/fixtures/nested/inner.py create mode 100644 src/core/__tests__/fixtures/one-file.ts create mode 100644 src/core/__tests__/issueManager.test.ts create mode 100644 src/core/__tests__/labelManager.test.ts create mode 100644 src/core/issueManager.ts create mode 100644 src/core/labelManager.ts create mode 100644 src/core/report.ts create mode 100644 src/core/todoUtils.ts create mode 100644 src/templates/issueBody.md create mode 100644 src/templates/issueTitle.txt create mode 100644 src/templates/utils.ts diff --git a/.github/workflows/todo.yml b/.github/workflows/todo.yml index 15f0804..6b6e3b3 100644 --- a/.github/workflows/todo.yml +++ b/.github/workflows/todo.yml @@ -1,4 +1,4 @@ -name: Smart TODO Check +name: Smart TODO Tracker on: push: @@ -7,6 +7,10 @@ on: jobs: smart-todo: runs-on: ubuntu-latest + permissions: + contents: write + issues: write + steps: - uses: actions/checkout@v3 @@ -22,3 +26,18 @@ jobs: uses: ./ with: repo-token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + report: true + + - name: Upload TODO report + uses: actions/upload-artifact@v3 + with: + name: todo-report + path: TODO_REPORT.md + + - name: Commit TODO report + run: | + git config --global user.name "github-actions[bot]" + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git add TODO_REPORT.md + git commit -m "chore(report): update TODO report" || echo "No changes" + git push \ No newline at end of file diff --git a/.gitignore b/.gitignore index f94630c..dcd9a1e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ node_modules/ dist/ -.env \ No newline at end of file +.env + + +TODO_REPORT.md \ No newline at end of file diff --git a/ROADMAP.md b/ROADMAP.md index 42989c6..78909d5 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -44,8 +44,9 @@ A smart GitHub Action that detects, classifies, and transforms inline TODOs in y > Provide visibility into the evolution and structure of tracked TODOs. -- [ ] Markdown/HTML dashboard with summary statistics - _Total TODOs, grouped by folder, priority, author (`git blame`)_ +- [X] Markdown/HTML dashboard with summary statistics + _Total TODOs, grouped by folder, priority, author (`git blame`) β€” **now sorted by `priority` and `due` date**_ + - [ ] TODO history tracking (added/removed/modified) - [ ] Due date notifications or PR comments @@ -68,101 +69,3 @@ A smart GitHub Action that detects, classifies, and transforms inline TODOs in y - Clean architecture and modularity are core principles from day one. - LLM functionality will be optional and clearly separated from core logic. - Built with automation, extensibility, and developer workflows in mind. - ---- - -# πŸš€ Roadmap for TODO Issue Tracker 2.0 - -This project aims to build an intelligent GitHub Action that scans your codebase for TODOs, classifies them, and transforms them into contextualized GitHub Issues β€” with semantic analysis and multi-platform integration. - ---- - -## 🧱 Phase 1: Foundations and Parity with the Original Project - -🎯 Goal: Recreate the original functionality with clean, modular, and testable code. - -- [ ] Create the base project structure - - `src/` folder for source code - - Subfolders: `core/`, `parser/`, `tasks/`, `templates/`, etc. - -- [ ] Implement TODO parser - - Detect `TODO`, `FIXME`, `BUG`, etc. comments - - Support for multiple languages (`.js`, `.ts`, `.py`, `.go`, etc.) - -- [ ] Initial task system: GitHub Issues - - Create, update, and remove issues based on detected TODOs - -- [ ] Templating system for issue creation - - Customizable titles and descriptions via templates - -- [ ] Functional GitHub Action workflow - - `action.yml` definition file - - Example usage in `.github/workflows/todo.yml` - -- [ ] Unit testing with Jest or Vitest - ---- - -## 🧠 Phase 2: Intelligence and Semantics - -🎯 Goal: Make the system smarter by leveraging LLMs and contextual awareness. - -- [ ] Automatic TODO classification - - Use LLMs or heuristics to classify as `bug`, `enhancement`, `refactor`, etc. - -- [ ] Auto-generate issue titles and descriptions using LLMs - _Example: `Review sorting algorithm` β†’ `Optimize Sorting Algorithm for Edge Cases`_ - -- [ ] Extract `due date` and `priority` via inline metadata parsing - _Example: `TODO(priority=high, due=2025-06-01): improve this logic`_ - ---- - -## 🌍 Phase 3: Extended Support - -🎯 Goal: Make the project adaptable to diverse environments and workflows. - -- [ ] Support for multiple task management platforms - _GitHub, Jira, Notion, Trello, Linear (via APIs)_ - -- [ ] Internationalization (i18n) - _Detect TODOs written in different languages_ - -- [ ] Support for additional file types - _`.ipynb`, `.yaml`, `.md`, `.json`, `.xml`, and more_ - ---- - -## πŸ“Š Phase 4: Analysis and Reporting - -🎯 Goal: Provide visibility into the state and evolution of TODOs. - -- [ ] Markdown/HTML dashboard with metrics - _Total TODOs, grouped by folder, priority, author (`git blame`)_ - -- [ ] TODO history tracking - _Track when TODOs are added, removed, or changed over time_ - -- [ ] Notifications and reminders - _Comment on PRs or issues when due dates are approaching_ - ---- - -## πŸ” Phase 5: Optimizations and Contributions - -🎯 Goal: Ensure quality, performance, and ease of collaboration. - -- [ ] Plugin-based modular architecture -- [ ] CLI support (standalone usage outside GitHub Actions) -- [ ] Test coverage >90% -- [ ] Full documentation with usage examples -- [ ] Publish to GitHub Marketplace as an official Action - ---- - -## πŸ“Œ Notes - -- Modularity, testability, and code clarity are priorities from day one. -- LLM integration will be optional and cleanly decoupled from core logic. -- Designed with automation, extensibility, and developer experience in mind. - diff --git a/action.yml b/action.yml index a66d0d0..530b622 100644 --- a/action.yml +++ b/action.yml @@ -4,8 +4,12 @@ author: 'Diogo Ribeiro' inputs: repo-token: - description: 'GitHub token com permissΓ£o para criar issues' required: true + description: GitHub token to create issues + report: + required: false + description: Whether to generate a TODO markdown report + default: 'false' runs: using: 'node20' diff --git a/package.json b/package.json index 517af1d..c36931e 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "license": "MIT", "dependencies": { "@actions/core": "^1.10.0", - "@actions/github": "^5.1.1" + "@actions/github": "^5.1.1", + "@octokit/rest": "^21.1.1" }, "devDependencies": { "@types/node": "^20.11.17", diff --git a/src/ActionMain.ts b/src/ActionMain.ts index 1308e9a..66f54a9 100644 --- a/src/ActionMain.ts +++ b/src/ActionMain.ts @@ -3,56 +3,14 @@ import * as github from '@actions/github'; import path from 'path'; import { extractTodosFromDir } from './parser/extractTodosFromDir'; import { TodoItem } from './parser/types'; - -const LABELS_BY_TAG: Record = { - TODO: ['enhancement'], - FIXME: ['bug'], - BUG: ['bug'], - HACK: ['technical-debt'] -}; - -const DEFAULT_LABEL_COLOR = 'cccccc'; -const LABEL_COLORS: Record = { - bug: 'd73a4a', - enhancement: 'a2eeef', - todo: 'ededed', - 'technical-debt': 'f9d0c4' -}; - -function labelsFromMetadata(metadata?: Record): string[] { - if (!metadata) return []; - return Object.entries(metadata).map(([key, value]) => `${key}:${value}`); -} - -async function ensureLabelExists( - octokit: ReturnType, - owner: string, - repo: string, - label: string -) { - try { - await octokit.rest.issues.getLabel({ owner, repo, name: label }); - } catch (err: any) { - if (err.status === 404) { - const base = label.toLowerCase().split(':')[0]; - const color = LABEL_COLORS[base] || DEFAULT_LABEL_COLOR; - await octokit.rest.issues.createLabel({ - owner, - repo, - name: label, - color, - description: 'Auto-created by smart-todo-action' - }); - core.info(`🏷️ Created label "${label}"`); - } else { - core.warning(`⚠️ Failed to check/create label "${label}": ${err.message}`); - } - } -} +import { getExistingIssueTitles, createIssueIfNeeded } from './core/issueManager'; +import { generateMarkdownReport } from './core/report'; +import { limitTodos, todoKey } from './core/todoUtils'; async function run(): Promise { try { const token = core.getInput('repo-token', { required: true }); + const generateReport = core.getInput('report') === 'true'; const workspace = process.env.GITHUB_WORKSPACE || '.'; const todos: TodoItem[] = extractTodosFromDir(workspace); @@ -61,36 +19,25 @@ async function run(): Promise { core.info(`πŸ” Found ${todos.length} TODOs`); - const MAX_ISSUES = 5; - const todosToCreate = todos - .filter(todo => todo.text && todo.text.length > 5) - .slice(0, MAX_ISSUES); + const existingTitles = await getExistingIssueTitles(octokit, owner, repo); - for (const todo of todosToCreate) { - const title = `[${todo.tag}] ${todo.text}`; - const body = `Found in \`${todo.file}:${todo.line}\`\n\n\`\`\`\n${todo.text}\n\`\`\``; - const tag = todo.tag.toUpperCase(); - const baseLabels = LABELS_BY_TAG[tag] || ['todo']; - const metaLabels = labelsFromMetadata(todo.metadata); - const labels = [...baseLabels, ...metaLabels]; + const seenKeys = new Set(); + const uniqueTodos = todos.filter(todo => { + const key = todoKey(todo); + if (seenKeys.has(key)) return false; + seenKeys.add(key); + return true; + }); - for (const label of labels) { - await ensureLabelExists(octokit, owner, repo, label); - } + const todosToCreate = limitTodos(uniqueTodos, 5); - try { - await octokit.rest.issues.create({ - owner, - repo, - title, - body, - labels - }); + for (const todo of todosToCreate) { + await createIssueIfNeeded(octokit, owner, repo, todo, existingTitles); + } - core.info(`βœ… Created issue with labels [${labels.join(', ')}]: ${title}`); - } catch (err: any) { - core.warning(`⚠️ Failed to create issue for: ${title} β€” ${err.message}`); - } + if (generateReport) { + generateMarkdownReport(todos); + core.info('πŸ“ Generated TODO_REPORT.md'); } } catch (error: any) { diff --git a/src/core/__tests__/extractTodos.test.ts b/src/core/__tests__/extractTodos.test.ts new file mode 100644 index 0000000..0685764 --- /dev/null +++ b/src/core/__tests__/extractTodos.test.ts @@ -0,0 +1,46 @@ +import { describe, it, expect } from 'vitest'; +import { extractTodosFromFile } from '../../parser/extractTodos'; // Ensure this file exists at the specified path +import { TodoItem } from '../../parser/types'; + + + +describe('extractTodos', () => { + it('extracts simple TODOs with //', () => { + const content = `// TODO: clean this up\nconst a = 1;`; + const todos = extractTodosFromFile(content); + expect(todos.length).toBe(1); + expect(todos[0].text).toBe('clean this up'); + expect(todos[0].tag).toBe('TODO'); + expect(todos[0].line).toBe(1); + }); + + it('extracts multiple tags', () => { + const content = `// BUG: crashes\n# FIXME: something wrong`; + const todos = extractTodosFromFile(content); + expect(todos.length).toBe(2); + expect(todos.map(t => t.tag)).toEqual(['BUG', 'FIXME']); + }); + + it('extracts metadata key=value pairs', () => { + const content = `// TODO(priority=high, due=2025-06-01): fix it`; + const todos = extractTodosFromFile(content); + expect(todos.length).toBe(1); + expect(todos[0].metadata).toEqual({ + priority: 'high', + due: '2025-06-01' + }); + }); + + it('supports HTML comments', () => { + const content = ``; + const todos = extractTodosFromFile(content); + expect(todos.length).toBe(1); + expect(todos[0].tag).toBe('TODO'); + }); + + it('returns empty list if no TODOs are found', () => { + const content = `const x = 5; // just a comment`; + const todos = extractTodosFromFile(content); + expect(todos.length).toBe(0); + }); +}); diff --git a/src/core/__tests__/extractTodosFromDir.test.ts b/src/core/__tests__/extractTodosFromDir.test.ts new file mode 100644 index 0000000..485c9a9 --- /dev/null +++ b/src/core/__tests__/extractTodosFromDir.test.ts @@ -0,0 +1,28 @@ +import { describe, it, expect } from 'vitest'; +import path from 'path'; +import { extractTodosFromDir } from '../../parser/extractTodosFromDir'; + +describe('extractTodosFromDir', () => { + const base = path.join(__dirname, 'fixtures'); + + it('should extract TODOs from supported files recursively', () => { + const todos = extractTodosFromDir(base); + expect(todos.length).toBe(2); + + const texts = todos.map(t => t.text); + expect(texts).toContain('Refactor this module'); + expect(texts).toContain('Handle edge case'); + + const tags = todos.map(t => t.tag); + expect(tags).toContain('TODO'); + expect(tags).toContain('FIXME'); + }); + + it('should include correct file and line information', () => { + const todos = extractTodosFromDir(base); + const one = todos.find(t => t.text.includes('Refactor')); + expect(one?.file.endsWith('one-file.ts')).toBe(true); + expect(typeof one?.line).toBe('number'); + expect(one?.line).toBeGreaterThan(0); + }); +}); diff --git a/src/core/__tests__/fixtures/nested/inner.py b/src/core/__tests__/fixtures/nested/inner.py new file mode 100644 index 0000000..270bd10 --- /dev/null +++ b/src/core/__tests__/fixtures/nested/inner.py @@ -0,0 +1,2 @@ +# FIXME: Handle edge case +print("Running") diff --git a/src/core/__tests__/fixtures/one-file.ts b/src/core/__tests__/fixtures/one-file.ts new file mode 100644 index 0000000..cdfd083 --- /dev/null +++ b/src/core/__tests__/fixtures/one-file.ts @@ -0,0 +1,2 @@ +// TODO: Refactor this module +export const a = 42; diff --git a/src/core/__tests__/issueManager.test.ts b/src/core/__tests__/issueManager.test.ts new file mode 100644 index 0000000..719a000 --- /dev/null +++ b/src/core/__tests__/issueManager.test.ts @@ -0,0 +1,79 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import * as core from '@actions/core'; +import { getExistingIssueTitles, createIssueIfNeeded } from '../issueManager'; +import { TodoItem } from '../../parser/types'; + +// Mocks +const mockOctokit = { + rest: { + issues: { + listForRepo: vi.fn(), + getLabel: vi.fn(), + createLabel: vi.fn(), + create: vi.fn() + } + } +}; + +vi.mock('../labelManager', () => ({ + ensureLabelExists: vi.fn(), + LABELS_BY_TAG: { TODO: ['enhancement'] }, + labelsFromMetadata: () => ['priority:high'] +})); + +describe('getExistingIssueTitles', () => { + const octokit = mockOctokit as any; + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('should collect titles of open issues (paginated)', async () => { + octokit.rest.issues.listForRepo + .mockResolvedValueOnce({ data: [{ title: 'Issue 1' }, { title: 'Issue 2' }] }) + .mockResolvedValueOnce({ data: [] }); + + const titles = await getExistingIssueTitles(octokit, 'test-owner', 'test-repo'); + expect([...titles]).toEqual(['Issue 1', 'Issue 2']); + }); +}); + +describe('createIssueIfNeeded', () => { + const octokit = mockOctokit as any; + const owner = 'test-owner'; + const repo = 'test-repo'; + + const todo: TodoItem = { + tag: 'TODO', + text: 'Refactor component', + file: 'src/file.ts', + line: 42, + metadata: { priority: 'high' } + }; + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('should skip duplicate issues', async () => { + const existingTitles: Set = new Set(['[TODO] Refactor component']); + + await createIssueIfNeeded(octokit, owner, repo, todo, existingTitles); + + expect(octokit.rest.issues.create).not.toHaveBeenCalled(); + }); + + it('should create a new issue if not duplicated', async () => { + const existingTitles: Set = new Set(); + + await createIssueIfNeeded(octokit, owner, repo, todo, existingTitles); + + expect(octokit.rest.issues.create).toHaveBeenCalledWith({ + owner, + repo, + title: '[TODO] Refactor component', + body: expect.stringContaining('src/file.ts'), + labels: ['enhancement', 'priority:high'] + }); + }); +}); diff --git a/src/core/__tests__/labelManager.test.ts b/src/core/__tests__/labelManager.test.ts new file mode 100644 index 0000000..e07cb84 --- /dev/null +++ b/src/core/__tests__/labelManager.test.ts @@ -0,0 +1,61 @@ +import { describe, it, expect, vi } from 'vitest'; +import * as core from '@actions/core'; +import { labelsFromMetadata, ensureLabelExists } from '../labelManager'; + +const mockOctokit = { + rest: { + issues: { + getLabel: vi.fn(), + createLabel: vi.fn() + } + } +}; + +describe('labelsFromMetadata', () => { + it('should return key:value pairs from metadata object', () => { + const metadata = { priority: 'high', due: '2025-06-01' }; + const labels = labelsFromMetadata(metadata); + expect(labels).toEqual(['priority:high', 'due:2025-06-01']); + }); + + it('should return empty array if metadata is undefined', () => { + expect(labelsFromMetadata(undefined)).toEqual([]); + }); +}); + +describe('ensureLabelExists', () => { + const octokit = mockOctokit as any; + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('should not create label if it already exists', async () => { + octokit.rest.issues.getLabel.mockResolvedValueOnce({ status: 200 }); + + await ensureLabelExists(octokit, 'test-owner', 'test-repo', 'bug'); + + expect(octokit.rest.issues.getLabel).toHaveBeenCalled(); + expect(octokit.rest.issues.createLabel).not.toHaveBeenCalled(); + }); + + it('should create label if it does not exist (404)', async () => { + const error = { status: 404 }; + octokit.rest.issues.getLabel.mockRejectedValueOnce(error); + octokit.rest.issues.createLabel.mockResolvedValueOnce({}); + + await ensureLabelExists(octokit, 'test-owner', 'test-repo', 'priority:high'); + + expect(octokit.rest.issues.createLabel).toHaveBeenCalledWith({ + owner: 'test-owner', + repo: 'test-repo', + name: 'priority:high', + color: 'cccccc', + description: 'Auto-created by smart-todo-action' + }); + }); +}); +function beforeEach(callback: () => void) { + callback(); +} + diff --git a/src/core/issueManager.ts b/src/core/issueManager.ts new file mode 100644 index 0000000..b0e1b3d --- /dev/null +++ b/src/core/issueManager.ts @@ -0,0 +1,89 @@ +import * as core from '@actions/core'; +import * as github from '@actions/github'; +import { TodoItem } from '../parser/types'; +import { LABELS_BY_TAG, labelsFromMetadata, ensureLabelExists } from './labelManager'; +import { loadTemplate, applyTemplate } from '../templates/utils'; + +export async function getExistingIssueTitles( + octokit: ReturnType, + owner: string, + repo: string +): Promise> { + const existing = new Set(); + const perPage = 100; + let page = 1; + let done = false; + + while (!done) { + const { data } = await octokit.rest.issues.listForRepo({ + owner, + repo, + state: 'open', + per_page: perPage, + page + }); + + for (const issue of data) { + if (!issue.pull_request) { + existing.add(issue.title); + } + } + + if (data.length < perPage) { + done = true; + } else { + page++; + } + } + + return existing; +} + +export async function createIssueIfNeeded( + octokit: ReturnType, + owner: string, + repo: string, + todo: TodoItem, + existingTitles: Set + ): Promise { + const titleTemplate = loadTemplate('issueTitle.txt'); + const bodyTemplate = loadTemplate('issueBody.md'); + + const flattened = { + ...todo, + ...todo.metadata + } as Record; + + const title = applyTemplate(titleTemplate, flattened); + const body = applyTemplate(bodyTemplate, flattened); + + + if (existingTitles.has(title)) { + core.info(`🟑 Skipping duplicate issue: ${title}`); + return; + } + + const tag = todo.tag.toUpperCase(); + const baseLabels = LABELS_BY_TAG[tag] || ['todo']; + const metaLabels = labelsFromMetadata(todo.metadata); + const labels = [...baseLabels, ...metaLabels]; + + for (const label of labels) { + await ensureLabelExists(octokit, owner, repo, label); + } + + try { + await octokit.rest.issues.create({ + owner, + repo, + title, + body, + labels + }); + + core.info(`βœ… Created issue with labels [${labels.join(', ')}]: ${title}`); + } catch (err: any) { + core.warning(`⚠️ Failed to create issue for: ${title} β€” ${err.message}`); + } + } + \ No newline at end of file diff --git a/src/core/labelManager.ts b/src/core/labelManager.ts new file mode 100644 index 0000000..be73ed5 --- /dev/null +++ b/src/core/labelManager.ts @@ -0,0 +1,51 @@ +import * as github from '@actions/github'; +import * as core from '@actions/core'; + +// Labels atribuΓ­das por tipo de comentΓ‘rio +export const LABELS_BY_TAG: Record = { + TODO: ['enhancement'], + FIXME: ['bug'], + BUG: ['bug'], + HACK: ['technical-debt'] +}; + +// Cores associadas a cada label base +export const LABEL_COLORS: Record = { + bug: 'd73a4a', + enhancement: 'a2eeef', + todo: 'cfd3d7', + 'technical-debt': 'e99695' +}; + +// Fallback para labels metadata:priority, due, etc. +export function labelsFromMetadata(metadata?: Record): string[] { + if (!metadata) return []; + return Object.entries(metadata).map(([key, value]) => `${key}:${value}`); +} + +// Garante que uma label existe no repositΓ³rio +export async function ensureLabelExists( + octokit: ReturnType, + owner: string, + repo: string, + label: string +): Promise { + try { + await octokit.rest.issues.getLabel({ owner, repo, name: label }); + } catch (err: any) { + if (err.status === 404) { + const base = label.split(':')[0]; + const color = LABEL_COLORS[base] || 'cccccc'; + await octokit.rest.issues.createLabel({ + owner, + repo, + name: label, + color, + description: 'Auto-created by smart-todo-action' + }); + core.info(`🏷️ Created label: ${label}`); + } else { + core.warning(`⚠️ Could not verify label "${label}": ${err.message}`); + } + } +} diff --git a/src/core/report.ts b/src/core/report.ts new file mode 100644 index 0000000..dceb6f7 --- /dev/null +++ b/src/core/report.ts @@ -0,0 +1,72 @@ +import fs from 'fs'; +import path from 'path'; +import { TodoItem } from '../parser/types'; +import { todoKey } from './todoUtils'; + +const PRIORITY_ORDER = ['high', 'medium', 'low']; + +function getPriority(todo: TodoItem): string { + return todo.metadata?.priority?.toLowerCase?.() ?? ''; +} + +function getDue(todo: TodoItem): string { + return todo.metadata?.due ?? ''; +} + +function sortTodos(a: TodoItem, b: TodoItem): number { + const pa = getPriority(a); + const pb = getPriority(b); + + const prioA = PRIORITY_ORDER.indexOf(pa); + const prioB = PRIORITY_ORDER.indexOf(pb); + + if (prioA !== prioB) { + return (prioA === -1 ? Infinity : prioA) - (prioB === -1 ? Infinity : prioB); + } + + const da = getDue(a); + const db = getDue(b); + + if (da && db) return da.localeCompare(db); + if (da) return -1; + if (db) return 1; + + return 0; +} + +export function generateMarkdownReport(todos: TodoItem[]): void { + const seen = new Set(); + const uniqueTodos = todos.filter(todo => { + const key = todoKey(todo); + if (seen.has(key)) return false; + seen.add(key); + return true; + }); + + const grouped: Record = {}; + + for (const todo of uniqueTodos) { + if (!grouped[todo.tag]) grouped[todo.tag] = []; + grouped[todo.tag].push(todo); + } + + let content = `# πŸ“Œ TODO Report\n\nTotal unique TODOs: **${uniqueTodos.length}**\n\n`; + + for (const tag of Object.keys(grouped)) { + const sorted = grouped[tag].sort(sortTodos); + content += `## ${tag}\n\n`; + + for (const todo of sorted) { + const prio = getPriority(todo); + const due = getDue(todo); + const meta = [prio && `priority=${prio}`, due && `due=${due}`].filter(Boolean).join(', '); + content += `- \`${todo.file}:${todo.line}\` β€” ${todo.text}`; + if (meta) content += ` _( ${meta} )_`; + content += `\n`; + } + + content += '\n'; + } + + fs.writeFileSync(path.join(process.cwd(), 'TODO_REPORT.md'), content); +} diff --git a/src/core/todoUtils.ts b/src/core/todoUtils.ts new file mode 100644 index 0000000..4f875f9 --- /dev/null +++ b/src/core/todoUtils.ts @@ -0,0 +1,17 @@ +import { TodoItem } from '../parser/types'; + +export function buildIssueTitle(todo: TodoItem): string { + return `[${todo.tag}] ${todo.text}`; +} + +export function isValidTodo(todo: TodoItem): boolean { + return todo.text.length > 5; +} + +export function limitTodos(todos: TodoItem[], max = 5): TodoItem[] { + return todos.filter(isValidTodo).slice(0, max); +} + +export function todoKey(todo: TodoItem): string { + return `[${todo.tag}] ${todo.text}`; +} diff --git a/src/parser/types.ts b/src/parser/types.ts index 5ed40fb..ad1781a 100644 --- a/src/parser/types.ts +++ b/src/parser/types.ts @@ -1,8 +1,10 @@ export interface TodoItem { - file: string; - line: number; - tag: string; - text: string; - metadata?: Record; - } + tag: string; + text: string; + file: string; + line: number; + metadata?: Record; + + [key: string]: string | number | Record | undefined; +} \ No newline at end of file diff --git a/src/templates/issueBody.md b/src/templates/issueBody.md new file mode 100644 index 0000000..13fe0ce --- /dev/null +++ b/src/templates/issueBody.md @@ -0,0 +1 @@ +Found in `{{file}}:{{line}}` diff --git a/src/templates/issueTitle.txt b/src/templates/issueTitle.txt new file mode 100644 index 0000000..9dcd6c3 --- /dev/null +++ b/src/templates/issueTitle.txt @@ -0,0 +1 @@ +[{{tag}}] {{text}} diff --git a/src/templates/utils.ts b/src/templates/utils.ts new file mode 100644 index 0000000..bc0685b --- /dev/null +++ b/src/templates/utils.ts @@ -0,0 +1,25 @@ +import fs from 'fs'; +import path from 'path'; + +const DEFAULT_TEMPLATES: Record = { + 'issueTitle.txt': '[{{tag}}] {{text}}', + 'issueBody.md': 'Found in `{{file}}:{{line}}`\n\n```\n{{text}}\n```' +}; + +export function applyTemplate(template: string, data: Record) { + return template.replace(/{{(.*?)}}/g, (_, key) => String(data[key.trim()] ?? '')); +} + +export function loadTemplate(name: string): string { + try { + const filePath = path.join(__dirname, name); + return fs.readFileSync(filePath, 'utf-8'); + } catch (err) { + const fallback = DEFAULT_TEMPLATES[name]; + if (fallback) { + return fallback; + } else { + throw new Error(`Missing template: ${name}`); + } + } +} diff --git a/yarn.lock b/yarn.lock index b81317b..c8c5c1b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -179,6 +179,11 @@ dependencies: "@octokit/types" "^6.0.3" +"@octokit/auth-token@^5.0.0": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-5.1.2.tgz#68a486714d7a7fd1df56cb9bc89a860a0de866de" + integrity sha512-JcQDsBdg49Yky2w2ld20IHAlwr8d/d8N6NiOXbtuoPCqzbsiJgF633mVUw3x4mo0H5ypataQIX7SFu3yy44Mpw== + "@octokit/core@^3.6.0": version "3.6.0" resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.6.0.tgz#3376cb9f3008d9b3d110370d90e0a1fcd5fe6085" @@ -192,6 +197,27 @@ before-after-hook "^2.2.0" universal-user-agent "^6.0.0" +"@octokit/core@^6.1.4": + version "6.1.5" + resolved "https://registry.yarnpkg.com/@octokit/core/-/core-6.1.5.tgz#c2842aae87c2c2130b7dd33e8caa0f642dde2c67" + integrity sha512-vvmsN0r7rguA+FySiCsbaTTobSftpIDIpPW81trAmsv9TGxg3YCujAxRYp/Uy8xmDgYCzzgulG62H7KYUFmeIg== + dependencies: + "@octokit/auth-token" "^5.0.0" + "@octokit/graphql" "^8.2.2" + "@octokit/request" "^9.2.3" + "@octokit/request-error" "^6.1.8" + "@octokit/types" "^14.0.0" + before-after-hook "^3.0.2" + universal-user-agent "^7.0.0" + +"@octokit/endpoint@^10.1.4": + version "10.1.4" + resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-10.1.4.tgz#8783be38a32b95af8bcb6523af20ab4eed7a2adb" + integrity sha512-OlYOlZIsfEVZm5HCSR8aSg02T2lbUWOsCQoPKfTXJwDzcHQBrVBGdGXb89dv2Kw2ToZaRtudp8O3ZIYoaOjKlA== + dependencies: + "@octokit/types" "^14.0.0" + universal-user-agent "^7.0.2" + "@octokit/endpoint@^6.0.1": version "6.0.12" resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.12.tgz#3b4d47a4b0e79b1027fb8d75d4221928b2d05658" @@ -210,11 +236,37 @@ "@octokit/types" "^6.0.3" universal-user-agent "^6.0.0" +"@octokit/graphql@^8.2.2": + version "8.2.2" + resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-8.2.2.tgz#3db48c4ffdf07f99600cee513baf45e73eced4d1" + integrity sha512-Yi8hcoqsrXGdt0yObxbebHXFOiUA+2v3n53epuOg1QUgOB6c4XzvisBNVXJSl8RYA5KrDuSL2yq9Qmqe5N0ryA== + dependencies: + "@octokit/request" "^9.2.3" + "@octokit/types" "^14.0.0" + universal-user-agent "^7.0.0" + "@octokit/openapi-types@^12.11.0": version "12.11.0" resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-12.11.0.tgz#da5638d64f2b919bca89ce6602d059f1b52d3ef0" integrity sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ== +"@octokit/openapi-types@^24.2.0": + version "24.2.0" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-24.2.0.tgz#3d55c32eac0d38da1a7083a9c3b0cca77924f7d3" + integrity sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg== + +"@octokit/openapi-types@^25.0.0": + version "25.0.0" + resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-25.0.0.tgz#adeead36992abf966e89dcd53518d8b0dc910e0d" + integrity sha512-FZvktFu7HfOIJf2BScLKIEYjDsw6RKc7rBJCdvCTfKsVnx2GEB/Nbzjr29DUdb7vQhlzS/j8qDzdditP0OC6aw== + +"@octokit/plugin-paginate-rest@^11.4.2": + version "11.6.0" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.6.0.tgz#e5e9ff3530e867c3837fdbff94ce15a2468a1f37" + integrity sha512-n5KPteiF7pWKgBIBJSk8qzoZWcUkza2O6A0za97pMGVrGfPdltxrfmfF5GucHYvHGZD8BdaZmmHGz5cX/3gdpw== + dependencies: + "@octokit/types" "^13.10.0" + "@octokit/plugin-paginate-rest@^2.17.0": version "2.21.3" resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz#7f12532797775640dbb8224da577da7dc210c87e" @@ -222,6 +274,18 @@ dependencies: "@octokit/types" "^6.40.0" +"@octokit/plugin-request-log@^5.3.1": + version "5.3.1" + resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-5.3.1.tgz#ccb75d9705de769b2aa82bcd105cc96eb0c00f69" + integrity sha512-n/lNeCtq+9ofhC15xzmJCNKP2BWTv8Ih2TTy+jatNCCq/gQP/V7rK3fjIfuz0pDWDALO/o/4QY4hyOF6TQQFUw== + +"@octokit/plugin-rest-endpoint-methods@^13.3.0": + version "13.5.0" + resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-13.5.0.tgz#d8c8ca2123b305596c959a9134dfa8b0495b0ba6" + integrity sha512-9Pas60Iv9ejO3WlAX3maE1+38c5nqbJXV5GrncEfkndIpZrJ/WPMRd2xYDcPPEt5yzpxcjw9fWNoPhsSGzqKqw== + dependencies: + "@octokit/types" "^13.10.0" + "@octokit/plugin-rest-endpoint-methods@^5.13.0": version "5.16.2" resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz#7ee8bf586df97dd6868cf68f641354e908c25342" @@ -239,6 +303,13 @@ deprecation "^2.0.0" once "^1.4.0" +"@octokit/request-error@^6.1.8": + version "6.1.8" + resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-6.1.8.tgz#3c7ce1ca6721eabd43dbddc76b44860de1fdea75" + integrity sha512-WEi/R0Jmq+IJKydWlKDmryPcmdYSVjL3ekaiEL1L9eo1sUnqMJ+grqmC9cjk7CA7+b2/T397tO5d8YLOH3qYpQ== + dependencies: + "@octokit/types" "^14.0.0" + "@octokit/request@^5.6.0", "@octokit/request@^5.6.3": version "5.6.3" resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.6.3.tgz#19a022515a5bba965ac06c9d1334514eb50c48b0" @@ -251,6 +322,41 @@ node-fetch "^2.6.7" universal-user-agent "^6.0.0" +"@octokit/request@^9.2.3": + version "9.2.3" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-9.2.3.tgz#00d023ad690903d952e4dd31e3f5804ef98fcd24" + integrity sha512-Ma+pZU8PXLOEYzsWf0cn/gY+ME57Wq8f49WTXA8FMHp2Ps9djKw//xYJ1je8Hm0pR2lU9FUGeJRWOtxq6olt4w== + dependencies: + "@octokit/endpoint" "^10.1.4" + "@octokit/request-error" "^6.1.8" + "@octokit/types" "^14.0.0" + fast-content-type-parse "^2.0.0" + universal-user-agent "^7.0.2" + +"@octokit/rest@^21.1.1": + version "21.1.1" + resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-21.1.1.tgz#7a70455ca451b1d253e5b706f35178ceefb74de2" + integrity sha512-sTQV7va0IUVZcntzy1q3QqPm/r8rWtDCqpRAmb8eXXnKkjoQEtFe3Nt5GTVsHft+R6jJoHeSiVLcgcvhtue/rg== + dependencies: + "@octokit/core" "^6.1.4" + "@octokit/plugin-paginate-rest" "^11.4.2" + "@octokit/plugin-request-log" "^5.3.1" + "@octokit/plugin-rest-endpoint-methods" "^13.3.0" + +"@octokit/types@^13.10.0": + version "13.10.0" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-13.10.0.tgz#3e7c6b19c0236c270656e4ea666148c2b51fd1a3" + integrity sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA== + dependencies: + "@octokit/openapi-types" "^24.2.0" + +"@octokit/types@^14.0.0": + version "14.0.0" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-14.0.0.tgz#bbd1d31e2269940789ef143b1c37918aae09adc4" + integrity sha512-VVmZP0lEhbo2O1pdq63gZFiGCKkm8PPp8AUOijlwPO6hojEVjspA0MWKP7E4hbvGxzFKNqKr6p0IYtOH/Wf/zA== + dependencies: + "@octokit/openapi-types" "^25.0.0" + "@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.39.0", "@octokit/types@^6.40.0": version "6.41.0" resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.41.0.tgz#e58ef78d78596d2fb7df9c6259802464b5f84a04" @@ -451,6 +557,11 @@ before-after-hook@^2.2.0: resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.3.tgz#c51e809c81a4e354084422b9b26bad88249c517c" integrity sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ== +before-after-hook@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-3.0.2.tgz#d5665a5fa8b62294a5aa0a499f933f4a1016195d" + integrity sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A== + cac@^6.7.14: version "6.7.14" resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" @@ -565,6 +676,11 @@ execa@^8.0.1: signal-exit "^4.1.0" strip-final-newline "^3.0.0" +fast-content-type-parse@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-content-type-parse/-/fast-content-type-parse-2.0.1.tgz#c236124534ee2cb427c8d8e5ba35a4856947847b" + integrity sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q== + fsevents@~2.3.2, fsevents@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" @@ -889,6 +1005,11 @@ universal-user-agent@^6.0.0: resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.1.tgz#15f20f55da3c930c57bddbf1734c6654d5fd35aa" integrity sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ== +universal-user-agent@^7.0.0, universal-user-agent@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-7.0.2.tgz#52e7d0e9b3dc4df06cc33cb2b9fd79041a54827e" + integrity sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q== + vite-node@1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.6.1.tgz#fff3ef309296ea03ceaa6ca4bb660922f5416c57" From efae8c0e397077d9c2c57c0494d0160fdebb42fd Mon Sep 17 00:00:00 2001 From: Diogo Ribeiro Date: Wed, 16 Apr 2025 19:06:15 +0100 Subject: [PATCH 3/7] chore: development work --- .github/workflows/todo.yml | 4 +- .github/workflows/todo/issueBody.md | 3 ++ .github/workflows/todo/issueTitle.txt | 1 + README.md | 39 +++++++++++++- action.yml | 10 ++++ src/ActionMain.ts | 12 ++++- src/core/__tests__/applyTemplate.test.ts | 40 +++++++++++++++ src/core/__tests__/commentPatterns.test.ts | 46 +++++++++++++++++ src/core/__tests__/extractTodos.test.ts | 14 ++--- .../__tests__/extractTodosFromContent.test.ts | 31 +++++++++++ src/core/issueManager.ts | 4 +- src/parser/extractTodosFromContent.ts | 51 +++++++++++++++++++ src/templates/utils.ts | 22 ++++---- 13 files changed, 256 insertions(+), 21 deletions(-) create mode 100644 .github/workflows/todo/issueBody.md create mode 100644 .github/workflows/todo/issueTitle.txt create mode 100644 src/core/__tests__/applyTemplate.test.ts create mode 100644 src/core/__tests__/commentPatterns.test.ts create mode 100644 src/core/__tests__/extractTodosFromContent.test.ts create mode 100644 src/parser/extractTodosFromContent.ts diff --git a/.github/workflows/todo.yml b/.github/workflows/todo.yml index 6b6e3b3..3061d3d 100644 --- a/.github/workflows/todo.yml +++ b/.github/workflows/todo.yml @@ -26,6 +26,8 @@ jobs: uses: ./ with: repo-token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + issue-title-template: src/templates/issueTitle.txt + issue-body-template: src/templates/issueBody.md report: true - name: Upload TODO report @@ -40,4 +42,4 @@ jobs: git config --global user.email "github-actions[bot]@users.noreply.github.com" git add TODO_REPORT.md git commit -m "chore(report): update TODO report" || echo "No changes" - git push \ No newline at end of file + git push diff --git a/.github/workflows/todo/issueBody.md b/.github/workflows/todo/issueBody.md new file mode 100644 index 0000000..db52414 --- /dev/null +++ b/.github/workflows/todo/issueBody.md @@ -0,0 +1,3 @@ +πŸ—‚ **File:** `{{file}}:{{line}}` + +πŸ“ **Content:** \ No newline at end of file diff --git a/.github/workflows/todo/issueTitle.txt b/.github/workflows/todo/issueTitle.txt new file mode 100644 index 0000000..9dcd6c3 --- /dev/null +++ b/.github/workflows/todo/issueTitle.txt @@ -0,0 +1 @@ +[{{tag}}] {{text}} diff --git a/README.md b/README.md index 0100a23..330b01e 100644 --- a/README.md +++ b/README.md @@ -98,4 +98,41 @@ If a label like `priority:high` or `due:2025-06-01` doesn't exist, it will be au - βœ… Support for issue comments and discussions - βœ… Customizable notification settings (e.g., email, Slack) - βœ… Support for issue closing and resolution tracking -- βœ… Customizable issue lifecycle management (e.g., open, in progress, closed) \ No newline at end of file +- βœ… Customizable issue lifecycle management (e.g., open, in progress, closed) + + +```plaintext +smart-todo-action/ +β”œβ”€β”€ .github/ +β”‚ └── workflows/ +β”‚ └── todo.yml +β”‚ +β”œβ”€β”€ dist/ +β”‚ └── index.js +β”‚ +β”œβ”€β”€ src/ +β”‚ β”œβ”€β”€ core/ +β”‚ β”‚ β”œβ”€β”€ issueManager.ts +β”‚ β”‚ β”œβ”€β”€ labelManager.ts # πŸ†• Label logic (static + metadata + creation) +β”‚ β”‚ β”œβ”€β”€ report.ts +β”‚ β”‚ β”œβ”€β”€ todoUtils.ts +β”‚ β”‚ └── __tests__/ # (opcional) unit tests +β”‚ +β”‚ β”œβ”€β”€ parser/ +β”‚ β”‚ β”œβ”€β”€ extractTodosFromDir.ts +β”‚ β”‚ β”œβ”€β”€ extractTodosFromFile.ts +β”‚ β”‚ └── types.ts +β”‚ +β”‚ β”œβ”€β”€ templates/ +β”‚ β”‚ β”œβ”€β”€ issueTitle.txt +β”‚ β”‚ β”œβ”€β”€ issueBody.md +β”‚ β”‚ └── utils.ts +β”‚ +β”‚ └── ActionMain.ts +β”‚ +β”œβ”€β”€ .gitignore +β”œβ”€β”€ action.yml +β”œβ”€β”€ package.json +β”œβ”€β”€ tsconfig.json +└── README.md +``` \ No newline at end of file diff --git a/action.yml b/action.yml index 530b622..9eaf551 100644 --- a/action.yml +++ b/action.yml @@ -6,11 +6,20 @@ inputs: repo-token: required: true description: GitHub token to create issues + report: required: false description: Whether to generate a TODO markdown report default: 'false' + issue-title-template: + required: false + description: Optional path to custom issue title template + + issue-body-template: + required: false + description: Optional path to custom issue body template + runs: using: 'node20' main: 'dist/index.js' @@ -18,3 +27,4 @@ runs: branding: icon: 'check-circle' color: 'blue' + diff --git a/src/ActionMain.ts b/src/ActionMain.ts index 66f54a9..f0b0648 100644 --- a/src/ActionMain.ts +++ b/src/ActionMain.ts @@ -11,6 +11,8 @@ async function run(): Promise { try { const token = core.getInput('repo-token', { required: true }); const generateReport = core.getInput('report') === 'true'; + const titleTemplatePath = core.getInput('issue-title-template'); + const bodyTemplatePath = core.getInput('issue-body-template'); const workspace = process.env.GITHUB_WORKSPACE || '.'; const todos: TodoItem[] = extractTodosFromDir(workspace); @@ -32,7 +34,15 @@ async function run(): Promise { const todosToCreate = limitTodos(uniqueTodos, 5); for (const todo of todosToCreate) { - await createIssueIfNeeded(octokit, owner, repo, todo, existingTitles); + await createIssueIfNeeded( + octokit, + owner, + repo, + todo, + existingTitles, + titleTemplatePath, + bodyTemplatePath + ); } if (generateReport) { diff --git a/src/core/__tests__/applyTemplate.test.ts b/src/core/__tests__/applyTemplate.test.ts new file mode 100644 index 0000000..dea01fa --- /dev/null +++ b/src/core/__tests__/applyTemplate.test.ts @@ -0,0 +1,40 @@ +import { applyTemplate } from '../../templates/utils'; +import { describe, it, expect } from 'vitest' + +describe('applyTemplate', () => { + it('replaces simple variables', () => { + const template = '[{{tag}}] {{text}}'; + const data = { + tag: 'TODO', + text: 'Implement login flow' + }; + + const result = applyTemplate(template, data); + expect(result).toBe('[TODO] Implement login flow'); + }); + + it('ignores missing variables', () => { + const template = 'Priority: {{priority}}'; + const data = { + tag: 'TODO' + }; + + const result = applyTemplate(template, data); + expect(result).toBe('Priority: '); + }); + + it('handles numeric values', () => { + const template = 'Line {{line}}: {{text}}'; + const data = { + line: 42, + text: 'Optimize loop' + }; + + const result = applyTemplate(template, data); + expect(result).toBe('Line 42: Optimize loop'); + }); +}); + + + + diff --git a/src/core/__tests__/commentPatterns.test.ts b/src/core/__tests__/commentPatterns.test.ts new file mode 100644 index 0000000..90d7d21 --- /dev/null +++ b/src/core/__tests__/commentPatterns.test.ts @@ -0,0 +1,46 @@ +import { describe, it, expect } from 'vitest'; +import { extractTodosFromString } from '../../parser/extractTodosFromContent'; + +describe('extractTodosFromString - comment support by extension', () => { + it('extracts from JS-style (//) for .js/.ts/.go/.java', () => { + const code = `// TODO: js comment\n// BUG: broken`; + const extensions = ['.js', '.ts', '.go', '.java']; + + for (const ext of extensions) { + const todos = extractTodosFromString(code, ext); + expect(todos.length).toBe(2); + expect(todos[0].tag).toBe('TODO'); + expect(todos[1].tag).toBe('BUG'); + } + }); + + it('extracts from Python-style (#) for .py/.sh/.rb', () => { + const code = `# TODO: python comment\n# FIXME: fix me`; + const extensions = ['.py', '.sh', '.rb']; + + for (const ext of extensions) { + const todos = extractTodosFromString(code, ext); + expect(todos.length).toBe(2); + expect(todos[0].tag).toBe('TODO'); + expect(todos[1].tag).toBe('FIXME'); + } + }); + + it('extracts from HTML-style () for .html/.xml', () => { + const code = `\n`; + const extensions = ['.html', '.xml']; + + for (const ext of extensions) { + const todos = extractTodosFromString(code, ext); + expect(todos.length).toBe(2); + expect(todos[0].tag).toBe('TODO'); + expect(todos[1].tag).toBe('HACK'); + } + }); + + it('returns [] for unsupported extensions', () => { + const code = `// TODO: will not be parsed`; + const todos = extractTodosFromString(code, '.txt'); + expect(todos).toEqual([]); + }); +}); diff --git a/src/core/__tests__/extractTodos.test.ts b/src/core/__tests__/extractTodos.test.ts index 0685764..00f6e61 100644 --- a/src/core/__tests__/extractTodos.test.ts +++ b/src/core/__tests__/extractTodos.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect } from 'vitest'; -import { extractTodosFromFile } from '../../parser/extractTodos'; // Ensure this file exists at the specified path +import { extractTodosFromString } from '../../parser/extractTodosFromContent'; import { TodoItem } from '../../parser/types'; @@ -7,7 +7,7 @@ import { TodoItem } from '../../parser/types'; describe('extractTodos', () => { it('extracts simple TODOs with //', () => { const content = `// TODO: clean this up\nconst a = 1;`; - const todos = extractTodosFromFile(content); + const todos = extractTodosFromString(content, '.js'); expect(todos.length).toBe(1); expect(todos[0].text).toBe('clean this up'); expect(todos[0].tag).toBe('TODO'); @@ -15,15 +15,15 @@ describe('extractTodos', () => { }); it('extracts multiple tags', () => { - const content = `// BUG: crashes\n# FIXME: something wrong`; - const todos = extractTodosFromFile(content); + const content = `# BUG: crashes\n# FIXME: something wrong`; + const todos = extractTodosFromString(content, '.py'); expect(todos.length).toBe(2); expect(todos.map(t => t.tag)).toEqual(['BUG', 'FIXME']); }); it('extracts metadata key=value pairs', () => { const content = `// TODO(priority=high, due=2025-06-01): fix it`; - const todos = extractTodosFromFile(content); + const todos = extractTodosFromString(content, '.js'); expect(todos.length).toBe(1); expect(todos[0].metadata).toEqual({ priority: 'high', @@ -33,14 +33,14 @@ describe('extractTodos', () => { it('supports HTML comments', () => { const content = ``; - const todos = extractTodosFromFile(content); + const todos = extractTodosFromString(content, '.html'); expect(todos.length).toBe(1); expect(todos[0].tag).toBe('TODO'); }); it('returns empty list if no TODOs are found', () => { const content = `const x = 5; // just a comment`; - const todos = extractTodosFromFile(content); + const todos = extractTodosFromString(content, '.js'); expect(todos.length).toBe(0); }); }); diff --git a/src/core/__tests__/extractTodosFromContent.test.ts b/src/core/__tests__/extractTodosFromContent.test.ts new file mode 100644 index 0000000..7e6844e --- /dev/null +++ b/src/core/__tests__/extractTodosFromContent.test.ts @@ -0,0 +1,31 @@ +import { extractTodosFromString } from '../../parser/extractTodosFromContent'; +import { describe, it, expect } from 'vitest' + +describe('extractTodosFromString', () => { + it('extracts multiple TODO-style tags', () => { + const content = `// BUG: crash here\n# FIXME: wrong\n`; + const jsTodos = extractTodosFromString(content, '.js'); + const pyTodos = extractTodosFromString(content, '.py'); + const htmlTodos = extractTodosFromString(content, '.html'); + + expect(jsTodos.length).toBe(1); + expect(jsTodos[0].tag).toBe('BUG'); + + expect(pyTodos.length).toBe(1); + expect(pyTodos[0].tag).toBe('FIXME'); + + expect(htmlTodos.length).toBe(1); + expect(htmlTodos[0].tag).toBe('TODO'); + }); + + it('extracts metadata key=value pairs', () => { + const content = `// TODO(priority=high, due=2025-06-01): fix it`; + const todos = extractTodosFromString(content, '.js'); + + expect(todos.length).toBe(1); + expect(todos[0].metadata).toEqual({ + priority: 'high', + due: '2025-06-01' + }); + }); +}); diff --git a/src/core/issueManager.ts b/src/core/issueManager.ts index b0e1b3d..f44c5de 100644 --- a/src/core/issueManager.ts +++ b/src/core/issueManager.ts @@ -44,7 +44,9 @@ export async function createIssueIfNeeded( owner: string, repo: string, todo: TodoItem, - existingTitles: Set + existingTitles: Set, + titlePath?: string, + bodyPath?: string ): Promise { const titleTemplate = loadTemplate('issueTitle.txt'); const bodyTemplate = loadTemplate('issueBody.md'); diff --git a/src/parser/extractTodosFromContent.ts b/src/parser/extractTodosFromContent.ts new file mode 100644 index 0000000..717fc10 --- /dev/null +++ b/src/parser/extractTodosFromContent.ts @@ -0,0 +1,51 @@ +import { TodoItem } from './types'; + +const COMMENT_PATTERNS = [ + { ext: ['.ts', '.js', '.java', '.go'], pattern: /^\s*\/\/\s*(.*)$/ }, + { ext: ['.py', '.sh', '.rb'], pattern: /^\s*#\s*(.*)$/ }, + { ext: ['.html', '.xml'], pattern: // } +]; + +const TAG_REGEX = /(TODO|FIXME|BUG|HACK)(\([^)]*\))?:?\s*(.*)/i; + +function extractMetadata(str: string): Record { + const meta: Record = {}; + const match = str.match(/\((.*?)\)/); + if (match) { + const content = match[1]; + content.split(',').forEach(pair => { + const [key, val] = pair.split('=').map(s => s.trim()); + if (key && val) meta[key] = val; + }); + } + return meta; +} + +export function extractTodosFromString(content: string, ext: string): TodoItem[] { + const pattern = COMMENT_PATTERNS.find(p => p.ext.includes(ext)); + if (!pattern) return []; + + const lines = content.split('\n'); + const todos: TodoItem[] = []; + + lines.forEach((line, idx) => { + const commentMatch = line.match(pattern.pattern); + if (commentMatch) { + const comment = commentMatch[1]; + const tagMatch = comment.match(TAG_REGEX); + if (tagMatch) { + const [_, tag, metaRaw, text] = tagMatch; + const metadata = metaRaw ? extractMetadata(metaRaw) : undefined; + todos.push({ + file: `inline${ext}`, + line: idx + 1, + tag, + text: text.trim(), + metadata + }); + } + } + }); + + return todos; +} diff --git a/src/templates/utils.ts b/src/templates/utils.ts index bc0685b..9b6f720 100644 --- a/src/templates/utils.ts +++ b/src/templates/utils.ts @@ -6,20 +6,22 @@ const DEFAULT_TEMPLATES: Record = { 'issueBody.md': 'Found in `{{file}}:{{line}}`\n\n```\n{{text}}\n```' }; -export function applyTemplate(template: string, data: Record) { +export function applyTemplate(template: string, data: Record): string { return template.replace(/{{(.*?)}}/g, (_, key) => String(data[key.trim()] ?? '')); } -export function loadTemplate(name: string): string { +export function loadTemplate(templatePath: string): string { + const isRelative = !path.isAbsolute(templatePath); + const resolvedPath = isRelative + ? path.resolve(process.cwd(), templatePath) + : templatePath; + try { - const filePath = path.join(__dirname, name); - return fs.readFileSync(filePath, 'utf-8'); + return fs.readFileSync(resolvedPath, 'utf-8'); } catch (err) { - const fallback = DEFAULT_TEMPLATES[name]; - if (fallback) { - return fallback; - } else { - throw new Error(`Missing template: ${name}`); - } + const fallback = DEFAULT_TEMPLATES[path.basename(templatePath)]; + if (fallback) return fallback; + throw new Error(`Template not found: ${templatePath}`); } } + From afce3bff7b00f65b77de8f9acc0c0124d970396d Mon Sep 17 00:00:00 2001 From: Diogo Ribeiro Date: Wed, 16 Apr 2025 22:15:35 +0100 Subject: [PATCH 4/7] chore: github action test run --- .github/workflows/run_tests.yml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .github/workflows/run_tests.yml diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml new file mode 100644 index 0000000..2f13965 --- /dev/null +++ b/.github/workflows/run_tests.yml @@ -0,0 +1,32 @@ +name: Run Tests + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: 20 + + - name: Install dependencies + run: yarn install + + - name: Run tests with coverage + run: yarn vitest run --coverage + + # - name: Upload coverage to Codecov + # uses: codecov/codecov-action@v5 + # with: + # files: coverage/coverage-final.json + # token: ${{ secrets.CODECOV_TOKEN }} # optional if public repo From 27abfba88170e819f4f24dad98ee8d7d34884b94 Mon Sep 17 00:00:00 2001 From: Diogo Ribeiro Date: Wed, 16 Apr 2025 22:22:01 +0100 Subject: [PATCH 5/7] chore: development --- coverage/base.css | 224 ++++ coverage/block-navigation.js | 87 ++ coverage/favicon.png | Bin 0 -> 445 bytes coverage/index.html | 161 +++ coverage/prettify.css | 1 + coverage/prettify.js | 2 + coverage/sort-arrow-sprite.png | Bin 0 -> 138 bytes coverage/sorter.js | 196 +++ coverage/src/ActionMain.ts.html | 259 ++++ coverage/src/core/index.html | 161 +++ coverage/src/core/issueManager.ts.html | 355 ++++++ coverage/src/core/labelManager.ts.html | 238 ++++ coverage/src/core/report.ts.html | 301 +++++ coverage/src/core/todoUtils.ts.html | 136 ++ coverage/src/index.html | 146 +++ coverage/src/main.ts.html | 91 ++ coverage/src/parser/extractTodos.ts.html | 247 ++++ .../parser/extractTodosFromContent.ts.html | 238 ++++ .../src/parser/extractTodosFromDir.ts.html | 178 +++ coverage/src/parser/index.html | 161 +++ coverage/src/parser/types.ts.html | 112 ++ coverage/src/templates/index.html | 116 ++ coverage/src/templates/utils.ts.html | 166 +++ coverage/src/testTodo.ts.html | 97 ++ package.json | 3 +- vitest.config.ts | 11 + yarn.lock | 1118 ++++++++++------- 27 files changed, 4368 insertions(+), 437 deletions(-) create mode 100644 coverage/base.css create mode 100644 coverage/block-navigation.js create mode 100644 coverage/favicon.png create mode 100644 coverage/index.html create mode 100644 coverage/prettify.css create mode 100644 coverage/prettify.js create mode 100644 coverage/sort-arrow-sprite.png create mode 100644 coverage/sorter.js create mode 100644 coverage/src/ActionMain.ts.html create mode 100644 coverage/src/core/index.html create mode 100644 coverage/src/core/issueManager.ts.html create mode 100644 coverage/src/core/labelManager.ts.html create mode 100644 coverage/src/core/report.ts.html create mode 100644 coverage/src/core/todoUtils.ts.html create mode 100644 coverage/src/index.html create mode 100644 coverage/src/main.ts.html create mode 100644 coverage/src/parser/extractTodos.ts.html create mode 100644 coverage/src/parser/extractTodosFromContent.ts.html create mode 100644 coverage/src/parser/extractTodosFromDir.ts.html create mode 100644 coverage/src/parser/index.html create mode 100644 coverage/src/parser/types.ts.html create mode 100644 coverage/src/templates/index.html create mode 100644 coverage/src/templates/utils.ts.html create mode 100644 coverage/src/testTodo.ts.html create mode 100644 vitest.config.ts diff --git a/coverage/base.css b/coverage/base.css new file mode 100644 index 0000000..f418035 --- /dev/null +++ b/coverage/base.css @@ -0,0 +1,224 @@ +body, html { + margin:0; padding: 0; + height: 100%; +} +body { + font-family: Helvetica Neue, Helvetica, Arial; + font-size: 14px; + color:#333; +} +.small { font-size: 12px; } +*, *:after, *:before { + -webkit-box-sizing:border-box; + -moz-box-sizing:border-box; + box-sizing:border-box; + } +h1 { font-size: 20px; margin: 0;} +h2 { font-size: 14px; } +pre { + font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; + margin: 0; + padding: 0; + -moz-tab-size: 2; + -o-tab-size: 2; + tab-size: 2; +} +a { color:#0074D9; text-decoration:none; } +a:hover { text-decoration:underline; } +.strong { font-weight: bold; } +.space-top1 { padding: 10px 0 0 0; } +.pad2y { padding: 20px 0; } +.pad1y { padding: 10px 0; } +.pad2x { padding: 0 20px; } +.pad2 { padding: 20px; } +.pad1 { padding: 10px; } +.space-left2 { padding-left:55px; } +.space-right2 { padding-right:20px; } +.center { text-align:center; } +.clearfix { display:block; } +.clearfix:after { + content:''; + display:block; + height:0; + clear:both; + visibility:hidden; + } +.fl { float: left; } +@media only screen and (max-width:640px) { + .col3 { width:100%; max-width:100%; } + .hide-mobile { display:none!important; } +} + +.quiet { + color: #7f7f7f; + color: rgba(0,0,0,0.5); +} +.quiet a { opacity: 0.7; } + +.fraction { + font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 10px; + color: #555; + background: #E8E8E8; + padding: 4px 5px; + border-radius: 3px; + vertical-align: middle; +} + +div.path a:link, div.path a:visited { color: #333; } +table.coverage { + border-collapse: collapse; + margin: 10px 0 0 0; + padding: 0; +} + +table.coverage td { + margin: 0; + padding: 0; + vertical-align: top; +} +table.coverage td.line-count { + text-align: right; + padding: 0 5px 0 20px; +} +table.coverage td.line-coverage { + text-align: right; + padding-right: 10px; + min-width:20px; +} + +table.coverage td span.cline-any { + display: inline-block; + padding: 0 5px; + width: 100%; +} +.missing-if-branch { + display: inline-block; + margin-right: 5px; + border-radius: 3px; + position: relative; + padding: 0 4px; + background: #333; + color: yellow; +} + +.skip-if-branch { + display: none; + margin-right: 10px; + position: relative; + padding: 0 4px; + background: #ccc; + color: white; +} +.missing-if-branch .typ, .skip-if-branch .typ { + color: inherit !important; +} +.coverage-summary { + border-collapse: collapse; + width: 100%; +} +.coverage-summary tr { border-bottom: 1px solid #bbb; } +.keyline-all { border: 1px solid #ddd; } +.coverage-summary td, .coverage-summary th { padding: 10px; } +.coverage-summary tbody { border: 1px solid #bbb; } +.coverage-summary td { border-right: 1px solid #bbb; } +.coverage-summary td:last-child { border-right: none; } +.coverage-summary th { + text-align: left; + font-weight: normal; + white-space: nowrap; +} +.coverage-summary th.file { border-right: none !important; } +.coverage-summary th.pct { } +.coverage-summary th.pic, +.coverage-summary th.abs, +.coverage-summary td.pct, +.coverage-summary td.abs { text-align: right; } +.coverage-summary td.file { white-space: nowrap; } +.coverage-summary td.pic { min-width: 120px !important; } +.coverage-summary tfoot td { } + +.coverage-summary .sorter { + height: 10px; + width: 7px; + display: inline-block; + margin-left: 0.5em; + background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; +} +.coverage-summary .sorted .sorter { + background-position: 0 -20px; +} +.coverage-summary .sorted-desc .sorter { + background-position: 0 -10px; +} +.status-line { height: 10px; } +/* yellow */ +.cbranch-no { background: yellow !important; color: #111; } +/* dark red */ +.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } +.low .chart { border:1px solid #C21F39 } +.highlighted, +.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ + background: #C21F39 !important; +} +/* medium red */ +.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } +/* light red */ +.low, .cline-no { background:#FCE1E5 } +/* light green */ +.high, .cline-yes { background:rgb(230,245,208) } +/* medium green */ +.cstat-yes { background:rgb(161,215,106) } +/* dark green */ +.status-line.high, .high .cover-fill { background:rgb(77,146,33) } +.high .chart { border:1px solid rgb(77,146,33) } +/* dark yellow (gold) */ +.status-line.medium, .medium .cover-fill { background: #f9cd0b; } +.medium .chart { border:1px solid #f9cd0b; } +/* light yellow */ +.medium { background: #fff4c2; } + +.cstat-skip { background: #ddd; color: #111; } +.fstat-skip { background: #ddd; color: #111 !important; } +.cbranch-skip { background: #ddd !important; color: #111; } + +span.cline-neutral { background: #eaeaea; } + +.coverage-summary td.empty { + opacity: .5; + padding-top: 4px; + padding-bottom: 4px; + line-height: 1; + color: #888; +} + +.cover-fill, .cover-empty { + display:inline-block; + height: 12px; +} +.chart { + line-height: 0; +} +.cover-empty { + background: white; +} +.cover-full { + border-right: none !important; +} +pre.prettyprint { + border: none !important; + padding: 0 !important; + margin: 0 !important; +} +.com { color: #999 !important; } +.ignore-none { color: #999; font-weight: normal; } + +.wrapper { + min-height: 100%; + height: auto !important; + height: 100%; + margin: 0 auto -48px; +} +.footer, .push { + height: 48px; +} diff --git a/coverage/block-navigation.js b/coverage/block-navigation.js new file mode 100644 index 0000000..cc12130 --- /dev/null +++ b/coverage/block-navigation.js @@ -0,0 +1,87 @@ +/* eslint-disable */ +var jumpToCode = (function init() { + // Classes of code we would like to highlight in the file view + var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; + + // Elements to highlight in the file listing view + var fileListingElements = ['td.pct.low']; + + // We don't want to select elements that are direct descendants of another match + var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` + + // Selecter that finds elements on the page to which we can jump + var selector = + fileListingElements.join(', ') + + ', ' + + notSelector + + missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` + + // The NodeList of matching elements + var missingCoverageElements = document.querySelectorAll(selector); + + var currentIndex; + + function toggleClass(index) { + missingCoverageElements + .item(currentIndex) + .classList.remove('highlighted'); + missingCoverageElements.item(index).classList.add('highlighted'); + } + + function makeCurrent(index) { + toggleClass(index); + currentIndex = index; + missingCoverageElements.item(index).scrollIntoView({ + behavior: 'smooth', + block: 'center', + inline: 'center' + }); + } + + function goToPrevious() { + var nextIndex = 0; + if (typeof currentIndex !== 'number' || currentIndex === 0) { + nextIndex = missingCoverageElements.length - 1; + } else if (missingCoverageElements.length > 1) { + nextIndex = currentIndex - 1; + } + + makeCurrent(nextIndex); + } + + function goToNext() { + var nextIndex = 0; + + if ( + typeof currentIndex === 'number' && + currentIndex < missingCoverageElements.length - 1 + ) { + nextIndex = currentIndex + 1; + } + + makeCurrent(nextIndex); + } + + return function jump(event) { + if ( + document.getElementById('fileSearch') === document.activeElement && + document.activeElement != null + ) { + // if we're currently focused on the search input, we don't want to navigate + return; + } + + switch (event.which) { + case 78: // n + case 74: // j + goToNext(); + break; + case 66: // b + case 75: // k + case 80: // p + goToPrevious(); + break; + } + }; +})(); +window.addEventListener('keydown', jumpToCode); diff --git a/coverage/favicon.png b/coverage/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..c1525b811a167671e9de1fa78aab9f5c0b61cef7 GIT binary patch literal 445 zcmV;u0Yd(XP))rP{nL}Ln%S7`m{0DjX9TLF* zFCb$4Oi7vyLOydb!7n&^ItCzb-%BoB`=x@N2jll2Nj`kauio%aw_@fe&*}LqlFT43 z8doAAe))z_%=P%v^@JHp3Hjhj^6*Kr_h|g_Gr?ZAa&y>wxHE99Gk>A)2MplWz2xdG zy8VD2J|Uf#EAw*bo5O*PO_}X2Tob{%bUoO2G~T`@%S6qPyc}VkhV}UifBuRk>%5v( z)x7B{I~z*k<7dv#5tC+m{km(D087J4O%+<<;K|qwefb6@GSX45wCK}Sn*> + + + + Code coverage report for All files + + + + + + + + + +
+
+

All files

+
+ +
+ 65.94% + Statements + 242/367 +
+ + +
+ 83.01% + Branches + 44/53 +
+ + +
+ 88.88% + Functions + 16/18 +
+ + +
+ 65.94% + Lines + 242/367 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
src +
+
0%0/5066.66%2/366.66%2/30%0/50
src/core +
+
60.43%110/18268.75%11/1683.33%5/660.43%110/182
src/parser +
+
100%113/11396.42%27/28100%7/7100%113/113
src/templates +
+
86.36%19/2266.66%4/6100%2/286.36%19/22
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/prettify.css b/coverage/prettify.css new file mode 100644 index 0000000..b317a7c --- /dev/null +++ b/coverage/prettify.css @@ -0,0 +1 @@ +.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/coverage/prettify.js b/coverage/prettify.js new file mode 100644 index 0000000..b322523 --- /dev/null +++ b/coverage/prettify.js @@ -0,0 +1,2 @@ +/* eslint-disable */ +window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/coverage/sort-arrow-sprite.png b/coverage/sort-arrow-sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..6ed68316eb3f65dec9063332d2f69bf3093bbfab GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^>_9Bd!3HEZxJ@+%Qh}Z>jv*C{$p!i!8j}?a+@3A= zIAGwzjijN=FBi!|L1t?LM;Q;gkwn>2cAy-KV{dn nf0J1DIvEHQu*n~6U}x}qyky7vi4|9XhBJ7&`njxgN@xNA8m%nc literal 0 HcmV?d00001 diff --git a/coverage/sorter.js b/coverage/sorter.js new file mode 100644 index 0000000..2bb296a --- /dev/null +++ b/coverage/sorter.js @@ -0,0 +1,196 @@ +/* eslint-disable */ +var addSorting = (function() { + 'use strict'; + var cols, + currentSort = { + index: 0, + desc: false + }; + + // returns the summary table element + function getTable() { + return document.querySelector('.coverage-summary'); + } + // returns the thead element of the summary table + function getTableHeader() { + return getTable().querySelector('thead tr'); + } + // returns the tbody element of the summary table + function getTableBody() { + return getTable().querySelector('tbody'); + } + // returns the th element for nth column + function getNthColumn(n) { + return getTableHeader().querySelectorAll('th')[n]; + } + + function onFilterInput() { + const searchValue = document.getElementById('fileSearch').value; + const rows = document.getElementsByTagName('tbody')[0].children; + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + if ( + row.textContent + .toLowerCase() + .includes(searchValue.toLowerCase()) + ) { + row.style.display = ''; + } else { + row.style.display = 'none'; + } + } + } + + // loads the search box + function addSearchBox() { + var template = document.getElementById('filterTemplate'); + var templateClone = template.content.cloneNode(true); + templateClone.getElementById('fileSearch').oninput = onFilterInput; + template.parentElement.appendChild(templateClone); + } + + // loads all columns + function loadColumns() { + var colNodes = getTableHeader().querySelectorAll('th'), + colNode, + cols = [], + col, + i; + + for (i = 0; i < colNodes.length; i += 1) { + colNode = colNodes[i]; + col = { + key: colNode.getAttribute('data-col'), + sortable: !colNode.getAttribute('data-nosort'), + type: colNode.getAttribute('data-type') || 'string' + }; + cols.push(col); + if (col.sortable) { + col.defaultDescSort = col.type === 'number'; + colNode.innerHTML = + colNode.innerHTML + ''; + } + } + return cols; + } + // attaches a data attribute to every tr element with an object + // of data values keyed by column name + function loadRowData(tableRow) { + var tableCols = tableRow.querySelectorAll('td'), + colNode, + col, + data = {}, + i, + val; + for (i = 0; i < tableCols.length; i += 1) { + colNode = tableCols[i]; + col = cols[i]; + val = colNode.getAttribute('data-value'); + if (col.type === 'number') { + val = Number(val); + } + data[col.key] = val; + } + return data; + } + // loads all row data + function loadData() { + var rows = getTableBody().querySelectorAll('tr'), + i; + + for (i = 0; i < rows.length; i += 1) { + rows[i].data = loadRowData(rows[i]); + } + } + // sorts the table using the data for the ith column + function sortByIndex(index, desc) { + var key = cols[index].key, + sorter = function(a, b) { + a = a.data[key]; + b = b.data[key]; + return a < b ? -1 : a > b ? 1 : 0; + }, + finalSorter = sorter, + tableBody = document.querySelector('.coverage-summary tbody'), + rowNodes = tableBody.querySelectorAll('tr'), + rows = [], + i; + + if (desc) { + finalSorter = function(a, b) { + return -1 * sorter(a, b); + }; + } + + for (i = 0; i < rowNodes.length; i += 1) { + rows.push(rowNodes[i]); + tableBody.removeChild(rowNodes[i]); + } + + rows.sort(finalSorter); + + for (i = 0; i < rows.length; i += 1) { + tableBody.appendChild(rows[i]); + } + } + // removes sort indicators for current column being sorted + function removeSortIndicators() { + var col = getNthColumn(currentSort.index), + cls = col.className; + + cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); + col.className = cls; + } + // adds sort indicators for current column being sorted + function addSortIndicators() { + getNthColumn(currentSort.index).className += currentSort.desc + ? ' sorted-desc' + : ' sorted'; + } + // adds event listeners for all sorter widgets + function enableUI() { + var i, + el, + ithSorter = function ithSorter(i) { + var col = cols[i]; + + return function() { + var desc = col.defaultDescSort; + + if (currentSort.index === i) { + desc = !currentSort.desc; + } + sortByIndex(i, desc); + removeSortIndicators(); + currentSort.index = i; + currentSort.desc = desc; + addSortIndicators(); + }; + }; + for (i = 0; i < cols.length; i += 1) { + if (cols[i].sortable) { + // add the click event handler on the th so users + // dont have to click on those tiny arrows + el = getNthColumn(i).querySelector('.sorter').parentElement; + if (el.addEventListener) { + el.addEventListener('click', ithSorter(i)); + } else { + el.attachEvent('onclick', ithSorter(i)); + } + } + } + } + // adds sorting functionality to the UI + return function() { + if (!getTable()) { + return; + } + cols = loadColumns(); + loadData(); + addSearchBox(); + addSortIndicators(); + enableUI(); + }; +})(); + +window.addEventListener('load', addSorting); diff --git a/coverage/src/ActionMain.ts.html b/coverage/src/ActionMain.ts.html new file mode 100644 index 0000000..ba61596 --- /dev/null +++ b/coverage/src/ActionMain.ts.html @@ -0,0 +1,259 @@ + + + + + + Code coverage report for src/ActionMain.ts + + + + + + + + + +
+
+

All files / src ActionMain.ts

+
+ +
+ 0% + Statements + 0/46 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/46 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import * as core from '@actions/core';
+import * as github from '@actions/github';
+import path from 'path';
+import { extractTodosFromDir } from './parser/extractTodosFromDir';
+import { TodoItem } from './parser/types';
+import { getExistingIssueTitles, createIssueIfNeeded } from './core/issueManager';
+import { generateMarkdownReport } from './core/report';
+import { limitTodos, todoKey } from './core/todoUtils';
+ 
+async function run(): Promise<void> {
+  try {
+    const token = core.getInput('repo-token', { required: true });
+    const generateReport = core.getInput('report') === 'true';
+    const titleTemplatePath = core.getInput('issue-title-template');
+    const bodyTemplatePath = core.getInput('issue-body-template');
+    const workspace = process.env.GITHUB_WORKSPACE || '.';
+ 
+    const todos: TodoItem[] = extractTodosFromDir(workspace);
+    const octokit = github.getOctokit(token);
+    const { owner, repo } = github.context.repo;
+ 
+    core.info(`πŸ” Found ${todos.length} TODOs`);
+ 
+    const existingTitles = await getExistingIssueTitles(octokit, owner, repo);
+ 
+    const seenKeys = new Set<string>();
+    const uniqueTodos = todos.filter(todo => {
+      const key = todoKey(todo);
+      if (seenKeys.has(key)) return false;
+      seenKeys.add(key);
+      return true;
+    });
+ 
+    const todosToCreate = limitTodos(uniqueTodos, 5);
+ 
+    for (const todo of todosToCreate) {
+      await createIssueIfNeeded(
+        octokit,
+        owner,
+        repo,
+        todo,
+        existingTitles,
+        titleTemplatePath,
+        bodyTemplatePath
+      );
+    }
+ 
+    if (generateReport) {
+      generateMarkdownReport(todos);
+      core.info('πŸ“ Generated TODO_REPORT.md');
+    }
+ 
+  } catch (error: any) {
+    core.setFailed(`Action failed: ${error.message}`);
+  }
+}
+ 
+run();
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/core/index.html b/coverage/src/core/index.html new file mode 100644 index 0000000..83f8606 --- /dev/null +++ b/coverage/src/core/index.html @@ -0,0 +1,161 @@ + + + + + + Code coverage report for src/core + + + + + + + + + +
+
+

All files src/core

+
+ +
+ 60.43% + Statements + 110/182 +
+ + +
+ 68.75% + Branches + 11/16 +
+ + +
+ 83.33% + Functions + 5/6 +
+ + +
+ 60.43% + Lines + 110/182 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
issueManager.ts +
+
94.59%70/7462.5%5/8100%2/294.59%70/74
labelManager.ts +
+
95.23%40/4283.33%5/6100%2/295.23%40/42
report.ts +
+
0%0/540%0/10%0/10%0/54
todoUtils.ts +
+
0%0/12100%1/1100%1/10%0/12
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/core/issueManager.ts.html b/coverage/src/core/issueManager.ts.html new file mode 100644 index 0000000..683f498 --- /dev/null +++ b/coverage/src/core/issueManager.ts.html @@ -0,0 +1,355 @@ + + + + + + Code coverage report for src/core/issueManager.ts + + + + + + + + + +
+
+

All files / src/core issueManager.ts

+
+ +
+ 94.59% + Statements + 70/74 +
+ + +
+ 62.5% + Branches + 5/8 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 94.59% + Lines + 70/74 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +911x +  +  +1x +1x +  +1x +1x +1x +1x +1x +1x +1x +1x +1x +  +1x +1x +1x +1x +1x +1x +1x +1x +  +1x +2x +2x +2x +2x +  +1x +1x +1x +  +  +1x +  +1x +1x +  +2x +2x +2x +2x +2x +2x +2x +2x +2x +2x +2x +  +2x +2x +2x +2x +  +2x +2x +  +  +2x +1x +1x +1x +  +1x +2x +2x +2x +  +2x +2x +2x +  +1x +1x +1x +1x +1x +1x +1x +1x +  +1x +2x +  +  +2x + 
import * as core from '@actions/core';
+import * as github from '@actions/github';
+import { TodoItem } from '../parser/types';
+import { LABELS_BY_TAG, labelsFromMetadata, ensureLabelExists } from './labelManager';
+import { loadTemplate, applyTemplate } from '../templates/utils';
+ 
+export async function getExistingIssueTitles(
+  octokit: ReturnType<typeof github.getOctokit>,
+  owner: string,
+  repo: string
+): Promise<Set<string>> {
+  const existing = new Set<string>();
+  const perPage = 100;
+  let page = 1;
+  let done = false;
+ 
+  while (!done) {
+    const { data } = await octokit.rest.issues.listForRepo({
+      owner,
+      repo,
+      state: 'open',
+      per_page: perPage,
+      page
+    });
+ 
+    for (const issue of data) {
+      if (!issue.pull_request) {
+        existing.add(issue.title);
+      }
+    }
+ 
+    if (data.length < perPage) {
+      done = true;
+    } else {
+      page++;
+    }
+  }
+ 
+  return existing;
+}
+ 
+export async function createIssueIfNeeded(
+    octokit: ReturnType<typeof github.getOctokit>,
+    owner: string,
+    repo: string,
+    todo: TodoItem,
+    existingTitles: Set<string>,
+    titlePath?: string,
+    bodyPath?: string
+  ): Promise<void> {
+    const titleTemplate = loadTemplate('issueTitle.txt');
+    const bodyTemplate = loadTemplate('issueBody.md');
+  
+    const flattened = {
+        ...todo,
+        ...todo.metadata
+      } as Record<string, string | number>;
+      
+    const title = applyTemplate(titleTemplate, flattened);
+    const body = applyTemplate(bodyTemplate, flattened);
+      
+  
+    if (existingTitles.has(title)) {
+      core.info(`🟑 Skipping duplicate issue: ${title}`);
+      return;
+    }
+  
+    const tag = todo.tag.toUpperCase();
+    const baseLabels = LABELS_BY_TAG[tag] || ['todo'];
+    const metaLabels = labelsFromMetadata(todo.metadata);
+    const labels = [...baseLabels, ...metaLabels];
+  
+    for (const label of labels) {
+      await ensureLabelExists(octokit, owner, repo, label);
+    }
+  
+    try {
+      await octokit.rest.issues.create({
+        owner,
+        repo,
+        title,
+        body,
+        labels
+      });
+  
+      core.info(`βœ… Created issue with labels [${labels.join(', ')}]: ${title}`);
+    } catch (err: any) {
+      core.warning(`⚠️ Failed to create issue for: ${title} β€” ${err.message}`);
+    }
+  }
+  
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/core/labelManager.ts.html b/coverage/src/core/labelManager.ts.html new file mode 100644 index 0000000..b00acde --- /dev/null +++ b/coverage/src/core/labelManager.ts.html @@ -0,0 +1,238 @@ + + + + + + Code coverage report for src/core/labelManager.ts + + + + + + + + + +
+
+

All files / src/core labelManager.ts

+
+ +
+ 95.23% + Statements + 40/42 +
+ + +
+ 83.33% + Branches + 5/6 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 95.23% + Lines + 40/42 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52  +1x +  +  +1x +1x +1x +1x +1x +1x +  +  +1x +1x +1x +1x +1x +1x +  +  +1x +2x +1x +1x +  +  +2x +2x +2x +2x +2x +2x +2x +2x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +1x +  +  +1x +2x + 
import * as github from '@actions/github';
+import * as core from '@actions/core';
+ 
+// Labels atribuΓ­das por tipo de comentΓ‘rio
+export const LABELS_BY_TAG: Record<string, string[]> = {
+  TODO: ['enhancement'],
+  FIXME: ['bug'],
+  BUG: ['bug'],
+  HACK: ['technical-debt']
+};
+ 
+// Cores associadas a cada label base
+export const LABEL_COLORS: Record<string, string> = {
+  bug: 'd73a4a',
+  enhancement: 'a2eeef',
+  todo: 'cfd3d7',
+  'technical-debt': 'e99695'
+};
+ 
+// Fallback para labels metadata:priority, due, etc.
+export function labelsFromMetadata(metadata?: Record<string, string>): string[] {
+  if (!metadata) return [];
+  return Object.entries(metadata).map(([key, value]) => `${key}:${value}`);
+}
+ 
+// Garante que uma label existe no repositΓ³rio
+export async function ensureLabelExists(
+  octokit: ReturnType<typeof github.getOctokit>,
+  owner: string,
+  repo: string,
+  label: string
+): Promise<void> {
+  try {
+    await octokit.rest.issues.getLabel({ owner, repo, name: label });
+  } catch (err: any) {
+    if (err.status === 404) {
+      const base = label.split(':')[0];
+      const color = LABEL_COLORS[base] || 'cccccc';
+      await octokit.rest.issues.createLabel({
+        owner,
+        repo,
+        name: label,
+        color,
+        description: 'Auto-created by smart-todo-action'
+      });
+      core.info(`🏷️ Created label: ${label}`);
+    } else {
+      core.warning(`⚠️ Could not verify label "${label}": ${err.message}`);
+    }
+  }
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/core/report.ts.html b/coverage/src/core/report.ts.html new file mode 100644 index 0000000..5a7ee5c --- /dev/null +++ b/coverage/src/core/report.ts.html @@ -0,0 +1,301 @@ + + + + + + Code coverage report for src/core/report.ts + + + + + + + + + +
+
+

All files / src/core report.ts

+
+ +
+ 0% + Statements + 0/54 +
+ + +
+ 0% + Branches + 0/1 +
+ + +
+ 0% + Functions + 0/1 +
+ + +
+ 0% + Lines + 0/54 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import fs from 'fs';
+import path from 'path';
+import { TodoItem } from '../parser/types';
+import { todoKey } from './todoUtils';
+ 
+const PRIORITY_ORDER = ['high', 'medium', 'low'];
+ 
+function getPriority(todo: TodoItem): string {
+  return todo.metadata?.priority?.toLowerCase?.() ?? '';
+}
+ 
+function getDue(todo: TodoItem): string {
+  return todo.metadata?.due ?? '';
+}
+ 
+function sortTodos(a: TodoItem, b: TodoItem): number {
+  const pa = getPriority(a);
+  const pb = getPriority(b);
+ 
+  const prioA = PRIORITY_ORDER.indexOf(pa);
+  const prioB = PRIORITY_ORDER.indexOf(pb);
+ 
+  if (prioA !== prioB) {
+    return (prioA === -1 ? Infinity : prioA) - (prioB === -1 ? Infinity : prioB);
+  }
+ 
+  const da = getDue(a);
+  const db = getDue(b);
+ 
+  if (da && db) return da.localeCompare(db);
+  if (da) return -1;
+  if (db) return 1;
+ 
+  return 0;
+}
+ 
+export function generateMarkdownReport(todos: TodoItem[]): void {
+  const seen = new Set<string>();
+  const uniqueTodos = todos.filter(todo => {
+    const key = todoKey(todo);
+    if (seen.has(key)) return false;
+    seen.add(key);
+    return true;
+  });
+ 
+  const grouped: Record<string, TodoItem[]> = {};
+ 
+  for (const todo of uniqueTodos) {
+    if (!grouped[todo.tag]) grouped[todo.tag] = [];
+    grouped[todo.tag].push(todo);
+  }
+ 
+  let content = `# πŸ“Œ TODO Report\n\nTotal unique TODOs: **${uniqueTodos.length}**\n\n`;
+ 
+  for (const tag of Object.keys(grouped)) {
+    const sorted = grouped[tag].sort(sortTodos);
+    content += `## ${tag}\n\n`;
+ 
+    for (const todo of sorted) {
+      const prio = getPriority(todo);
+      const due = getDue(todo);
+      const meta = [prio && `priority=${prio}`, due && `due=${due}`].filter(Boolean).join(', ');
+      content += `- \`${todo.file}:${todo.line}\` β€” ${todo.text}`;
+      if (meta) content += ` _( ${meta} )_`;
+      content += `\n`;
+    }
+ 
+    content += '\n';
+  }
+ 
+  fs.writeFileSync(path.join(process.cwd(), 'TODO_REPORT.md'), content);
+}
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/core/todoUtils.ts.html b/coverage/src/core/todoUtils.ts.html new file mode 100644 index 0000000..a1115ab --- /dev/null +++ b/coverage/src/core/todoUtils.ts.html @@ -0,0 +1,136 @@ + + + + + + Code coverage report for src/core/todoUtils.ts + + + + + + + + + +
+
+

All files / src/core todoUtils.ts

+
+ +
+ 0% + Statements + 0/12 +
+ + +
+ 100% + Branches + 1/1 +
+ + +
+ 100% + Functions + 1/1 +
+ + +
+ 0% + Lines + 0/12 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  + 
import { TodoItem } from '../parser/types';
+ 
+export function buildIssueTitle(todo: TodoItem): string {
+  return `[${todo.tag}] ${todo.text}`;
+}
+ 
+export function isValidTodo(todo: TodoItem): boolean {
+  return todo.text.length > 5;
+}
+ 
+export function limitTodos(todos: TodoItem[], max = 5): TodoItem[] {
+  return todos.filter(isValidTodo).slice(0, max);
+}
+ 
+export function todoKey(todo: TodoItem): string {
+  return `[${todo.tag}] ${todo.text}`;
+}
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/index.html b/coverage/src/index.html new file mode 100644 index 0000000..045682b --- /dev/null +++ b/coverage/src/index.html @@ -0,0 +1,146 @@ + + + + + + Code coverage report for src + + + + + + + + + +
+
+

All files src

+
+ +
+ 0% + Statements + 0/50 +
+ + +
+ 66.66% + Branches + 2/3 +
+ + +
+ 66.66% + Functions + 2/3 +
+ + +
+ 0% + Lines + 0/50 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
ActionMain.ts +
+
0%0/460%0/10%0/10%0/46
main.ts +
+
0%0/1100%1/1100%1/10%0/1
testTodo.ts +
+
0%0/3100%1/1100%1/10%0/3
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/main.ts.html b/coverage/src/main.ts.html new file mode 100644 index 0000000..9d762e3 --- /dev/null +++ b/coverage/src/main.ts.html @@ -0,0 +1,91 @@ + + + + + + Code coverage report for src/main.ts + + + + + + + + + +
+
+

All files / src main.ts

+
+ +
+ 0% + Statements + 0/1 +
+ + +
+ 100% + Branches + 1/1 +
+ + +
+ 100% + Functions + 1/1 +
+ + +
+ 0% + Lines + 0/1 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3  +  + 
// Ponto de entrada da Action
+ 
+console.log('TODO Watcher iniciado');
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/parser/extractTodos.ts.html b/coverage/src/parser/extractTodos.ts.html new file mode 100644 index 0000000..90f4736 --- /dev/null +++ b/coverage/src/parser/extractTodos.ts.html @@ -0,0 +1,247 @@ + + + + + + Code coverage report for src/parser/extractTodos.ts + + + + + + + + + +
+
+

All files / src/parser extractTodos.ts

+
+ +
+ 100% + Statements + 46/46 +
+ + +
+ 90.9% + Branches + 10/11 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 100% + Lines + 46/46 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +551x +1x +  +  +1x +1x +1x +1x +1x +  +1x +  +2x +2x +2x +2x +2x +2x +3x +3x +2x +2x +2x +2x +  +1x +5x +5x +5x +  +5x +5x +  +5x +20x +20x +8x +8x +8x +7x +7x +7x +7x +7x +7x +7x +7x +7x +7x +8x +5x +  +5x +5x + 
import fs from 'fs';
+import path from 'path';
+import { TodoItem } from './types';
+ 
+const COMMENT_PATTERNS = [
+  { ext: ['.ts', '.js', '.java', '.go'], pattern: /^\s*\/\/\s*(.*)$/ },
+  { ext: ['.py', '.sh', '.rb'], pattern: /^\s*#\s*(.*)$/ },
+  { ext: ['.html', '.xml'], pattern: /<!--\s*(.*?)\s*-->/ }
+];
+ 
+const TAG_REGEX = /(TODO|FIXME|BUG|HACK)(\([^)]*\))?:?\s*(.*)/i;
+ 
+function extractMetadata(str: string): Record<string, string> {
+  const meta: Record<string, string> = {};
+  const match = str.match(/\((.*?)\)/);
+  if (match) {
+    const content = match[1];
+    content.split(',').forEach(pair => {
+      const [key, val] = pair.split('=').map(s => s.trim());
+      if (key && val) meta[key] = val;
+    });
+  }
+  return meta;
+}
+ 
+export function extractTodosFromFile(filePath: string): TodoItem[] {
+  const ext = path.extname(filePath);
+  const pattern = COMMENT_PATTERNS.find(p => p.ext.includes(ext));
+  if (!pattern) return [];
+ 
+  const lines = fs.readFileSync(filePath, 'utf-8').split('\n');
+  const todos: TodoItem[] = [];
+ 
+  lines.forEach((line, idx) => {
+    const commentMatch = line.match(pattern.pattern);
+    if (commentMatch) {
+      const comment = commentMatch[1];
+      const tagMatch = comment.match(TAG_REGEX);
+      if (tagMatch) {
+        const [_, tag, metaRaw, text] = tagMatch;
+        const metadata = metaRaw ? extractMetadata(metaRaw) : undefined;
+        todos.push({
+          file: filePath,
+          line: idx + 1,
+          tag,
+          text: text.trim(),
+          metadata
+        });
+      }
+    }
+  });
+ 
+  return todos;
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/parser/extractTodosFromContent.ts.html b/coverage/src/parser/extractTodosFromContent.ts.html new file mode 100644 index 0000000..722ff70 --- /dev/null +++ b/coverage/src/parser/extractTodosFromContent.ts.html @@ -0,0 +1,238 @@ + + + + + + Code coverage report for src/parser/extractTodosFromContent.ts + + + + + + + + + +
+
+

All files / src/parser extractTodosFromContent.ts

+
+ +
+ 100% + Statements + 43/43 +
+ + +
+ 100% + Branches + 11/11 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 100% + Lines + 43/43 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52  +  +1x +1x +1x +1x +1x +  +1x +  +2x +2x +2x +2x +2x +2x +4x +4x +2x +2x +2x +2x +  +1x +19x +19x +  +18x +18x +  +18x +35x +35x +27x +27x +27x +27x +27x +27x +27x +27x +27x +27x +27x +27x +27x +27x +18x +  +18x +18x + 
import { TodoItem } from './types';
+ 
+const COMMENT_PATTERNS = [
+  { ext: ['.ts', '.js', '.java', '.go'], pattern: /^\s*\/\/\s*(.*)$/ },
+  { ext: ['.py', '.sh', '.rb'], pattern: /^\s*#\s*(.*)$/ },
+  { ext: ['.html', '.xml'], pattern: /<!--\s*(.*?)\s*-->/ }
+];
+ 
+const TAG_REGEX = /(TODO|FIXME|BUG|HACK)(\([^)]*\))?:?\s*(.*)/i;
+ 
+function extractMetadata(str: string): Record<string, string> {
+  const meta: Record<string, string> = {};
+  const match = str.match(/\((.*?)\)/);
+  if (match) {
+    const content = match[1];
+    content.split(',').forEach(pair => {
+      const [key, val] = pair.split('=').map(s => s.trim());
+      if (key && val) meta[key] = val;
+    });
+  }
+  return meta;
+}
+ 
+export function extractTodosFromString(content: string, ext: string): TodoItem[] {
+  const pattern = COMMENT_PATTERNS.find(p => p.ext.includes(ext));
+  if (!pattern) return [];
+ 
+  const lines = content.split('\n');
+  const todos: TodoItem[] = [];
+ 
+  lines.forEach((line, idx) => {
+    const commentMatch = line.match(pattern.pattern);
+    if (commentMatch) {
+      const comment = commentMatch[1];
+      const tagMatch = comment.match(TAG_REGEX);
+      if (tagMatch) {
+        const [_, tag, metaRaw, text] = tagMatch;
+        const metadata = metaRaw ? extractMetadata(metaRaw) : undefined;
+        todos.push({
+          file: `inline${ext}`,
+          line: idx + 1,
+          tag,
+          text: text.trim(),
+          metadata
+        });
+      }
+    }
+  });
+ 
+  return todos;
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/parser/extractTodosFromDir.ts.html b/coverage/src/parser/extractTodosFromDir.ts.html new file mode 100644 index 0000000..8348c2b --- /dev/null +++ b/coverage/src/parser/extractTodosFromDir.ts.html @@ -0,0 +1,178 @@ + + + + + + Code coverage report for src/parser/extractTodosFromDir.ts + + + + + + + + + +
+
+

All files / src/parser extractTodosFromDir.ts

+
+ +
+ 100% + Statements + 24/24 +
+ + +
+ 100% + Branches + 5/5 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 100% + Lines + 24/24 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +321x +1x +1x +  +  +1x +  +1x +2x +  +2x +4x +  +4x +6x +  +6x +2x +6x +4x +4x +4x +4x +4x +4x +6x +4x +  +2x +2x +2x + 
import fs from 'fs';
+import path from 'path';
+import { extractTodosFromFile } from './extractTodos';
+import { TodoItem } from './types';
+ 
+const SUPPORTED_EXTENSIONS = ['.ts', '.js', '.py', '.go', '.java', '.rb', '.sh', '.html', '.xml'];
+ 
+export function extractTodosFromDir(dirPath: string): TodoItem[] {
+  const todos: TodoItem[] = [];
+ 
+  function walk(currentPath: string) {
+    const entries = fs.readdirSync(currentPath, { withFileTypes: true });
+ 
+    for (const entry of entries) {
+      const fullPath = path.join(currentPath, entry.name);
+ 
+      if (entry.isDirectory()) {
+        walk(fullPath);
+      } else if (entry.isFile()) {
+        const ext = path.extname(entry.name);
+        if (SUPPORTED_EXTENSIONS.includes(ext)) {
+          const fileTodos = extractTodosFromFile(fullPath);
+          todos.push(...fileTodos);
+        }
+      }
+    }
+  }
+ 
+  walk(dirPath);
+  return todos;
+}
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/parser/index.html b/coverage/src/parser/index.html new file mode 100644 index 0000000..3c09ea1 --- /dev/null +++ b/coverage/src/parser/index.html @@ -0,0 +1,161 @@ + + + + + + Code coverage report for src/parser + + + + + + + + + +
+
+

All files src/parser

+
+ +
+ 100% + Statements + 113/113 +
+ + +
+ 96.42% + Branches + 27/28 +
+ + +
+ 100% + Functions + 7/7 +
+ + +
+ 100% + Lines + 113/113 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
extractTodos.ts +
+
100%46/4690.9%10/11100%2/2100%46/46
extractTodosFromContent.ts +
+
100%43/43100%11/11100%2/2100%43/43
extractTodosFromDir.ts +
+
100%24/24100%5/5100%2/2100%24/24
types.ts +
+
0%0/00%1/10%1/10%0/0
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/parser/types.ts.html b/coverage/src/parser/types.ts.html new file mode 100644 index 0000000..e7cc8e2 --- /dev/null +++ b/coverage/src/parser/types.ts.html @@ -0,0 +1,112 @@ + + + + + + Code coverage report for src/parser/types.ts + + + + + + + + + +
+
+

All files / src/parser types.ts

+
+ +
+ 0% + Statements + 0/0 +
+ + +
+ 0% + Branches + 1/1 +
+ + +
+ 0% + Functions + 1/1 +
+ + +
+ 0% + Lines + 0/0 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10  +  +  +  +  +  +  +  +  + 
export interface TodoItem {
+  tag: string;
+  text: string;
+  file: string;
+  line: number;
+  metadata?: Record<string, string>;
+ 
+  [key: string]: string | number | Record<string, string> | undefined;
+}
+  
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/templates/index.html b/coverage/src/templates/index.html new file mode 100644 index 0000000..6eb425e --- /dev/null +++ b/coverage/src/templates/index.html @@ -0,0 +1,116 @@ + + + + + + Code coverage report for src/templates + + + + + + + + + +
+
+

All files src/templates

+
+ +
+ 86.36% + Statements + 19/22 +
+ + +
+ 66.66% + Branches + 4/6 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 86.36% + Lines + 19/22 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileStatementsBranchesFunctionsLines
utils.ts +
+
86.36%19/2266.66%4/6100%2/286.36%19/22
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/templates/utils.ts.html b/coverage/src/templates/utils.ts.html new file mode 100644 index 0000000..80053cd --- /dev/null +++ b/coverage/src/templates/utils.ts.html @@ -0,0 +1,166 @@ + + + + + + Code coverage report for src/templates/utils.ts + + + + + + + + + +
+
+

All files / src/templates utils.ts

+
+ +
+ 86.36% + Statements + 19/22 +
+ + +
+ 66.66% + Branches + 4/6 +
+ + +
+ 100% + Functions + 2/2 +
+ + +
+ 86.36% + Lines + 19/22 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +281x +1x +  +1x +1x +1x +1x +  +1x +7x +7x +  +1x +4x +4x +4x +  +  +4x +4x +4x +4x +4x +  +  +4x +  + 
import fs from 'fs';
+import path from 'path';
+ 
+const DEFAULT_TEMPLATES: Record<string, string> = {
+  'issueTitle.txt': '[{{tag}}] {{text}}',
+  'issueBody.md': 'Found in `{{file}}:{{line}}`\n\n```\n{{text}}\n```'
+};
+ 
+export function applyTemplate(template: string, data: Record<string, string | number>): string {
+  return template.replace(/{{(.*?)}}/g, (_, key) => String(data[key.trim()] ?? ''));
+}
+ 
+export function loadTemplate(templatePath: string): string {
+  const isRelative = !path.isAbsolute(templatePath);
+  const resolvedPath = isRelative
+    ? path.resolve(process.cwd(), templatePath)
+    : templatePath;
+ 
+  try {
+    return fs.readFileSync(resolvedPath, 'utf-8');
+  } catch (err) {
+    const fallback = DEFAULT_TEMPLATES[path.basename(templatePath)];
+    if (fallback) return fallback;
+    throw new Error(`Template not found: ${templatePath}`);
+  }
+}
+ 
+ 
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/coverage/src/testTodo.ts.html b/coverage/src/testTodo.ts.html new file mode 100644 index 0000000..7bde8b5 --- /dev/null +++ b/coverage/src/testTodo.ts.html @@ -0,0 +1,97 @@ + + + + + + Code coverage report for src/testTodo.ts + + + + + + + + + +
+
+

All files / src testTodo.ts

+
+ +
+ 0% + Statements + 0/3 +
+ + +
+ 100% + Branches + 1/1 +
+ + +
+ 100% + Functions + 1/1 +
+ + +
+ 0% + Lines + 0/3 +
+ + +
+

+ Press n or j to go to the next uncovered block, b, p or k for the previous block. +

+ +
+
+

+
1 +2 +3 +4 +5  +  +  +  + 
// src/testTodo.ts
+// TODO: Refactor this logic to improve performance
+export function testLogic() {
+    return Math.random();
+  }
+ +
+
+ + + + + + + + \ No newline at end of file diff --git a/package.json b/package.json index c36931e..b5071b0 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ "devDependencies": { "@types/node": "^20.11.17", "@vercel/ncc": "^0.38.3", + "@vitest/coverage-v8": "^3.1.1", "typescript": "^5.3.3", - "vitest": "^1.3.0" + "vitest": "^3.1.1" } } diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..feb8f83 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: true, + coverage: { + provider: 'v8', + reporter: ['text', 'html'], + }, + }, +}); diff --git a/yarn.lock b/yarn.lock index c8c5c1b..e0c1a5c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -40,138 +40,223 @@ resolved "https://registry.yarnpkg.com/@actions/io/-/io-1.1.3.tgz#4cdb6254da7962b07473ff5c335f3da485d94d71" integrity sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q== -"@esbuild/aix-ppc64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" - integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== - -"@esbuild/android-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" - integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== - -"@esbuild/android-arm@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" - integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== - -"@esbuild/android-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" - integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== - -"@esbuild/darwin-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" - integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== - -"@esbuild/darwin-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" - integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== - -"@esbuild/freebsd-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" - integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== - -"@esbuild/freebsd-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" - integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== - -"@esbuild/linux-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" - integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== - -"@esbuild/linux-arm@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" - integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== - -"@esbuild/linux-ia32@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" - integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== - -"@esbuild/linux-loong64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" - integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== - -"@esbuild/linux-mips64el@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" - integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== - -"@esbuild/linux-ppc64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" - integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== - -"@esbuild/linux-riscv64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" - integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== - -"@esbuild/linux-s390x@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" - integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== - -"@esbuild/linux-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" - integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== - -"@esbuild/netbsd-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" - integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== - -"@esbuild/openbsd-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" - integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== - -"@esbuild/sunos-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" - integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== - -"@esbuild/win32-arm64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" - integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== - -"@esbuild/win32-ia32@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" - integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== - -"@esbuild/win32-x64@0.21.5": - version "0.21.5" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" - integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== +"@ampproject/remapping@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@babel/helper-string-parser@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c" + integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== + +"@babel/helper-validator-identifier@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" + integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== + +"@babel/parser@^7.25.4": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.27.0.tgz#3d7d6ee268e41d2600091cbd4e145ffee85a44ec" + integrity sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg== + dependencies: + "@babel/types" "^7.27.0" + +"@babel/types@^7.25.4", "@babel/types@^7.27.0": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.27.0.tgz#ef9acb6b06c3173f6632d993ecb6d4ae470b4559" + integrity sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg== + dependencies: + "@babel/helper-string-parser" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + +"@bcoe/v8-coverage@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz#bbe12dca5b4ef983a0d0af4b07b9bc90ea0ababa" + integrity sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA== + +"@esbuild/aix-ppc64@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz#b87036f644f572efb2b3c75746c97d1d2d87ace8" + integrity sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag== + +"@esbuild/android-arm64@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.2.tgz#5ca7dc20a18f18960ad8d5e6ef5cf7b0a256e196" + integrity sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w== + +"@esbuild/android-arm@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.2.tgz#3c49f607b7082cde70c6ce0c011c362c57a194ee" + integrity sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA== + +"@esbuild/android-x64@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.2.tgz#8a00147780016aff59e04f1036e7cb1b683859e2" + integrity sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg== + +"@esbuild/darwin-arm64@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.2.tgz#486efe7599a8d90a27780f2bb0318d9a85c6c423" + integrity sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA== + +"@esbuild/darwin-x64@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.2.tgz#95ee222aacf668c7a4f3d7ee87b3240a51baf374" + integrity sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA== + +"@esbuild/freebsd-arm64@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.2.tgz#67efceda8554b6fc6a43476feba068fb37fa2ef6" + integrity sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w== + +"@esbuild/freebsd-x64@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.2.tgz#88a9d7ecdd3adadbfe5227c2122d24816959b809" + integrity sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ== + +"@esbuild/linux-arm64@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.2.tgz#87be1099b2bbe61282333b084737d46bc8308058" + integrity sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g== + +"@esbuild/linux-arm@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.2.tgz#72a285b0fe64496e191fcad222185d7bf9f816f6" + integrity sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g== + +"@esbuild/linux-ia32@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.2.tgz#337a87a4c4dd48a832baed5cbb022be20809d737" + integrity sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ== + +"@esbuild/linux-loong64@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.2.tgz#1b81aa77103d6b8a8cfa7c094ed3d25c7579ba2a" + integrity sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w== + +"@esbuild/linux-mips64el@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.2.tgz#afbe380b6992e7459bf7c2c3b9556633b2e47f30" + integrity sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q== + +"@esbuild/linux-ppc64@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.2.tgz#6bf8695cab8a2b135cca1aa555226dc932d52067" + integrity sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g== + +"@esbuild/linux-riscv64@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.2.tgz#43c2d67a1a39199fb06ba978aebb44992d7becc3" + integrity sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw== + +"@esbuild/linux-s390x@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.2.tgz#419e25737ec815c6dce2cd20d026e347cbb7a602" + integrity sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q== + +"@esbuild/linux-x64@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.2.tgz#22451f6edbba84abe754a8cbd8528ff6e28d9bcb" + integrity sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg== + +"@esbuild/netbsd-arm64@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.2.tgz#744affd3b8d8236b08c5210d828b0698a62c58ac" + integrity sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw== + +"@esbuild/netbsd-x64@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.2.tgz#dbbe7521fd6d7352f34328d676af923fc0f8a78f" + integrity sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg== + +"@esbuild/openbsd-arm64@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.2.tgz#f9caf987e3e0570500832b487ce3039ca648ce9f" + integrity sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg== + +"@esbuild/openbsd-x64@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.2.tgz#d2bb6a0f8ffea7b394bb43dfccbb07cabd89f768" + integrity sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw== + +"@esbuild/sunos-x64@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.2.tgz#49b437ed63fe333b92137b7a0c65a65852031afb" + integrity sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA== + +"@esbuild/win32-arm64@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.2.tgz#081424168463c7d6c7fb78f631aede0c104373cf" + integrity sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q== + +"@esbuild/win32-ia32@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.2.tgz#3f9e87143ddd003133d21384944a6c6cadf9693f" + integrity sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg== + +"@esbuild/win32-x64@0.25.2": + version "0.25.2" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.2.tgz#839f72c2decd378f86b8f525e1979a97b920c67d" + integrity sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA== "@fastify/busboy@^2.0.0": version "2.1.1" resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.1.tgz#b9da6a878a371829a0502c9b6c1c143ef6663f4d" integrity sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA== -"@jest/schemas@^29.6.3": - version "29.6.3" - resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" - integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + 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/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.8" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142" + integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA== dependencies: - "@sinclair/typebox" "^0.27.8" + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" -"@jridgewell/sourcemap-codec@^1.5.0": +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": version "1.5.0" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== +"@jridgewell/trace-mapping@^0.3.23", "@jridgewell/trace-mapping@^0.3.24": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + "@octokit/auth-token@^2.4.4": version "2.5.0" resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.5.0.tgz#27c37ea26c205f28443402477ffd261311f21e36" @@ -364,6 +449,11 @@ dependencies: "@octokit/openapi-types" "^12.11.0" +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + "@rollup/rollup-android-arm-eabi@4.40.0": version "4.40.0" resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz#d964ee8ce4d18acf9358f96adc408689b6e27fe3" @@ -464,11 +554,6 @@ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.0.tgz#fd92d31a2931483c25677b9c6698106490cbbc76" integrity sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ== -"@sinclair/typebox@^0.27.8": - version "0.27.8" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" - integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== - "@types/estree@1.0.7", "@types/estree@^1.0.0": version "1.0.7" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.7.tgz#4158d3105276773d5b7695cd4834b1722e4f37a8" @@ -486,71 +571,114 @@ resolved "https://registry.yarnpkg.com/@vercel/ncc/-/ncc-0.38.3.tgz#5475eeee3ac0f1a439f237596911525a490a88b5" integrity sha512-rnK6hJBS6mwc+Bkab+PGPs9OiS0i/3kdTO+CkI8V0/VrW3vmz7O2Pxjw/owOlmo6PKEIxRSeZKv/kuL9itnpYA== -"@vitest/expect@1.6.1": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-1.6.1.tgz#b90c213f587514a99ac0bf84f88cff9042b0f14d" - integrity sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog== +"@vitest/coverage-v8@^3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@vitest/coverage-v8/-/coverage-v8-3.1.1.tgz#5f24a2a1620dc602fd5eb07b72b5c77f7ad5943b" + integrity sha512-MgV6D2dhpD6Hp/uroUoAIvFqA8AuvXEFBC2eepG3WFc1pxTfdk1LEqqkWoWhjz+rytoqrnUUCdf6Lzco3iHkLQ== + dependencies: + "@ampproject/remapping" "^2.3.0" + "@bcoe/v8-coverage" "^1.0.2" + debug "^4.4.0" + istanbul-lib-coverage "^3.2.2" + istanbul-lib-report "^3.0.1" + istanbul-lib-source-maps "^5.0.6" + istanbul-reports "^3.1.7" + magic-string "^0.30.17" + magicast "^0.3.5" + std-env "^3.8.1" + test-exclude "^7.0.1" + tinyrainbow "^2.0.0" + +"@vitest/expect@3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-3.1.1.tgz#d64ddfdcf9e877d805e1eee67bd845bf0708c6c2" + integrity sha512-q/zjrW9lgynctNbwvFtQkGK9+vvHA5UzVi2V8APrp1C6fG6/MuYYkmlx4FubuqLycCeSdHD5aadWfua/Vr0EUA== dependencies: - "@vitest/spy" "1.6.1" - "@vitest/utils" "1.6.1" - chai "^4.3.10" + "@vitest/spy" "3.1.1" + "@vitest/utils" "3.1.1" + chai "^5.2.0" + tinyrainbow "^2.0.0" -"@vitest/runner@1.6.1": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-1.6.1.tgz#10f5857c3e376218d58c2bfacfea1161e27e117f" - integrity sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA== +"@vitest/mocker@3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-3.1.1.tgz#7689d99f87498684c71e9fe9defdbd13ffb7f1ac" + integrity sha512-bmpJJm7Y7i9BBELlLuuM1J1Q6EQ6K5Ye4wcyOpOMXMcePYKSIYlpcrCm4l/O6ja4VJA5G2aMJiuZkZdnxlC3SA== dependencies: - "@vitest/utils" "1.6.1" - p-limit "^5.0.0" - pathe "^1.1.1" + "@vitest/spy" "3.1.1" + estree-walker "^3.0.3" + magic-string "^0.30.17" -"@vitest/snapshot@1.6.1": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-1.6.1.tgz#90414451a634bb36cd539ccb29ae0d048a8c0479" - integrity sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ== +"@vitest/pretty-format@3.1.1", "@vitest/pretty-format@^3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-3.1.1.tgz#5b4d577771daccfced47baf3bf026ad59b52c283" + integrity sha512-dg0CIzNx+hMMYfNmSqJlLSXEmnNhMswcn3sXO7Tpldr0LiGmg3eXdLLhwkv2ZqgHb/d5xg5F7ezNFRA1fA13yA== dependencies: - magic-string "^0.30.5" - pathe "^1.1.1" - pretty-format "^29.7.0" + tinyrainbow "^2.0.0" -"@vitest/spy@1.6.1": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-1.6.1.tgz#33376be38a5ed1ecd829eb986edaecc3e798c95d" - integrity sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw== +"@vitest/runner@3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-3.1.1.tgz#76b598700737089d66c74272b2e1c94ca2891a49" + integrity sha512-X/d46qzJuEDO8ueyjtKfxffiXraPRfmYasoC4i5+mlLEJ10UvPb0XH5M9C3gWuxd7BAQhpK42cJgJtq53YnWVA== dependencies: - tinyspy "^2.2.0" + "@vitest/utils" "3.1.1" + pathe "^2.0.3" -"@vitest/utils@1.6.1": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-1.6.1.tgz#6d2f36cb6d866f2bbf59da854a324d6bf8040f17" - integrity sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g== +"@vitest/snapshot@3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-3.1.1.tgz#42b6aa0d0e2b3b48b95a5c76efdcc66a44cb11f3" + integrity sha512-bByMwaVWe/+1WDf9exFxWWgAixelSdiwo2p33tpqIlM14vW7PRV5ppayVXtfycqze4Qhtwag5sVhX400MLBOOw== dependencies: - diff-sequences "^29.6.3" - estree-walker "^3.0.3" - loupe "^2.3.7" - pretty-format "^29.7.0" + "@vitest/pretty-format" "3.1.1" + magic-string "^0.30.17" + pathe "^2.0.3" -acorn-walk@^8.3.2: - version "8.3.4" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" - integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== +"@vitest/spy@3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-3.1.1.tgz#deca0b025e151302ab514f38390fd7777e294837" + integrity sha512-+EmrUOOXbKzLkTDwlsc/xrwOlPDXyVk3Z6P6K4oiCndxz7YLpp/0R0UsWVOKT0IXWjjBJuSMk6D27qipaupcvQ== dependencies: - acorn "^8.11.0" + tinyspy "^3.0.2" -acorn@^8.11.0, acorn@^8.14.0: - version "8.14.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.1.tgz#721d5dc10f7d5b5609a891773d47731796935dfb" - integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== +"@vitest/utils@3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-3.1.1.tgz#2893c30219ab6bdf109f07ce5cd287fe8058438d" + integrity sha512-1XIjflyaU2k3HMArJ50bwSh3wKWPD6Q47wz/NUSmRV0zNywPc4w79ARjg/i/aNINHwA+mIALhUVqD9/aUvZNgg== + dependencies: + "@vitest/pretty-format" "3.1.1" + loupe "^3.1.3" + tinyrainbow "^2.0.0" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-regex@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== + +ansi-styles@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" -ansi-styles@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" - integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== -assertion-error@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" - integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== +assertion-error@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" + integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== before-after-hook@^2.2.0: version "2.2.3" @@ -562,37 +690,47 @@ before-after-hook@^3.0.2: resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-3.0.2.tgz#d5665a5fa8b62294a5aa0a499f933f4a1016195d" integrity sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A== +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + cac@^6.7.14: version "6.7.14" resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== -chai@^4.3.10: - version "4.5.0" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.5.0.tgz#707e49923afdd9b13a8b0b47d33d732d13812fd8" - integrity sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw== +chai@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-5.2.0.tgz#1358ee106763624114addf84ab02697e411c9c05" + integrity sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw== dependencies: - assertion-error "^1.1.0" - check-error "^1.0.3" - deep-eql "^4.1.3" - get-func-name "^2.0.2" - loupe "^2.3.6" - pathval "^1.1.1" - type-detect "^4.1.0" + assertion-error "^2.0.1" + check-error "^2.1.1" + deep-eql "^5.0.1" + loupe "^3.1.0" + pathval "^2.0.0" -check-error@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" - integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== +check-error@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-2.1.1.tgz#87eb876ae71ee388fa0471fe423f494be1d96ccc" + integrity sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw== + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== dependencies: - get-func-name "^2.0.2" + color-name "~1.1.4" -confbox@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.8.tgz#820d73d3b3c82d9bd910652c5d4d599ef8ff8b06" - integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w== +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -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" integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== @@ -601,58 +739,73 @@ cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -debug@^4.3.4: +debug@^4.1.1, debug@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== dependencies: ms "^2.1.3" -deep-eql@^4.1.3: - version "4.1.4" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.4.tgz#d0d3912865911bb8fac5afb4e3acfa6a28dc72b7" - integrity sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg== - dependencies: - type-detect "^4.0.0" +deep-eql@^5.0.1: + version "5.0.2" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" + integrity sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q== deprecation@^2.0.0, deprecation@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== -diff-sequences@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" - integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== - -esbuild@^0.21.3: - version "0.21.5" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" - integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw== +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +es-module-lexer@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.6.0.tgz#da49f587fd9e68ee2404fe4e256c0c7d3a81be21" + integrity sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ== + +esbuild@^0.25.0: + version "0.25.2" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.2.tgz#55a1d9ebcb3aa2f95e8bba9e900c1a5061bc168b" + integrity sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ== optionalDependencies: - "@esbuild/aix-ppc64" "0.21.5" - "@esbuild/android-arm" "0.21.5" - "@esbuild/android-arm64" "0.21.5" - "@esbuild/android-x64" "0.21.5" - "@esbuild/darwin-arm64" "0.21.5" - "@esbuild/darwin-x64" "0.21.5" - "@esbuild/freebsd-arm64" "0.21.5" - "@esbuild/freebsd-x64" "0.21.5" - "@esbuild/linux-arm" "0.21.5" - "@esbuild/linux-arm64" "0.21.5" - "@esbuild/linux-ia32" "0.21.5" - "@esbuild/linux-loong64" "0.21.5" - "@esbuild/linux-mips64el" "0.21.5" - "@esbuild/linux-ppc64" "0.21.5" - "@esbuild/linux-riscv64" "0.21.5" - "@esbuild/linux-s390x" "0.21.5" - "@esbuild/linux-x64" "0.21.5" - "@esbuild/netbsd-x64" "0.21.5" - "@esbuild/openbsd-x64" "0.21.5" - "@esbuild/sunos-x64" "0.21.5" - "@esbuild/win32-arm64" "0.21.5" - "@esbuild/win32-ia32" "0.21.5" - "@esbuild/win32-x64" "0.21.5" + "@esbuild/aix-ppc64" "0.25.2" + "@esbuild/android-arm" "0.25.2" + "@esbuild/android-arm64" "0.25.2" + "@esbuild/android-x64" "0.25.2" + "@esbuild/darwin-arm64" "0.25.2" + "@esbuild/darwin-x64" "0.25.2" + "@esbuild/freebsd-arm64" "0.25.2" + "@esbuild/freebsd-x64" "0.25.2" + "@esbuild/linux-arm" "0.25.2" + "@esbuild/linux-arm64" "0.25.2" + "@esbuild/linux-ia32" "0.25.2" + "@esbuild/linux-loong64" "0.25.2" + "@esbuild/linux-mips64el" "0.25.2" + "@esbuild/linux-ppc64" "0.25.2" + "@esbuild/linux-riscv64" "0.25.2" + "@esbuild/linux-s390x" "0.25.2" + "@esbuild/linux-x64" "0.25.2" + "@esbuild/netbsd-arm64" "0.25.2" + "@esbuild/netbsd-x64" "0.25.2" + "@esbuild/openbsd-arm64" "0.25.2" + "@esbuild/openbsd-x64" "0.25.2" + "@esbuild/sunos-x64" "0.25.2" + "@esbuild/win32-arm64" "0.25.2" + "@esbuild/win32-ia32" "0.25.2" + "@esbuild/win32-x64" "0.25.2" estree-walker@^3.0.3: version "3.0.3" @@ -661,107 +814,155 @@ estree-walker@^3.0.3: dependencies: "@types/estree" "^1.0.0" -execa@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c" - integrity sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^8.0.1" - human-signals "^5.0.0" - is-stream "^3.0.0" - merge-stream "^2.0.0" - npm-run-path "^5.1.0" - onetime "^6.0.0" - signal-exit "^4.1.0" - strip-final-newline "^3.0.0" +expect-type@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/expect-type/-/expect-type-1.2.1.tgz#af76d8b357cf5fa76c41c09dafb79c549e75f71f" + integrity sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw== fast-content-type-parse@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-content-type-parse/-/fast-content-type-parse-2.0.1.tgz#c236124534ee2cb427c8d8e5ba35a4856947847b" integrity sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q== +fdir@^6.4.3: + version "6.4.3" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.3.tgz#011cdacf837eca9b811c89dbb902df714273db72" + integrity sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw== + +foreground-child@^3.1.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f" + integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== + dependencies: + cross-spawn "^7.0.6" + signal-exit "^4.0.1" + fsevents@~2.3.2, fsevents@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== -get-func-name@^2.0.1, get-func-name@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" - integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== +glob@^10.4.1: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + 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" + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -get-stream@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" - integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA== +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== -human-signals@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28" - integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ== +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== is-plain-object@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== -is-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" - integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== - isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== -js-tokens@^9.0.1: - version "9.0.1" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-9.0.1.tgz#2ec43964658435296f6761b34e10671c2d9527f4" - integrity sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ== +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== -local-pkg@^0.5.0: - version "0.5.1" - resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-0.5.1.tgz#69658638d2a95287534d4c2fff757980100dbb6d" - integrity sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ== +istanbul-lib-report@^3.0.0, istanbul-lib-report@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + 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.6: + version "5.0.6" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz#acaef948df7747c8eb5fbf1265cb980f6353a441" + integrity sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A== dependencies: - mlly "^1.7.3" - pkg-types "^1.2.1" + "@jridgewell/trace-mapping" "^0.3.23" + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + +istanbul-reports@^3.1.7: + version "3.1.7" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" + integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" -loupe@^2.3.6, loupe@^2.3.7: - version "2.3.7" - resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" - integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== dependencies: - get-func-name "^2.0.1" + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + +loupe@^3.1.0, loupe@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.1.3.tgz#042a8f7986d77f3d0f98ef7990a2b2fef18b0fd2" + integrity sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug== -magic-string@^0.30.5: +lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + +magic-string@^0.30.17: version "0.30.17" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453" integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA== dependencies: "@jridgewell/sourcemap-codec" "^1.5.0" -merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== +magicast@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.3.5.tgz#8301c3c7d66704a0771eb1bad74274f0ec036739" + integrity sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ== + dependencies: + "@babel/parser" "^7.25.4" + "@babel/types" "^7.25.4" + source-map-js "^1.2.0" -mimic-fn@^4.0.0: +make-dir@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" - integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" -mlly@^1.7.3, mlly@^1.7.4: - version "1.7.4" - resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.7.4.tgz#3d7295ea2358ec7a271eaa5d000a0f84febe100f" - integrity sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw== +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== dependencies: - acorn "^8.14.0" - pathe "^2.0.1" - pkg-types "^1.3.0" - ufo "^1.5.4" + brace-expansion "^2.0.1" + +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== ms@^2.1.3: version "2.1.3" @@ -780,13 +981,6 @@ node-fetch@^2.6.7: dependencies: whatwg-url "^5.0.0" -npm-run-path@^5.1.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.3.0.tgz#e23353d0ebb9317f174e93417e4a4d82d0249e9f" - integrity sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ== - dependencies: - path-key "^4.0.0" - once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -794,60 +988,45 @@ once@^1.4.0: dependencies: wrappy "1" -onetime@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" - integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== - dependencies: - mimic-fn "^4.0.0" - -p-limit@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-5.0.0.tgz#6946d5b7140b649b7a33a027d89b4c625b3a5985" - integrity sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ== - dependencies: - yocto-queue "^1.0.0" +package-json-from-dist@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" + integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-key@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" - integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== - -pathe@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" - integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ== +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" -pathe@^2.0.1: +pathe@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716" integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w== -pathval@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" - integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== +pathval@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-2.0.0.tgz#7e2550b422601d4f6b8e26f1301bc8f15a741a25" + integrity sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA== -picocolors@^1.0.0, picocolors@^1.1.1: +picocolors@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== -pkg-types@^1.2.1, pkg-types@^1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.3.1.tgz#bd7cc70881192777eef5326c19deb46e890917df" - integrity sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ== - dependencies: - confbox "^0.1.8" - mlly "^1.7.4" - pathe "^2.0.1" +picomatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" + integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== -postcss@^8.4.43: +postcss@^8.5.3: version "8.5.3" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.3.tgz#1463b6f1c7fb16fe258736cba29a2de35237eafb" integrity sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A== @@ -856,21 +1035,7 @@ postcss@^8.4.43: picocolors "^1.1.1" source-map-js "^1.2.1" -pretty-format@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" - integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== - dependencies: - "@jest/schemas" "^29.6.3" - ansi-styles "^5.0.0" - react-is "^18.0.0" - -react-is@^18.0.0: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" - integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== - -rollup@^4.20.0: +rollup@^4.34.9: version "4.40.0" resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.40.0.tgz#13742a615f423ccba457554f006873d5a4de1920" integrity sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w== @@ -899,6 +1064,11 @@ rollup@^4.20.0: "@rollup/rollup-win32-x64-msvc" "4.40.0" fsevents "~2.3.2" +semver@^7.5.3: + version "7.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" + integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -916,12 +1086,12 @@ siginfo@^2.0.0: resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30" integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g== -signal-exit@^4.1.0: +signal-exit@^4.0.1: version "4.1.0" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== -source-map-js@^1.2.1: +source-map-js@^1.2.0, source-map-js@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== @@ -931,37 +1101,107 @@ stackback@0.0.2: resolved "https://registry.yarnpkg.com/stackback/-/stackback-0.0.2.tgz#1ac8a0d9483848d1695e418b6d031a3c3ce68e3b" integrity sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw== -std-env@^3.5.0: +std-env@^3.8.1: version "3.9.0" resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.9.0.tgz#1a6f7243b339dca4c9fd55e1c7504c77ef23e8f1" integrity sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw== -strip-final-newline@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" - integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + 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: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + 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" -strip-literal@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-2.1.1.tgz#26906e65f606d49f748454a08084e94190c2e5ad" - integrity sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q== +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + 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" + 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.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: - js-tokens "^9.0.1" + has-flag "^4.0.0" -tinybench@^2.5.1: +test-exclude@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-7.0.1.tgz#20b3ba4906ac20994e275bbcafd68d510264c2a2" + integrity sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^10.4.1" + minimatch "^9.0.4" + +tinybench@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.9.0.tgz#103c9f8ba6d7237a47ab6dd1dcff77251863426b" integrity sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg== -tinypool@^0.8.3: - version "0.8.4" - resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-0.8.4.tgz#e217fe1270d941b39e98c625dcecebb1408c9aa8" - integrity sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ== +tinyexec@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.3.2.tgz#941794e657a85e496577995c6eef66f53f42b3d2" + integrity sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA== + +tinyglobby@^0.2.12: + version "0.2.12" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.12.tgz#ac941a42e0c5773bd0b5d08f32de82e74a1a61b5" + integrity sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww== + dependencies: + fdir "^6.4.3" + picomatch "^4.0.2" -tinyspy@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-2.2.1.tgz#117b2342f1f38a0dbdcc73a50a454883adf861d1" - integrity sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A== +tinypool@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-1.0.2.tgz#706193cc532f4c100f66aa00b01c42173d9051b2" + integrity sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA== + +tinyrainbow@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/tinyrainbow/-/tinyrainbow-2.0.0.tgz#9509b2162436315e80e3eee0fcce4474d2444294" + integrity sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw== + +tinyspy@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-3.0.2.tgz#86dd3cf3d737b15adcf17d7887c84a75201df20a" + integrity sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q== tr46@~0.0.3: version "0.0.3" @@ -973,21 +1213,11 @@ tunnel@^0.0.6: resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== -type-detect@^4.0.0, type-detect@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.1.0.tgz#deb2453e8f08dcae7ae98c626b13dddb0155906c" - integrity sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw== - typescript@^5.3.3: version "5.8.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e" integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== -ufo@^1.5.4: - version "1.6.1" - resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.6.1.tgz#ac2db1d54614d1b22c1d603e3aef44a85d8f146b" - integrity sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA== - undici-types@~6.19.2: version "6.19.8" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" @@ -1010,53 +1240,56 @@ universal-user-agent@^7.0.0, universal-user-agent@^7.0.2: resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-7.0.2.tgz#52e7d0e9b3dc4df06cc33cb2b9fd79041a54827e" integrity sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q== -vite-node@1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.6.1.tgz#fff3ef309296ea03ceaa6ca4bb660922f5416c57" - integrity sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA== +vite-node@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-3.1.1.tgz#ad186c07859a6e5fca7c7f563e55fb11b16557bc" + integrity sha512-V+IxPAE2FvXpTCHXyNem0M+gWm6J7eRyWPR6vYoG/Gl+IscNOjXzztUhimQgTxaAoUoj40Qqimaa0NLIOOAH4w== dependencies: cac "^6.7.14" - debug "^4.3.4" - pathe "^1.1.1" - picocolors "^1.0.0" - vite "^5.0.0" - -vite@^5.0.0: - version "5.4.18" - resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.18.tgz#b5af357f9d5ebb2e0c085779b7a37a77f09168a4" - integrity sha512-1oDcnEp3lVyHCuQ2YFelM4Alm2o91xNoMncRm1U7S+JdYfYOvbiGZ3/CxGttrOu2M/KcGz7cRC2DoNUA6urmMA== - dependencies: - esbuild "^0.21.3" - postcss "^8.4.43" - rollup "^4.20.0" + debug "^4.4.0" + es-module-lexer "^1.6.0" + pathe "^2.0.3" + vite "^5.0.0 || ^6.0.0" + +"vite@^5.0.0 || ^6.0.0": + version "6.3.0" + resolved "https://registry.yarnpkg.com/vite/-/vite-6.3.0.tgz#17c86b3a0f4d20b210fe89f22f7b27d5926fcce5" + integrity sha512-9aC0n4pr6hIbvi1YOpFjwQ+QOTGssvbJKoeYkuHHGWwlXfdxQlI8L2qNMo9awEEcCPSiS+5mJZk5jH1PAqoDeQ== + dependencies: + esbuild "^0.25.0" + fdir "^6.4.3" + picomatch "^4.0.2" + postcss "^8.5.3" + rollup "^4.34.9" + tinyglobby "^0.2.12" optionalDependencies: fsevents "~2.3.3" -vitest@^1.3.0: - version "1.6.1" - resolved "https://registry.yarnpkg.com/vitest/-/vitest-1.6.1.tgz#b4a3097adf8f79ac18bc2e2e0024c534a7a78d2f" - integrity sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag== - dependencies: - "@vitest/expect" "1.6.1" - "@vitest/runner" "1.6.1" - "@vitest/snapshot" "1.6.1" - "@vitest/spy" "1.6.1" - "@vitest/utils" "1.6.1" - acorn-walk "^8.3.2" - chai "^4.3.10" - debug "^4.3.4" - execa "^8.0.1" - local-pkg "^0.5.0" - magic-string "^0.30.5" - pathe "^1.1.1" - picocolors "^1.0.0" - std-env "^3.5.0" - strip-literal "^2.0.0" - tinybench "^2.5.1" - tinypool "^0.8.3" - vite "^5.0.0" - vite-node "1.6.1" - why-is-node-running "^2.2.2" +vitest@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-3.1.1.tgz#39fa2356e510513fccdc5d16465a9fc066ef1fc6" + integrity sha512-kiZc/IYmKICeBAZr9DQ5rT7/6bD9G7uqQEki4fxazi1jdVl2mWGzedtBs5s6llz59yQhVb7FFY2MbHzHCnT79Q== + dependencies: + "@vitest/expect" "3.1.1" + "@vitest/mocker" "3.1.1" + "@vitest/pretty-format" "^3.1.1" + "@vitest/runner" "3.1.1" + "@vitest/snapshot" "3.1.1" + "@vitest/spy" "3.1.1" + "@vitest/utils" "3.1.1" + chai "^5.2.0" + debug "^4.4.0" + expect-type "^1.2.0" + magic-string "^0.30.17" + pathe "^2.0.3" + std-env "^3.8.1" + tinybench "^2.9.0" + tinyexec "^0.3.2" + tinypool "^1.0.2" + tinyrainbow "^2.0.0" + vite "^5.0.0 || ^6.0.0" + vite-node "3.1.1" + why-is-node-running "^2.3.0" webidl-conversions@^3.0.0: version "3.0.1" @@ -1078,7 +1311,7 @@ which@^2.0.1: dependencies: isexe "^2.0.0" -why-is-node-running@^2.2.2: +why-is-node-running@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/why-is-node-running/-/why-is-node-running-2.3.0.tgz#a3f69a97107f494b3cdc3bdddd883a7d65cebf04" integrity sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w== @@ -1086,12 +1319,25 @@ why-is-node-running@^2.2.2: siginfo "^2.0.0" stackback "0.0.2" +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + 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.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + 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" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - -yocto-queue@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.2.1.tgz#36d7c4739f775b3cbc28e6136e21aa057adec418" - integrity sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg== From 2e5ebcf1f879f38b030e8a4a180073569c63019a Mon Sep 17 00:00:00 2001 From: Diogo Ribeiro Date: Wed, 16 Apr 2025 22:24:49 +0100 Subject: [PATCH 6/7] chore: development work --- .github/workflows/run_tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 2f13965..eeece84 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -12,10 +12,10 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Node.js - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 20 From 4a35713dfe71aac59efb5fd5ee1deed2ceae6162 Mon Sep 17 00:00:00 2001 From: Diogo Ribeiro Date: Wed, 16 Apr 2025 22:26:35 +0100 Subject: [PATCH 7/7] Update src/core/__tests__/labelManager.test.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/core/__tests__/labelManager.test.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/core/__tests__/labelManager.test.ts b/src/core/__tests__/labelManager.test.ts index e07cb84..75ee22b 100644 --- a/src/core/__tests__/labelManager.test.ts +++ b/src/core/__tests__/labelManager.test.ts @@ -55,7 +55,3 @@ describe('ensureLabelExists', () => { }); }); }); -function beforeEach(callback: () => void) { - callback(); -} -