diff --git a/.ai/architecture.yaml b/.ai/architecture.yaml index c96e7296..44b0f847 100644 --- a/.ai/architecture.yaml +++ b/.ai/architecture.yaml @@ -22,12 +22,12 @@ components: validationProvider.ts: Input validation with Quick Fixes componentBrowserProvider.ts: Component browser webview UI componentDetector.ts: Detect GitLab CI component usage in YAML - componentHtmlRenderer.ts: Render component docs as HTML + hoverContentBuilder.ts: Build the hover popup's markdown body (vscode-free, unit-tested) depends_on: - services - utils - types - - templates + - webview services: location: src/services/ purpose: Business logic and data management @@ -77,14 +77,17 @@ components: depends_on: - types - utils - templates: - location: src/templates/ - purpose: HTML template generation for webview UIs + webview: + location: src/webview/ + purpose: Helpers and assets for the webview documents rendered by the providers files: - detachedComponent.ts: Detached component view template - helpers/htmlBuilder.ts: HTML construction helper - helpers/styleBuilder.ts: CSS style helper - index.ts: Public exports + webviewHtml.ts: Nonce, Content-Security-Policy and asset-URI helpers for webview documents + inlineMarkdown.ts: HTML escaping and inline-Markdown rendering (vscode-free, unit-tested) + scriptData.ts: Safe JSON serialization for embedding data in a script block (vscode-free, unit-tested) + clientInlineMarkdown.ts: Source text for the browser-side twin of renderInlineMarkdown (vscode-free, unit-tested) + styles/: Stylesheets built to out/webview/styles/ and loaded via a CSP'd link + notes: Assets under styles/ (and client/ as scripts are extracted) are built by the webview esbuild + context and resolved at runtime through assetUri; they are not bundled into out/extension.js. depends_on: - types constants: @@ -140,6 +143,26 @@ components: publish-release.sh: Publish to VS Code marketplace release-and-publish.sh: Combined release and publish setup-github-token.sh: GitHub token configuration + demo_gifs: + location: scripts/demo-gifs/ + purpose: Maintainer tool that records the README demo GIFs by driving a real VS Code through Playwright over CDP + packaged: false (scripts/** in .vscodeignore; own package.json, out/ and node_modules/ gitignored) + files: + record.mjs: Entry point. Resets the work dir, packages + installs the VSIX, warms the cache, records scenes + lib/config.mjs: Paths, viewport (1280x800 at 2x), GIF size (1100 wide, 12 fps), env overrides; refuses a + GCH_DEMO_DIR not named gch-demo* or containing the home folder or repo, since it is wiped each run + lib/workspace.mjs: Throwaway profile, demo workspace (my-pipelines), vsce package + install + lib/vscode.mjs: Launch/stop VS Code, Command Palette, scene reset, webview frame lookup + lib/input.mjs: Drawn cursor, eased mouse moves, typing, wheel scrolling + lib/recorder.mjs: CDP screencast capture, ffmpeg GIF encode, per-second review sheet + scenes/: One module per GIF (browse, complete, hover, validate, versions) + fixtures/: Profile settings.json (component sources, quiet editor) and templates/deploy.yml for local includes + how_it_works: + - VS Code starts with --remote-debugging-port=0; the port is read from /DevToolsActivePort and + Playwright attaches with chromium.connectOverCDP, so a stray instance can't be picked up by mistake + - Emulation.setDeviceMetricsOverride fixes the viewport so output size doesn't depend on the screen + - The OS pointer isn't captured, so a cursor element is drawn in the top document and moved with page.mouse + - Page.startScreencast frames only arrive on change; an ffmpeg concat list holds each frame until the next interfaces: Component: location: src/types/git-component.ts @@ -213,8 +236,8 @@ data_flow: component: componentService action: Fetch component details (cache-first) - step: 4 - component: componentHtmlRenderer - action: Render documentation as HTML using templates/helpers + component: hoverContentBuilder + action: Build the hover markdown body (a MarkdownString, not HTML) - step: 5 component: hoverProvider action: Display hover card diff --git a/.ai/context.yaml b/.ai/context.yaml index a12fc9a5..bce25a4d 100644 --- a/.ai/context.yaml +++ b/.ai/context.yaml @@ -29,6 +29,7 @@ structure: types: src/types/ utils: src/utils/ scripts: scripts/ + demo_gifs: scripts/demo-gifs/ context_modules: architecture: architecture.yaml workflows: workflows.yaml diff --git a/.ai/decisions.yaml b/.ai/decisions.yaml index 3867ad60..352d0960 100644 --- a/.ai/decisions.yaml +++ b/.ai/decisions.yaml @@ -124,6 +124,42 @@ decisions: - .release-it/vscode-version.js - package.json (release:main, release:beta scripts) title: Release It + DEPENDABOT_TARGETS_BETA: + date: '2026-09-14' + status: accepted + context: Dependabot defaulted to the repository default branch (main), which is the stable + release line. Bumps opened there duplicated what had already landed on beta, and a merge + to main auto-cuts a stable release. + decision: 'Set target-branch: "beta" on every ecosystem in .github/dependabot.yml (npm, + github-actions, pip)' + rationale: + - A push to main runs release-it with .release-it.json and cuts a stable GitHub release, so + a routine dependency bump merged there ships a release out of band + - main trails beta by everything not yet released, so bumps against main duplicate versions + beta already carries (e.g. #291/#292/#295 re-proposed bumps merged weeks earlier) + - Retargeting such a PR to beta conflicts on package-lock.json, since beta has moved + - Updates reach main the same way every other change does, through the beta -> main release PR + implementation: + config: '.github/dependabot.yml, target-branch: "beta" on each of the three package-ecosystem + entries' + flow: dependabot -> beta -> release PR -> main + alternatives_considered: + - name: leave_targeting_main + rejected_because: Ships stable releases from dependency bumps and produces duplicate PRs + - name: retarget_each_pr_by_hand + rejected_because: Lockfile conflicts on every npm PR; recurring manual work + consequences: + positive: + - Dependency updates follow the same path as feature work + - No stable release cut by a dependency bump + - No duplicate bumps against a stale branch + negative: + - A security fix reaches main only when the next release PR merges + references: + - .github/dependabot.yml + - .release-it.json + - .release-it.beta.json + title: Dependabot Targets Beta MODULAR_SERVICE_SPLIT: date: '2026' status: accepted @@ -391,6 +427,38 @@ decisions: - .mocharc.cjs - package.json (test scripts) title: Mocha Over Jest + DEMO_GIFS_RECORDED_BY_SCRIPT: + date: '2026-10' + status: accepted + context: README/Marketplace GIFs were hand-recorded, went stale as the UI changed, and risked showing the + maintainer's own projects and paths + decision: Record them with scripts/demo-gifs (Playwright driving a packaged VSIX in a throwaway profile) and + host the output as GitHub user-attachments linked from README.md + rationale: + - Re-recording after a UI change is one command, and every take looks the same + - Fresh profile, neutral my-pipelines folder and public gitlab.com components keep personal details out + - Installing the packaged VSIX keeps "[Extension Development Host]" out of the title bar + - user-attachments URLs are public for a public repo and render on the Marketplace; committing GIFs would + grow the repo by ~4 MB per re-record + consequences: + positive: + - Demos can be refreshed with every UI change + - Review sheets make the privacy check quick + negative: + - macOS + local VS Code only; not run in CI + - user-attachments links stop rendering publicly if the repo goes private, and GitHub doesn't promise + they last forever + alternatives_considered: + - name: manual screen recording + rejected_because: Inconsistent, slow to redo, easy to leak personal details + - name: commit GIFs under images/ + rejected_because: Repo growth on every re-record + - name: extensionDevelopmentPath instead of a VSIX + rejected_because: Title bar shows [Extension Development Host] + references: + - scripts/demo-gifs/record.mjs + - .ai/workflows.yaml (record_demo_gifs) + title: Demo GIFs Recorded By Script future_decisions: - question: Should we support other CI/CD platforms (GitHub Actions, CircleCI)? status: under_consideration diff --git a/.ai/errors.yaml b/.ai/errors.yaml index 3d6a7a33..f9e40861 100644 --- a/.ai/errors.yaml +++ b/.ai/errors.yaml @@ -391,6 +391,26 @@ errors: - Re-enable v10 once @release-it/conventional-changelog adopts the render-function stack (conventional-changelog@8 / writer@9) reference: .github/dependabot.yml + package.json; see huntridge-labs/argus#318 + demo_gif_recording_fails: + symptom: npm run record in scripts/demo-gifs fails or produces a wrong-looking GIF + causes: + - cause: 'listen EINVAL on .../1.13-main.sock or "IPC handle is longer than 103 chars"' + solution: Point GCH_DEMO_DIR at a short folder named gch-demo*, e.g. /tmp/gch-demo2 (default /tmp/gch-demo). + Other names are refused because the folder is wiped on every run + - cause: 'mach_port_rendezvous ... Permission denied, or "Starting inspector failed: operation not permitted"' + solution: Run outside the command sandbox; VS Code can't start inside it + - cause: VS Code never wrote DevToolsActivePort, or a stray instance from a crashed run holds the profile + solution: pkill -9 -f "user-data-dir=${GCH_DEMO_DIR:-/tmp/gch-demo}/profile" and run again + - cause: Command Palette did not highlight a command + solution: The command title changed in VS Code; update the name in the scene or lib/vscode.mjs + - cause: An empty "Drag a view here" pane or a side bar shows up + solution: prepareScene hides side bars by checking visibility; check the .part.* selectors still match + - cause: Typing lands at the wrong indent or Enter accepts a suggestion + solution: Scenes rely on fixtures/settings.json (wordBasedSuggestions off) and VS Code's YAML auto-indent; + re-check those after a VS Code update + - cause: A webview element is never found + solution: Webviews are out-of-process frames that only attach while the script is connected; open the + panel inside the same run and use webviewFrame(page, selector) debugging: enable_debug_logs: steps: diff --git a/.ai/index.yaml b/.ai/index.yaml index efc14d4c..af3737f5 100644 --- a/.ai/index.yaml +++ b/.ai/index.yaml @@ -19,15 +19,16 @@ keys: - cache - component - constants + - demo_gifs - errors - extension - parsers - providers - scripts - services - - templates - types - utils + - webview workflows: - add_configuration_option - add_new_command @@ -35,6 +36,7 @@ keys: - build_and_package - debug_extension - fix_failing_test + - record_demo_gifs - release - run_tests - setup_dev_environment @@ -43,6 +45,8 @@ keys: - BATCH_API_REQUESTS - CACHE_COMPONENTS - CENTRALIZED_ERROR_HANDLING + - DEMO_GIFS_RECORDED_BY_SCRIPT + - DEPENDABOT_TARGETS_BETA - EXTENSION_HOST_TEST_LAYER - FILE_SIZE_POLICY - MOCHA_OVER_JEST @@ -61,6 +65,7 @@ keys: - cache_issues - compilation_errors - component_not_loading + - demo_gif_recording_fails - empty_changelog_conventionalcommits_v10 - extension_not_activating - hover_not_working diff --git a/.ai/workflows.yaml b/.ai/workflows.yaml index e9285c21..adbb2576 100644 --- a/.ai/workflows.yaml +++ b/.ai/workflows.yaml @@ -138,6 +138,40 @@ workflows: command: npm test - action: commit_changes command: 'git commit -m ''chore: update dependencies''' + record_demo_gifs: + description: Re-record the README demo GIFs (browse, complete, hover, validate, versions) after a UI change + location: scripts/demo-gifs/ + prerequisites: + - macOS with VS Code installed at /Applications (override with VSCODE_BIN / VSCODE_CLI) + - ffmpeg on PATH + - Network access to gitlab.com (scenes use public components/opentofu, sast, secret-detection, code-quality) + - Run outside any command sandbox; VS Code needs its mach port and debug port + - Root dependencies installed (npm ci at the repo root); vsce package runs the root vscode:prepublish build + steps: + - action: install_recorder_dependencies + command: cd scripts/demo-gifs && npm ci + note: Own package.json/lock, separate from the extension's; root npm install never touches it + - action: record + command: npm run record + note: 'All scenes, or name some: npm run record -- hover versions. Packages the extension with vsce, + installs it into a throwaway profile under /tmp/gch-demo (GCH_DEMO_DIR, which is wiped each run and must be + named gch-demo*), drives VS Code over CDP on a free debug port, + writes out/.gif and out/-review.png' + - action: privacy_review + check: Open every out/-review.png (one tile per second) and confirm no names, paths, accounts, + private projects or tokens appear. The profile is fresh and the folder is my-pipelines, but check anyway + - action: publish + steps: + - Drag the GIFs into a comment on the README PR on GitHub and post it + - Copy the github.com/user-attachments/assets/ URLs from the comment into README.md + - Confirm each URL loads without logging in (curl -sL -o /dev/null -w '%{http_code}' returns 200) + note: GIFs are not committed; see decisions.yaml DEMO_GIFS_RECORDED_BY_SCRIPT + - action: add_or_change_a_scene + location: scripts/demo-gifs/scenes/{name}.mjs + contract: Export cursorStart, prepare(page) and perform(page); register it in SCENES in record.mjs + helpers: lib/vscode.mjs (prepareScene, runCommand, webviewFrame), lib/input.mjs (moveTo, clickOn, typeSlow, + wordPosition, scrollIntoView) + reference: scripts/demo-gifs/record.mjs common_commands: compile: npm run compile watch: npm run watch @@ -145,6 +179,7 @@ common_commands: debug: F5 (in VS Code) package: npm run package lint: npm run lint + lint_ci: npm run lint:ci (eslint + stylelint with GitHub annotation formatters; run by CI) git_workflow: branch_naming: feature/description or fix/description commit_format: 'type(scope): description' diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 8a8ce834..e83bba37 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,11 +6,18 @@ # in osv-scanner.toml that the Argus scan honors. Do NOT add a dev-dep `ignore:` here to suppress # those alerts -- `ignore:` also stops the version-update PRs below, which are how dev tools stay # current and how a transitive fix (e.g. serialize-javascript >= 7.0.5) actually lands. +# +# Every ecosystem below sets `target-branch: "beta"`. Without it Dependabot opens against the default +# branch (`main`), which is the STABLE release line: a push there auto-cuts a stable GitHub release, so a +# routine dependency bump would ship one out of band. `main` also trails `beta` by whatever has not been +# released yet, so bumps opened against it duplicate what already landed on `beta` and conflict on the +# lockfile when retargeted. Everything reaches `main` through the beta -> main release PR instead. version: 2 updates: # Maintain npm dependencies - package-ecosystem: "npm" directory: "/" + target-branch: "beta" schedule: interval: "weekly" day: "monday" @@ -68,6 +75,7 @@ updates: # Maintain GitHub Actions - package-ecosystem: "github-actions" directory: "/" + target-branch: "beta" schedule: interval: "weekly" day: "monday" @@ -85,6 +93,7 @@ updates: # Maintain pre-commit hooks - package-ecosystem: "pip" directory: "/" + target-branch: "beta" schedule: interval: "weekly" day: "monday" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5839f328..bdabbde2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,7 +27,7 @@ jobs: run: npm ci - name: Run lint - run: npm run lint + run: npm run lint:ci - name: Run compile run: node esbuild.js diff --git a/.github/workflows/security-hardening.yml b/.github/workflows/security-hardening.yml index 0eb89aa9..52d4646f 100644 --- a/.github/workflows/security-hardening.yml +++ b/.github/workflows/security-hardening.yml @@ -19,8 +19,10 @@ permissions: jobs: argus-hardening: name: Argus Reusable Hardening - # Pinned to the commit for Argus v1.11.0 for supply-chain safety. - uses: huntridge-labs/argus/.github/workflows/reusable-security-hardening.yml@9b444d8975f4a2253cc53e09a7c5837e5b509d24 + # SHA-pinned rather than tag-pinned for supply-chain safety: a tag can be moved, a commit cannot. + # Dependabot bumps this SHA and names the tag it resolves to in the PR title, so read the version there + # rather than trusting a hand-written one here (this comment claimed v1.11.0 through three bumps past it). + uses: huntridge-labs/argus/.github/workflows/reusable-security-hardening.yml@3fb133a5d03ec81a7a534cf451dd19991e04a975 with: scanners: codeql,gitleaks,osv,dependency-review enable_code_security: true diff --git a/README.md b/README.md index 8b9f947b..6156a6cc 100644 --- a/README.md +++ b/README.md @@ -1,63 +1,82 @@ -# ๐Ÿš€ GitLab Component Helper +

+ GitLab Component Helper +

-[![AICaC](https://img.shields.io/badge/AICaC-Comprehensive-success.svg)](https://github.com/eFAILution/AICaC) +

GitLab Component Helper

+ +

+ Autocomplete, inline docs, and a component browser for GitLab CI/CD, right in VS Code.
+ Works with gitlab.com and self-hosted GitLab, public or private. +

+ +

+ Marketplace version + Installs + CI status + MIT license + AICaC +

-> Browse, insert, and manage reusable GitLab CI/CD components in VS Code โ€” from any GitLab instance, public or private. +

+ Quick start ยท + Features ยท + Configuration ยท + Commands ยท + Settings ยท + Troubleshooting +

-### Component Browser -![componentBrowser](https://github.com/user-attachments/assets/6e4ad12e-d3f5-4165-8b72-c59bda51ae38) +![Searching the Component Browser, picking inputs, and inserting a component](https://github.com/user-attachments/assets/83dd2645-7cdc-4bfa-a6bc-4a315f0c1ea8) ---- +[GitLab CI/CD components](https://docs.gitlab.com/ci/components/) make pipelines reusable, but writing them means jumping between your editor, the catalog, and each component's docs to find the right path, version, and inputs. This extension brings all of that into the file you're editing. -## โœจ Features +## Quick start + +[![AICaC](https://img.shields.io/badge/AICaC-Comprehensive-success.svg)](https://github.com/eFAILution/AICaC) -- **Component Browser** โ€” explore and insert components from any GitLab project or group -- **Smart Completion** โ€” context-aware suggestions for components and versions as you type -- **Hover Docs** โ€” full documentation and parameter hints inline; when a component declares no description, its README's opening lines stand in -- **Input Validation** โ€” real-time checking of component inputs, with Quick Fix suggestions -- **Local Includes** โ€” the same hover, completion, and validation for `include: - local:` entries that declare a `spec.inputs` block -- **Version Picker & Upgrade Hints** โ€” pick the right tag, and get flagged when a pinned semver falls behind (with one-click updates) -- **Variable Expansion** โ€” resolves GitLab CI/CD variables (`$CI_SERVER_FQDN`, `$CI_PROJECT_PATH`, โ€ฆ) in component URLs -- **Private Access** โ€” add private projects/groups with a token, stored encrypted per instance -- **Fast** โ€” caching and batched API calls keep large catalogs responsive -![componentAutofill](https://github.com/user-attachments/assets/a76ba19a-240b-4799-a08f-88a78a5cf004) +1. Install **GitLab Component Helper** from the Extensions view, or run `code --install-extension eFAILution.gitlab-component-helper`. +2. Open a `.gitlab-ci.yml` and type `component:`. Suggestions come with versions already filled in. +3. Hover any component URL to read its docs and inputs. +4. Run **GitLab CI: Browse Components** from the Command Palette to explore everything your sources offer. ---- +Want your own components in the list? Run **GitLab CI: Add Component Project/Group** and point it at a project or group. A token is only needed for private ones. -## ๐Ÿ› ๏ธ Quick Start +## Features -1. **Install** "GitLab Component Helper" from the VS Code Extensions view. -2. **Browse** โ€” `Ctrl+Shift+P` โ†’ **GitLab CI: Browse Components**. -3. **Add a source** โ€” **GitLab CI: Add Component Project/Group** (public or private; token optional). -4. **Author** โ€” type `component:` in a `.gitlab-ci.yml` and accept the versioned suggestions. -5. **Hover** any component URL for instant documentation. +### Browse and insert -![hoverContext](https://github.com/user-attachments/assets/3c92f336-db04-4a68-80cf-43732d96b6f1) +The Component Browser lists every component from your configured projects and groups, on any GitLab instance. Pick one, choose a version, and insert it, with its inputs stubbed out if you want them. A **Raw YAML** toggle shows the original template. ---- +### Complete as you type -## ๐Ÿ”’ Private Components +Context-aware completion for component paths, versions, and input names. GitLab CI/CD variables such as `$CI_SERVER_FQDN` and `$CI_PROJECT_PATH` are resolved in component URLs. -Add a private project or group with a personal access token โ€” once per GitLab instance, then it's reused for that instance. Tokens are stored with VS Code **SecretStorage** (encrypted, never in plain text or files) and used only for API calls to the instance you added. +![Autocompleting a component and picking its version](https://github.com/user-attachments/assets/84e9a936-ed33-471b-8f59-5e8126b23577) -Create the token with the **`read_api`** scope, and ensure its user has at least **Reporter** access to the project. +### Docs on hover -> โš ๏ธ The legacy `gitlabComponentHelper.gitlabToken` setting stores tokens in plain text in `settings.json` and is **deprecated**. Use **GitLab CI: Add Component Project/Group** instead, then clear the field. +Hover a component to see its description, inputs, defaults, and version status. If a component has no description of its own, the opening paragraph of its `README.md` stands in. ---- +![Hovering a component and one of its inputs](https://github.com/user-attachments/assets/4c945758-e077-4890-8285-cf69dfb16891) -## โšก Example +### Inputs that check themselves + +Inputs are checked as you type. Unknown names and missing required inputs get flagged, with Quick Fixes to add what's missing. ```yaml include: - - component: https://gitlab.com/components/terraform@v1.0.0 + - component: gitlab.com/components/terraform@v1.0.0 inputs: terraform_version: "1.5.0" workspace: "default" ``` -Local templates work the same way โ€” point a `- local:` entry at a workspace YAML that declares a `spec.inputs` block and you get the same hover, completion, and validation: +![Fixing a mistyped input, then filling a local template's inputs](https://github.com/user-attachments/assets/97f44dd4-105b-4002-9bf5-8584cfee0940) + +### Local includes too + +`include: - local:` entries get the same hover, completion, and validation, as long as the target file declares a `spec.inputs` block. ```yaml include: @@ -67,51 +86,78 @@ include: job_type: nightly ``` -![insertInputs](https://github.com/user-attachments/assets/098f4eaf-3c4a-45a8-9caf-9a1351730b93) -![inputsValidation](https://github.com/user-attachments/assets/54d4b2ce-ad84-4bbc-8cd7-911a01565536) +### Stay on the latest version + +When a component is pinned to a semantic version (`X.Y.Z`, optionally `v`-prefixed), the extension checks for a newer **stable** release: + +- Hover shows `โœ“ up to date` or `โš ๏ธ update available` next to your version. +- An outdated pin gets a warning squiggle with an **Update to `X.Y.Z`** Quick Fix (`Ctrl+.` / `Cmd+.`). +- **GitLab CI: Update All Component Versions to Latest** bumps every outdated pin in the file at once. + +![Updating an outdated pin with a Quick Fix, then updating the rest](https://github.com/user-attachments/assets/85ecce79-7187-42b3-9b97-c88437026e1c) + +Floating refs (`main`, `latest`, `~latest`), partial pins (`1`, `1.2`), and commit SHAs are left alone, and pre-releases are never suggested. The check runs when a CI file is opened or saved and reuses the version cache. + +
+Choosing a default version per component +
+ +Completion and the Component Browser offer the same default for each component: the highest semantic version, falling back to `main` or `master` when the project has no releases. + +To change that, open the Component Browser, load a component's versions, and right-click the version dropdown: + +- **Set as Default Version** pins the version you picked. +- **Always Use Latest** always offers the highest stable version. + +Choosing one replaces the other. The choice is saved in `gitlabComponentHelper.versionPreferences` in your user settings, keyed by `//`, with `~latest` meaning Always Use Latest. You can edit or clear it there. A workspace entry for the same component wins over your user setting. + +
---- +### Private components -## ๐Ÿ†™ Stay on the Latest Version +Add a private project or group with **GitLab CI: Add Component Project/Group**. You enter a token once per GitLab instance, and it's reused for everything on that instance. -When a component is pinned to a semantic version (`X.Y.Z`), the extension checks whether a newer **stable** release exists and helps you upgrade: +- Tokens live in VS Code **SecretStorage**: encrypted, never in plain text or settings files. +- They're only sent to the instance you added them for. +- Use the **`read_api`** scope, on a user with at least **Reporter** access to the project. -- **Hover** shows the latest available version next to the one you're on โ€” `โœ“ up to date` or `โš ๏ธ update available`. -- An outdated pin gets a **warning squiggle** on the version ref, with an **Update to `X.Y.Z`** quick fix (`Ctrl+.`). -- **GitLab CI: Update All Component Versions to Latest** rewrites every outdated pin in the active file at once. +> **Heads up:** the old `gitlabComponentHelper.gitlabToken` setting stores tokens in plain text and is deprecated. Re-add the source with the command above, then clear that field. -Only clean `X.Y.Z` pins (optionally `v`-prefixed) are checked โ€” floating refs (`main`, `latest`, `~latest`), partial pins (`1`, `1.2`), and commit SHAs are left untouched, and pre-release tags are never suggested. The check runs when a CI file is opened or saved (not on every keystroke) and reuses the version cache. Toggle it with `gitlabComponentHelper.versionCheck.enabled`; soften the squiggle to an informational underline with `gitlabComponentHelper.versionCheck.severity`. +### Fast on big catalogs ---- +Component data is cached (one hour by default) and API calls are batched, so large groups stay responsive. -## โš™๏ธ Configuration +## Configuration -Point the extension at your component sources in VS Code settings: +Most people only need component sources. Add them with the command above, or in `settings.json`: -```json +```jsonc "gitlabComponentHelper.componentSources": [ { "name": "OpenTofu Components", "path": "components/opentofu", "gitlabInstance": "gitlab.com" }, { "name": "Internal CI Components", "path": "devops/ci-components", "gitlabInstance": "gitlab.company.com" } ] ``` -To recognise CI files kept outside the defaults (`.gitlab-ci.yml`, `.gitlab-ci.yaml`, and anything under `.gitlab/`), add globs โ€” they're merged with the built-in defaults and match at any depth: +CI files are recognised at `.gitlab-ci.yml`, `.gitlab-ci.yaml`, and anywhere under `.gitlab/`. Keep pipelines somewhere else? Add globs. They're merged with the defaults and match at any depth: ```jsonc "gitlabComponentHelper.additionalFileGlobs": ["**/ci/*.yml", "**/pipelines/**/*.yaml"] ``` -**Advanced setups** have their own guides: -- [Component discovery tuning](https://github.com/eFAILution/gitlab-component-helper/blob/main/docs/discovery.md) โ€” scan custom directories or depths for repos that pre-date the [GitLab Components spec](https://docs.gitlab.com/ci/components/#directory-structure). -- [Monorepo tag conventions](https://github.com/eFAILution/gitlab-component-helper/blob/main/docs/monorepo-tags.md) โ€” scope per-component tags in a tag-per-component monorepo. +
+Advanced setups +
-Every setting is listed in the [Settings Reference](#-settings-reference) below and editable from the VS Code Settings UI. +- **[Component discovery tuning](https://github.com/eFAILution/gitlab-component-helper/blob/main/docs/discovery.md):** scan custom directories or depths for repos that pre-date the [GitLab components layout](https://docs.gitlab.com/ci/components/#directory-structure). +- **[Monorepo tag conventions](https://github.com/eFAILution/gitlab-component-helper/blob/main/docs/monorepo-tags.md):** scope per-component tags in a tag-per-component monorepo. ---- +
-## ๐Ÿ“ Template Header Spec (Optional) +
+Template header comments (for component authors) +
-Add spec-compliant header comments to the top of a template to surface consistent context in the Component Browser. Supported keys: `summary`, `usage`, `note`. +Add header comments to the top of a template to show consistent context in the Component Browser. Supported keys are `summary`, `usage`, and `note`. ```yaml # @gitlab-component-helper: summary: Push a Helm chart to Sonic @@ -119,45 +165,46 @@ Add spec-compliant header comments to the top of a template to surface consisten # @gitlab-component-helper: note: Requires a protected ref for publish ``` -The short prefix `# @gch:` works too. Headers must appear before any non-comment content; multiple `note` lines are allowed, and the section stays hidden if no header is present. Component details also include a **Raw YAML** toggle for inspecting the original template. - -When a component or project has no description of its own, the Component Browser and hover fall back to the opening paragraph of its `README.md` โ€” checked alongside the template first, then at the repository root. - ---- +- The short prefix `# @gch:` works too. +- Headers must come before any non-comment content. +- Multiple `note` lines are allowed. +- The section stays hidden when no header is present. -## ๐Ÿงฉ Commands +When a component or project has no description, the browser and hover use the opening paragraph of its `README.md`, checked next to the template first and then at the repository root. -Run from the Command Palette (`Ctrl+Shift+P`): +
-- **GitLab CI: Browse Components** โ€” explore and insert from your sources -- **GitLab CI: Add Component Project/Group** โ€” add a project/group (optional token for private access) -- **GitLab CI: Update All Component Versions to Latest** โ€” bump outdated semver pins in the active file -- **GitLab CI: Refresh Components Cache** / **Update Cache** / **Reset Cache** โ€” refresh, force a full re-fetch, or clear cached data -- **GitLab CI: Show Cache Status** โ€” cache info and stats +## Commands -Debugging commands are also available: **Debug Cache (Detailed)**, **Show Performance Statistics**, and **Test Providers**. +Open the Command Palette (`Ctrl+Shift+P` / `Cmd+Shift+P`) and type **GitLab CI**. ---- +| Command | What it does | +| --- | --- | +| **Browse Components** | Explore and insert components from your sources | +| **Add Component Project/Group** | Add a project or group, with an optional token for private access | +| **Update All Component Versions to Latest** | Bump every outdated semver pin in the active file | +| **Refresh Components Cache** | Refresh cached component data | +| **Update Cache** | Force a full re-fetch | +| **Reset Cache** | Clear all cached data | +| **Show Cache Status** | Show cache info and stats | -## ๐Ÿ†˜ Troubleshooting +For debugging there's also **Debug Cache (Detailed)**, **Show Performance Statistics**, and **Test Providers**. -- **No components showing?** Confirm the file's language mode is YAML and that component sources are configured. -- **HTTP 401 / "token expired" errors?** The token is expired or invalid โ€” re-add it via **GitLab CI: Add Component Project/Group**, or the **Update Token** action in the error view. Confirm it has the **`read_api`** scope and at least **Reporter** access. -- **Version dropdown not loading?** Check connectivity to the GitLab instance, verify token/permissions, and refresh the cache. -- **Still stuck?** Set `gitlabComponentHelper.logLevel` to `DEBUG`, reproduce, and open an issue with the output and your configuration. +## Settings reference ---- +Every setting is also editable from the Settings UI under **GitLab Component Helper**. -## โš™๏ธ Settings Reference - -Add these to `settings.json` or configure them via the Settings UI. +
+All settings +
| Setting | Type | Default | Description | -|--------|------|---------|-------------| -| `gitlabComponentHelper.componentSources` | array | _see [Configuration](#-configuration)_ | GitLab repositories with reusable components. Each item takes `name`, `path`, `gitlabInstance`, and optionally a `discovery` block or a `tagPattern` (see the advanced guides). | +| --- | --- | --- | --- | +| `gitlabComponentHelper.componentSources` | array | _see [Configuration](#configuration)_ | GitLab repositories with reusable components. Each item takes `name`, `path`, `gitlabInstance`, and optionally a `discovery` block or a `tagPattern` (see the advanced guides). | | `gitlabComponentHelper.additionalFileGlobs` | array | `[]` | Extra GitLab CI file globs, merged with the built-in defaults. Patterns match at any depth (e.g. `ci/*.yml` โ†’ `**/ci/*.yml`). | | `gitlabComponentHelper.versionCheck.enabled` | boolean | `true` | Warn when a component pinned to a semantic version has a newer stable release. Checked on open/save. | | `gitlabComponentHelper.versionCheck.severity` | string | `warning` | Severity of the "newer version available" diagnostic. One of `warning`, `information`. | +| `gitlabComponentHelper.versionPreferences` | object | `{}` | Version offered per component, keyed by `//`: a version, or `~latest` for the highest stable version. Set via **Set as Default Version** or **Always Use Latest** in the Component Browser. | | `gitlabComponentHelper.cacheTime` | number | `3600` | Component cache lifetime, in seconds. | | `gitlabComponentHelper.logLevel` | string | `ERROR` | Logging level. One of `DEBUG`, `INFO`, `WARN`, `ERROR`. | | `gitlabComponentHelper.autoShowOutput` | boolean | `false` | Show the output channel automatically when the log level changes. | @@ -166,21 +213,49 @@ Add these to `settings.json` or configure them via the Settings UI. | `gitlabComponentHelper.batchSize` | number | `5` | Components processed in parallel per batch. | | `gitlabComponentHelper.discovery.templateRoots` | array | `["templates"]` | Directories scanned for components (up to 5). See [discovery tuning](https://github.com/eFAILution/gitlab-component-helper/blob/main/docs/discovery.md). | | `gitlabComponentHelper.discovery.maxDepth` | number | `1` | Subdirectory depth to recurse under each root. Range `0`โ€“`3`. | -| `gitlabComponentHelper.discovery.filePatterns` | array | `["*.yml", "*.yaml"]` | Filename globs for template files (filename only โ€” no path globs). | +| `gitlabComponentHelper.discovery.filePatterns` | array | `["*.yml", "*.yaml"]` | Filename globs for template files (filename only, no path globs). | | `gitlabComponentHelper.discovery.templateFileNames` | array | `["template.yml", "template.yaml"]` | Filenames recognised inside per-component subfolders. | -| `gitlabComponentHelper.gitlabToken` | string | `""` | โš ๏ธ **Deprecated** โ€” stores tokens in plain text. Use **GitLab CI: Add Component Project/Group** instead. | +| `gitlabComponentHelper.gitlabToken` | string | `""` | **Deprecated.** Stores tokens in plain text. Use **GitLab CI: Add Component Project/Group** instead. | + +
+ +## Troubleshooting + +
+No components showing up +
+ +Check that the file's language mode is YAML and that at least one component source is configured. + +
---- +
+HTTP 401 or "token expired" +
-## ๐Ÿ”Œ API +The token is expired or invalid. Re-add it with **GitLab CI: Add Component Project/Group**, or use the **Update Token** action in the error view. Make sure it has the **`read_api`** scope and at least **Reporter** access. -The extension is designed to expose a programmatic API for other extensions to consume โ€” see [docs/api.md](https://github.com/eFAILution/gitlab-component-helper/blob/main/docs/api.md). **Status: not yet exposed** (`activate()` does not return the API today); the doc describes the intended contract. +
---- +
+Version dropdown won't load +
-## ๐Ÿง‘โ€๐Ÿ’ป Development +Check that you can reach the GitLab instance, verify the token and its permissions, then run **GitLab CI: Refresh Components Cache**. -**Prerequisites:** VS Code 1.120.0+, Node.js 22.x+, npm. +
+ +
+Still stuck? +
+ +Set `gitlabComponentHelper.logLevel` to `DEBUG`, reproduce the problem, and [open an issue](https://github.com/eFAILution/gitlab-component-helper/issues) with the output and your configuration (leave out any tokens). + +
+ +## Contributing + +Issues and pull requests are welcome. ```bash git clone https://github.com/eFAILution/gitlab-component-helper.git @@ -189,20 +264,14 @@ npm install npm run compile ``` -Press `F5` to launch an Extension Development Host with the extension loaded. - ---- - -## ๐Ÿค Contributing - -1. Fork and branch (`git checkout -b feat/your-feature`). -2. Commit using [conventional commits](https://www.conventionalcommits.org/) (`feat:`, `fix:`, `docs:`, `chore:`, โ€ฆ). -3. Open a Pull Request. +Press `F5` to launch an Extension Development Host with the extension loaded. You'll need VS Code 1.120.0+ and Node.js 22+. -Releases are two-stage: **[release-it](https://github.com/release-it/release-it)** bumps the version and `CHANGELOG.md` from the commit history when changes land on `beta`/`main`, then publishing to the Marketplace is a **manually-dispatched** GitHub Actions workflow (Publish / Publish Beta). See [docs/RELEASING.md](https://github.com/eFAILution/gitlab-component-helper/blob/main/docs/RELEASING.md). +- Branch from `beta` and use [conventional commits](https://www.conventionalcommits.org/) (`feat:`, `fix:`, `docs:`, `chore:`, โ€ฆ). +- `npm test` runs the unit suite. `npm run test:extension-host` runs the tests inside real VS Code. +- Releases are cut by [release-it](https://github.com/release-it/release-it) when changes land on `beta` or `main`. Publishing to the Marketplace is a manual workflow. See [docs/RELEASING.md](https://github.com/eFAILution/gitlab-component-helper/blob/main/docs/RELEASING.md). ---- +A programmatic API for other extensions is planned but not exposed yet. [docs/api.md](https://github.com/eFAILution/gitlab-component-helper/blob/main/docs/api.md) describes the intended contract. -## ๐Ÿ“„ License +## License -MIT โ€” see [`LICENSE`](./LICENSE). +[MIT](https://github.com/eFAILution/gitlab-component-helper/blob/main/LICENSE) diff --git a/esbuild.js b/esbuild.js index 8eec0ae0..f07182a2 100644 --- a/esbuild.js +++ b/esbuild.js @@ -1,9 +1,16 @@ const esbuild = require('esbuild'); +const fs = require('fs'); const production = process.argv.includes('--production'); const watch = process.argv.includes('--watch'); /** + * Emits the `[watch] build started`/`finished` markers VS Code's background problem matcher keys on. + * + * Only one context may emit them: the matcher treats the first `finished` as "task ready", so a second pair from a + * parallel build would mark the task ready while that build is still running. {@link errorReporterPlugin} covers the + * other contexts. + * * @type {import('esbuild').Plugin} */ const esbuildProblemMatcherPlugin = { @@ -14,42 +21,127 @@ const esbuildProblemMatcherPlugin = { console.log('[watch] build started'); }); build.onEnd((result) => { - result.errors.forEach(({ text, location }) => { - console.error(`โœ˜ [ERROR] ${text}`); - console.error(` ${location.file}:${location.line}:${location.column}:`); - }); + reportErrors(result); console.log('[watch] build finished'); }); }, }; -async function main() { - const ctx = await esbuild.context({ - entryPoints: ['src/extension.ts'], - bundle: true, - format: 'cjs', - minify: production, - sourcemap: !production, - sourcesContent: false, - platform: 'node', - outfile: 'out/extension.js', - external: ['vscode'], - logLevel: 'silent', - // Additional optimizations - treeShaking: true, - metafile: production, - // Drop console logs in production for smaller bundle - drop: production ? ['console', 'debugger'] : [], - plugins: [ - /* add to the end of plugins array */ - esbuildProblemMatcherPlugin, - ], +/** + * Reports build errors without emitting watch markers, for contexts that build alongside the marker-emitting one. + * + * @param {string} label Which build the errors came from, since the output is interleaved. + * @returns {import('esbuild').Plugin} + */ +const errorReporterPlugin = (label) => ({ + name: `esbuild-error-reporter-${label}`, + + setup(build) { + build.onEnd((result) => reportErrors(result, label)); + }, +}); + +/** @param {import('esbuild').BuildResult} result @param {string} [label] */ +function reportErrors(result, label) { + const prefix = label ? `โœ˜ [ERROR] [${label}] ` : 'โœ˜ [ERROR] '; + result.errors.forEach(({ text, location }) => { + console.error(`${prefix}${text}`); + if (location) { + console.error(` ${location.file}:${location.line}:${location.column}:`); + } + }); +} + +/** + * Build config for the Node-side extension bundle. + */ +const extensionConfig = { + entryPoints: ['src/extension.ts'], + bundle: true, + format: 'cjs', + minify: production, + sourcemap: !production, + sourcesContent: false, + platform: 'node', + outfile: 'out/extension.js', + external: ['vscode'], + logLevel: 'silent', + // Additional optimizations + treeShaking: true, + metafile: production, + // Drop console logs in production for smaller bundle + drop: production ? ['console', 'debugger'] : [], + plugins: [ + /* add to the end of plugins array */ + esbuildProblemMatcherPlugin, + ], +}; + +/** + * Every webview asset to build, discovered rather than listed. + * + * A stylesheet missing from a hand-maintained list still lints and typechecks, the build still exits 0, and the + * `` only 404s once the extension is packaged. Discovery keeps the build in step with the directory. + * + * Only the top level of each directory is collected, so shared modules imported by a client script are bundled into + * it rather than becoming entry points of their own. Directories that don't exist yet (`client/`, until scripts are + * extracted) contribute nothing. + * + * @returns {string[]} Paths of every asset entry point, relative to the repo root. + */ +function webviewEntryPoints() { + const assetDirs = [ + { dir: 'src/webview/styles', ext: '.css' }, + { dir: 'src/webview/client', ext: '.ts' }, + ]; + + return assetDirs.flatMap(({ dir, ext }) => { + if (!fs.existsSync(dir)) { + return []; + } + return fs + .readdirSync(dir, { withFileTypes: true }) + // `.d.ts` files declare ambient types for the client scripts; they emit nothing and are not assets. + .filter((entry) => entry.isFile() && entry.name.endsWith(ext) && !entry.name.endsWith('.d.ts')) + .map((entry) => `${dir}/${entry.name}`); }); +} + +/** + * Build config for webview assets (styles, and client scripts as they are + * added). These run in the browser-like webview context, not Node, so they + * build separately and emit under out/webview for asWebviewUri loading. + */ +const webviewConfig = { + entryPoints: webviewEntryPoints(), + bundle: true, + minify: production, + sourcemap: production ? false : 'inline', + platform: 'browser', + // Pin the syntax level: webview assets run in the Electron renderer, not Node, so they must not inherit + // esbuild's `esnext` default. + target: ['es2020'], + format: 'iife', + outdir: 'out/webview', + // Preserve the src/webview/* folder structure (styles/, client/) under the + // output dir so asset URIs resolve to the same sub-path as the source. + outbase: 'src/webview', + logLevel: 'silent', + plugins: [errorReporterPlugin('webview')], +}; + +async function main() { + // Clear stale output: esbuild never removes files, so a renamed or deleted asset would leave a copy behind that + // still resolves through asWebviewUri โ€” masking a broken reference until the extension is packaged. + fs.rmSync(webviewConfig.outdir, { recursive: true, force: true }); + + const ctx = await esbuild.context(extensionConfig); + const webviewCtx = await esbuild.context(webviewConfig); if (watch) { - await ctx.watch(); + await Promise.all([ctx.watch(), webviewCtx.watch()]); } else { - await ctx.rebuild(); - await ctx.dispose(); + await Promise.all([ctx.rebuild(), webviewCtx.rebuild()]); + await Promise.all([ctx.dispose(), webviewCtx.dispose()]); } } diff --git a/eslint.config.js b/eslint.config.js index 12cc5627..f5cf9078 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -40,4 +40,26 @@ module.exports = [ ...js.configs.recommended.rules, }, }, + { + // Demo GIF recorder, a maintainer tool. Its page.evaluate callbacks run in the workbench, hence browser globals. + files: ['scripts/demo-gifs/**/*.mjs'], + languageOptions: { + sourceType: 'module', + globals: { ...globals.node, ...globals.browser }, + }, + rules: { + ...js.configs.recommended.rules, + }, + }, + { + // Webview client scripts run in the Electron renderer, not the extension host + files: ['src/webview/client/**/*.ts'], + languageOptions: { + globals: { + ...globals.browser, + // Injected by VS Code into the webview; not a browser global. + acquireVsCodeApi: 'readonly', + }, + }, + }, ]; diff --git a/package-lock.json b/package-lock.json index e8fbf063..93e136ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,49 +1,53 @@ { "name": "gitlab-component-helper", - "version": "0.16.12", + "version": "0.17.21", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "gitlab-component-helper", - "version": "0.16.12", + "version": "0.17.21", "license": "MIT", "devDependencies": { - "@commitlint/cli": "^21.2.2", + "@commitlint/cli": "^21.2.3", "@commitlint/config-conventional": "^21.0.2", + "@csstools/stylelint-formatter-github": "^2.0.0", "@digitalroute/cz-conventional-changelog-for-jira": "^8.0.1", "@eslint/js": "^10.0.1", - "@octokit/core": "^7.0.7", + "@octokit/core": "^7.0.8", "@octokit/plugin-paginate-rest": "^15.0.0", - "@release-it/conventional-changelog": "^12.0.0", + "@release-it/conventional-changelog": "^12.0.2", "@types/glob": "^9.0.0", - "@types/js-yaml": "^4.0.9", "@types/mocha": "^10.0.10", - "@types/node": "^26.2.0", + "@types/node": "^26.6.2", "@types/vscode": "^1.120.0", - "@typescript-eslint/eslint-plugin": "^8.67.0", - "@typescript-eslint/parser": "^8.67.0", + "@types/vscode-webview": "^1.57.5", + "@typescript-eslint/eslint-plugin": "^8.70.1", + "@typescript-eslint/parser": "^8.70.1", "@vscode/test-electron": "^3.1.0", "commitizen": "^4.3.2", "conventional-changelog-conventionalcommits": "^9.3.1", "cz-conventional-changelog": "^3.3.0", - "cz-emoji-conventional": "^1.1.0", + "cz-emoji-conventional": "^1.3.0", "dateformat": "^5.0.3", - "dotenv": "^17.4.2", + "dotenv": "^18.0.3", "esbuild": "^0.28.2", - "eslint": "^10.8.1", - "globals": "^17.11.0", + "eslint": "^10.11.0", + "eslint-formatter-gha": "^2.0.1", + "globals": "^17.12.0", "husky": "^9.1.6", "is-ci": "^4.0.0", - "js-yaml": "^5.3.0", + "js-yaml": "^5.4.2", "minimatch": "^10.2.6", - "mocha": "^11.8.0", + "mocha": "^12.0.2", "npm-run-all": "^4.1.5", - "release-it": "^21.0.2", + "release-it": "^21.1.0", "semver": "^7.8.5", - "tsx": "^4.23.12", + "stylelint": "^17.15.0", + "stylelint-config-standard": "^40.0.0", + "tsx": "^4.23.15", "typescript": "^6.0.3", - "typescript-eslint": "^8.67.0" + "typescript-eslint": "^8.70.1" }, "engines": { "node": ">=22.0.0", @@ -75,19 +79,43 @@ "node": ">=6.9.0" } }, + "node_modules/@cacheable/memory": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.2.0.tgz", + "integrity": "sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cacheable/utils": "^2.5.0", + "@keyv/bigmap": "^1.3.1", + "hookified": "^1.15.1", + "keyv": "^5.6.0" + } + }, + "node_modules/@cacheable/utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@cacheable/utils/-/utils-2.5.0.tgz", + "integrity": "sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hashery": "^1.5.1", + "keyv": "^5.6.0" + } + }, "node_modules/@commitlint/cli": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-21.2.2.tgz", - "integrity": "sha512-a+6hQxIxnpdvSvS2apvttPNbEliYsVC3PqFYDiiB2kjbwIsQsj1urvQ4Tkf70pKYozPalKAuRQmm/GHwndduqA==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-21.2.3.tgz", + "integrity": "sha512-5yOX6IRjcrIReCxpyAd04hgI/yhUMpVBJ/ouwFV0wk9yx5+fYRDWZWJ5h55Tbedgfol+5m2mU5nqzbB8g3v0vQ==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/config-conventional": "^21.2.2", - "@commitlint/format": "^21.2.2", - "@commitlint/lint": "^21.2.2", - "@commitlint/load": "^21.2.2", - "@commitlint/read": "^21.2.1", - "@commitlint/types": "^21.2.0", + "@commitlint/config-conventional": "^21.2.3", + "@commitlint/format": "^21.2.3", + "@commitlint/lint": "^21.2.3", + "@commitlint/load": "^21.2.3", + "@commitlint/read": "^21.2.3", + "@commitlint/types": "^21.2.3", "tinyexec": "^1.0.0", "yargs": "^18.0.0" }, @@ -99,13 +127,13 @@ } }, "node_modules/@commitlint/config-conventional": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-21.2.2.tgz", - "integrity": "sha512-NxA37SZviusFUEYOQZ5hNnZ1h7O/KiemPkxjOlpzKJNnWxThiwc6/SaZhaPa8fyLvfRBAywhQhJJk8XESHWlpQ==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-21.2.3.tgz", + "integrity": "sha512-EP2n5DN2GwRWNVrLX0Jx3mpQlW5PfFi9HnD9OJ8hN/H0xFqpCFyHeGDhg+0P8/21iMMcdkcQgbNqmVklebqYsQ==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^21.2.0", + "@commitlint/types": "^21.2.3", "conventional-changelog-conventionalcommits": "^10.0.0" }, "engines": { @@ -126,13 +154,13 @@ } }, "node_modules/@commitlint/config-validator": { - "version": "21.2.0", - "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-21.2.0.tgz", - "integrity": "sha512-t7AzNHAKeIdo/3NRGwzpufKHsKkPHmFs/56N2Fnsh0/r0rGtnQzTxk6vnFgjaGr4hdSQKNB50/KAhR9Yk4LJKA==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-21.2.3.tgz", + "integrity": "sha512-JQ13v0GafSM4fBYX8UowSy++07Was20auq0NcTdnzSEq6/05Cq5GBUMIfKkqjzyBwC9sJFmPpKWgLLhH7cygkw==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^21.2.0", + "@commitlint/types": "^21.2.3", "ajv": "^8.11.0" }, "engines": { @@ -140,13 +168,13 @@ } }, "node_modules/@commitlint/ensure": { - "version": "21.2.0", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-21.2.0.tgz", - "integrity": "sha512-76IF9vDNS13lAzEEik9eKwzt8f9hYhWiwVXZ2AnyLCz5/f511FsEQ3pw1X3/zSQpdRLQU7i5qDMVKyXi1GWjSg==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-21.2.3.tgz", + "integrity": "sha512-gEjNKgRocbODI5/sMx2Qc9XOf2/zFTNV2aEK1QZ4gKDKxDC/VR7us3QtIX1C5d5xxHxx0I/tEbYbdSP1Am2LwA==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^21.2.0", + "@commitlint/types": "^21.2.3", "es-toolkit": "^1.46.0" }, "engines": { @@ -164,13 +192,13 @@ } }, "node_modules/@commitlint/format": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-21.2.2.tgz", - "integrity": "sha512-v6fvxZSc/AvVMROlr3H34+1766bZSYApRUSCAMjWamStPjKMvZ8GdvVA5YW/VQNgbFTmcMz6OYmSTJEvIjPrfA==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-21.2.3.tgz", + "integrity": "sha512-KKwCjXYqA8r295uhLnulDXL9yekdXmj2yp2Q0XsBPhxQ2iPuvRE8F43j7g7yexo69wTdmUQmFz15jpderluzUQ==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^21.2.0", + "@commitlint/types": "^21.2.3", "picocolors": "^1.1.1" }, "engines": { @@ -178,13 +206,13 @@ } }, "node_modules/@commitlint/is-ignored": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-21.2.2.tgz", - "integrity": "sha512-9UoKNgfFE3LU7FrzierCvk3CdDfMDeVGC86qZiT/n0TIjfq/dmZ9MHuXd45OTNRa26ZanmJRxEtmiXk/lEJihg==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-21.2.3.tgz", + "integrity": "sha512-Ng4nRj/LBAOvc+GQu7bsFW4/fL89LvZ14OOC/ERLbUpnG6QBwWRzY/1oXGwPs3C8YHWjJObin4kLYo2YeEn70w==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^21.2.0", + "@commitlint/types": "^21.2.3", "semver": "^7.6.0" }, "engines": { @@ -192,32 +220,32 @@ } }, "node_modules/@commitlint/lint": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-21.2.2.tgz", - "integrity": "sha512-Fy8JxEBzdmsYWFude/61GxXu5O+wEymwiRK2z9GL9R8mCsXphCoGxAFc5iHn5mjlfcSrhiiONE+ksf4KOjnaPg==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-21.2.3.tgz", + "integrity": "sha512-lUZcSuVLLEDkhge9ERk8Rp+FXQtrUhCK+h328BFnzKXrTuXGdqiYMEpTlNWdZaOrjyMhMJaz354ZaWEGJxcLeg==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/is-ignored": "^21.2.2", - "@commitlint/parse": "^21.2.2", - "@commitlint/rules": "^21.2.2", - "@commitlint/types": "^21.2.0" + "@commitlint/is-ignored": "^21.2.3", + "@commitlint/parse": "^21.2.3", + "@commitlint/rules": "^21.2.3", + "@commitlint/types": "^21.2.3" }, "engines": { "node": ">=22.12.0" } }, "node_modules/@commitlint/load": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-21.2.2.tgz", - "integrity": "sha512-0Tt6wDPX167cjKC5D4zhm0+20wJJG+TN/TKovMOspfSe78rOnKX+MNzlVNiu6HyQPZChPJ8QBH31MVt6Bb8fCg==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-21.2.3.tgz", + "integrity": "sha512-cDrL8lOo23Lk7knGzQdjbFcq7z2JgvjwV6PhbESVvEc+Fe21MeLjPKBJi8nKjg7j+jh79CVbVSUbZc104thXRw==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/config-validator": "^21.2.0", + "@commitlint/config-validator": "^21.2.3", "@commitlint/execute-rule": "^21.0.1", - "@commitlint/resolve-extends": "^21.2.2", - "@commitlint/types": "^21.2.0", + "@commitlint/resolve-extends": "^21.2.3", + "@commitlint/types": "^21.2.3", "cosmiconfig": "^9.0.1", "cosmiconfig-typescript-loader": "^6.1.0", "es-toolkit": "^1.46.0", @@ -239,13 +267,13 @@ } }, "node_modules/@commitlint/parse": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-21.2.2.tgz", - "integrity": "sha512-MEkobPfvRp+z06Wro8HMG1BDGHzZmj82A1LH1nWeG3ipHpg/x4m6v3wEDvMBIKjRFUnfR3nBeFs3MVCr7UdAmg==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-21.2.3.tgz", + "integrity": "sha512-Jt61QpF1xA88damCELe8I0FlDZPSpXNc8IhN7z5kZ0EcDYPjdZ+ZHPvsSXl69r2MIlLnNKeHhOn2cmVpziFE9w==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^21.2.0", + "@commitlint/types": "^21.2.3", "conventional-changelog-angular": "^9.0.0", "conventional-commits-parser": "^7.0.0" }, @@ -254,14 +282,14 @@ } }, "node_modules/@commitlint/read": { - "version": "21.2.1", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-21.2.1.tgz", - "integrity": "sha512-hUW7EJQnNTL0vPOmVMNK4CrnrNBN0nN+JJHReFkdHO5y4iyHeEmTBwuC15OCqUTjxWo7idnH1LftfpWVIaPWIA==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-21.2.3.tgz", + "integrity": "sha512-szAepuLA1vTTr7fuudEg7jYyVHudf+FH+vptU91bhxE1WnE8TKrfTAi44HVllz8XpI8Pvp4GjR/iP5Nshgh+og==", "dev": true, "license": "MIT", "dependencies": { "@commitlint/top-level": "^21.2.0", - "@commitlint/types": "^21.2.0", + "@commitlint/types": "^21.2.3", "@conventional-changelog/git-client": "^3.0.0", "tinyexec": "^1.0.0" }, @@ -270,14 +298,14 @@ } }, "node_modules/@commitlint/resolve-extends": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-21.2.2.tgz", - "integrity": "sha512-RPkJ/IFi7sMUUVbZLqwWFtWw/zRDcfFsmrPSiTMrt5wb7AdxOr86EGQFvmGzef5QKV5IPBWWCujqVTw1RWX44A==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-21.2.3.tgz", + "integrity": "sha512-bqJdmAtXgAQel+l02uIsF7rHgKgx1AGZdGBjam7uK4XW54ZAQtB6XAIUXezYprQiCcRMpBh4fHs5JodXK4mVZA==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/config-validator": "^21.2.0", - "@commitlint/types": "^21.2.0", + "@commitlint/config-validator": "^21.2.3", + "@commitlint/types": "^21.2.3", "es-toolkit": "^1.46.0", "global-directory": "^5.0.0", "resolve-from": "^5.0.0" @@ -287,16 +315,16 @@ } }, "node_modules/@commitlint/rules": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-21.2.2.tgz", - "integrity": "sha512-eplQzyYkBjYB1HyyRj8hkcK11Y9DU9nuBz7uOKEd6NpE9NGDytLFCAnlRE+OoiK/5sHEJsaz2RGhuWBvYzIbNA==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-21.2.3.tgz", + "integrity": "sha512-5+YnI/LuTx3JDl9GjqfP2z9x96M8KKDrd+4jOel/T0L1BB3oAmBlSN8xppf63QsudiVEgR8C0gRoAMrPVrms6g==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/ensure": "^21.2.0", + "@commitlint/ensure": "^21.2.3", "@commitlint/message": "^21.2.0", "@commitlint/to-lines": "^21.0.1", - "@commitlint/types": "^21.2.0" + "@commitlint/types": "^21.2.3" }, "engines": { "node": ">=22.12.0" @@ -326,9 +354,9 @@ } }, "node_modules/@commitlint/types": { - "version": "21.2.0", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-21.2.0.tgz", - "integrity": "sha512-7zVFCDB2reMvJH5dmbKnOQPjZEvjdJTH8jc0U/PIPU1r3/+vf5pD1HlfitV2MWsWXrvu7u39iY1lyLUPOaN0Gw==", + "version": "21.2.3", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-21.2.3.tgz", + "integrity": "sha512-sGEA473TlCvhCGNoTBY9OXZVWdscIXdGt0dm8EpB+2MRfmt8LNh/X56P/T3nCtEB+eH5qGEa3odphSAoUxSfSQ==", "dev": true, "license": "MIT", "dependencies": { @@ -340,9 +368,9 @@ } }, "node_modules/@conventional-changelog/git-client": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-3.1.0.tgz", - "integrity": "sha512-Tqa/gHco2WJWa740NRjOrfKVvzIqxkZpecb8bemaQ8sKM5PXb1UK4uTyTb/1wIqNuOVaDOFxyBdhTIQZn6gdjQ==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-3.1.2.tgz", + "integrity": "sha512-jZqwnJwf7nboIlAcw/mkOjVa6DexCcUOgT2oOQgkoi3z9vR8tGFkcMy2BFcYwjhL9sYcDDXkRQDayiDieCoW7A==", "dev": true, "license": "MIT", "dependencies": { @@ -355,7 +383,7 @@ }, "peerDependencies": { "conventional-commits-filter": "^6.0.1", - "conventional-commits-parser": "^7.0.1" + "conventional-commits-parser": "^7.1.2" }, "peerDependenciesMeta": { "conventional-commits-filter": { @@ -367,15 +395,200 @@ } }, "node_modules/@conventional-changelog/template": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@conventional-changelog/template/-/template-1.2.1.tgz", - "integrity": "sha512-TzlTVpKPjaqW6qOYjQcYUDuGsLCNsvFHVBXkYGTAnf5V37jCWrE5haKNXzz0WZUtVHjrpV76L1buANjwXMfT8w==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@conventional-changelog/template/-/template-1.4.0.tgz", + "integrity": "sha512-aalGyl7dbB5PArRebDIX43ZvBlXrYm9uWzGJ26t+4SzJVPsOuvfILGGbw5X4yX7i50YEmJ8zvbiWnqH/AAnZqg==", "dev": true, "license": "MIT", "engines": { "node": ">=22" } }, + "node_modules/@csstools/css-calc": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.3.0.tgz", + "integrity": "sha512-c5ihYsPkdG6JCkU2zTMm4+k6r7RXuGxtWYhu5DHMIiF1FHzrfmHL5so11AoFpUv/tu61xfcmT4AmKoFfMPoqdQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.12.tgz", + "integrity": "sha512-3vLQK+dXxhBMR2Wx99PTCifE+vHtW2ndZWyla8yK813ev6oGhyn8Lja8jCyGAWTJ+LEYZK7EVtJxrDj8ztevJw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@csstools/media-query-list-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-5.0.0.tgz", + "integrity": "sha512-T9lXmZOfnam3eMERPsszjY5NK0jX8RmThmmm99FZ8b7z8yMaFZWKwLWGZuTwdO3ddRY5fy13GmmEYZXB4I98Eg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/selector-resolve-nested": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/selector-resolve-nested/-/selector-resolve-nested-4.0.1.tgz", + "integrity": "sha512-j3vdQu0XwLME5qOTWxm8cnmvsf423R2YL6DbKklCHZwkDm7UdKNu6RPlw4REIJhSlKBICY3B70/7QZdicLqZgg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.1.1" + } + }, + "node_modules/@csstools/selector-specificity": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-6.0.0.tgz", + "integrity": "sha512-4sSgl78OtOXEX/2d++8A83zHNTgwCJMaR24FvsYL7Uf/VS8HZk9PTwR51elTbGqMuwH3szLvvOXEaVnqn0Z3zA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.1.1" + } + }, + "node_modules/@csstools/stylelint-formatter-github": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@csstools/stylelint-formatter-github/-/stylelint-formatter-github-2.0.0.tgz", + "integrity": "sha512-LAzHf7W1FmBNi/cA4n7ZqGW063UK+KZgcaoAmtkJZlbAxRlnthA/VEojmO06+eBAczKMMU1yslqsDh6Etvok8g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "stylelint": "^17.0.0" + } + }, "node_modules/@digitalroute/cz-conventional-changelog-for-jira": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/@digitalroute/cz-conventional-changelog-for-jira/-/cz-conventional-changelog-for-jira-8.0.1.tgz", @@ -944,9 +1157,9 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz", - "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==", + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.3.tgz", + "integrity": "sha512-IkO+/KEUvwbVpiURZg+P7zF74z5Jxe0UgJxVni+RtoHQ6IZieXaO02kmadomap/q+l6bc/jdPGGqTjhuZnuz1Q==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1024,9 +1237,9 @@ } }, "node_modules/@inquirer/ansi": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.7.tgz", - "integrity": "sha512-3eTuUO1vH2cZm2ZKHeQxnOqlTi9EfZDGgIe3BL3I4u+rJHocr9Fz86M4fjYABPvFnQG/gGK551HqDiIcETwU6Q==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.8.tgz", + "integrity": "sha512-WpQM+Ti6Z40EFwwt+uL2p4UabT+W179zHp6HhLVOzfbwnVn05IPO/eXIZXGNqcT1jbQ15SujNLzQ39k4QPPxBQ==", "dev": true, "license": "MIT", "engines": { @@ -1034,16 +1247,16 @@ } }, "node_modules/@inquirer/checkbox": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.2.1.tgz", - "integrity": "sha512-b6xmA/VlTe0ZgDQHDui+Nav470u7u49nRd8/iuhOcQPO9Ch7lGuogydhi2VOmNlZ+zXcM8IcPuNSwQcdJaF/kw==", + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.2.5.tgz", + "integrity": "sha512-bRt8J8m+Fot9CXv+zNQGXUq2ET0MggR1fPz7v6edN6MFYmsbfGnMmkmWZJEegMKqrAC8ej/o1sqisHZXZJMAfQ==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^2.0.7", - "@inquirer/core": "^11.2.1", - "@inquirer/figures": "^2.0.7", - "@inquirer/type": "^4.0.7" + "@inquirer/ansi": "^2.0.8", + "@inquirer/core": "^12.0.3", + "@inquirer/figures": "^2.0.9", + "@inquirer/type": "4.1.1" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" @@ -1058,14 +1271,14 @@ } }, "node_modules/@inquirer/confirm": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.1.1.tgz", - "integrity": "sha512-eb8DBZcz/2qHWQda4rk2JiQk5h9QV/cVHi1yjt0f69WFZMRFn0sJTye3EAP8icut8UDMjQPsaH5KbcOogefrFQ==", + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.3.2.tgz", + "integrity": "sha512-Xvr/0HggjddPtGppuqVmxhTw+Hr8PvsZ/k0HmOEaAqQEt80OITNkFWnsdNmyT0/eM4Ab+iJLx2R8rctlEyfSVg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^11.2.1", - "@inquirer/type": "^4.0.7" + "@inquirer/core": "^12.0.3", + "@inquirer/type": "4.1.1" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" @@ -1080,15 +1293,15 @@ } }, "node_modules/@inquirer/core": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-11.2.1.tgz", - "integrity": "sha512-Qd6GJT1yVyrZZCfN8W2qKF5ApmqryXRhRKCuip8h01x2w/esJQ2XIYc6f9abMIHgKQdBfFTSOdbHRLAhuM09UA==", + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.3.tgz", + "integrity": "sha512-wsSy0sznmXwkty+2PzZwx00Cazc/E0r0B7mAzdGROz2Ct+DFZXaK7WDjGZvgjRldxH5ZhFVfF2lgkYrqgOw2KA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^2.0.7", - "@inquirer/figures": "^2.0.7", - "@inquirer/type": "^4.0.7", + "@inquirer/ansi": "^2.0.8", + "@inquirer/figures": "^2.0.9", + "@inquirer/type": "4.1.1", "cli-width": "^4.1.0", "fast-wrap-ansi": "^0.2.0", "mute-stream": "^3.0.0", @@ -1140,15 +1353,15 @@ } }, "node_modules/@inquirer/editor": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.2.2.tgz", - "integrity": "sha512-ZRVd/oD+sYsUd5zVm0NflqEzlqfYCyHNsqkHl2oWXEUHs12tCbcSFi+wVFEvD8+LGRaMUsVrE7qeo6lSG/S1Vg==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.3.3.tgz", + "integrity": "sha512-YsKkS2q63IiLtaDK/9nqzdComN97SDQrmKiyNggN+ceP4ty+Z6VwyTz3FpjeUWeW1Efss2xHFKCC9sx7hnrsxg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^11.2.1", - "@inquirer/external-editor": "^3.0.3", - "@inquirer/type": "^4.0.7" + "@inquirer/core": "^12.0.3", + "@inquirer/external-editor": "^3.0.5", + "@inquirer/type": "4.1.1" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" @@ -1163,9 +1376,9 @@ } }, "node_modules/@inquirer/editor/node_modules/@inquirer/external-editor": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-3.0.3.tgz", - "integrity": "sha512-6thf5I8q7lZwzGLAxPaaGEREEkZ3nyePPDQ1oyobblxmEE8mqTLguScP7pDjUTAibiyb4hfXl+qjUEJ+di/aNA==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-3.0.5.tgz", + "integrity": "sha512-f3QQJRIX5ZEneBHNUIuPjmbdzHnmRFJA8r2dkcb8q+OM5Uv5KtnuAttQumnrjcBVBM3mcTX1CkmtAkU58VRZxg==", "dev": true, "license": "MIT", "dependencies": { @@ -1185,14 +1398,14 @@ } }, "node_modules/@inquirer/expand": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.1.1.tgz", - "integrity": "sha512-YmQpenjbFSHAK3sOd44puHh3V1KXXr+JiNpUztoSQ4drLh2rTVzTap/YtlAVu/5xavifIlBfNEzJ/neZJ1a/1g==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.1.5.tgz", + "integrity": "sha512-uHuXLmXW+TtIfT/9vSBotypAkqn1n34Ul+CLGPos/xANyO4Ff5xZzkYhbKR4NEcfVK4a9mHQOpwVZzluSHFRGw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^11.2.1", - "@inquirer/type": "^4.0.7" + "@inquirer/core": "^12.0.3", + "@inquirer/type": "4.1.1" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" @@ -1229,9 +1442,9 @@ } }, "node_modules/@inquirer/figures": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.7.tgz", - "integrity": "sha512-aJ8TBPOGB6f/2qziPfElISTCEd5XOYTFckA2SGjhNmiKzfK/u4ot3v0DUzGVdUnKjN10EqnnEPck36BkyfLnJw==", + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.9.tgz", + "integrity": "sha512-EAWgUTGQ/Umgga51dE3B2PUHbufuXarDfg86uVgoSgNHNNQnyFKcOrQLWVqYMghuSyHh8+2HUH0Js9cTC1WAdg==", "dev": true, "license": "MIT", "engines": { @@ -1239,14 +1452,14 @@ } }, "node_modules/@inquirer/input": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.1.2.tgz", - "integrity": "sha512-9K/DDBSQpOyZSkt6sOVP9Vo0TR7atX2kuILsUu0x3wVcVbe97lJwIJKMLdMw25tDYuXl/qp6erT0Xs1rfmcfZg==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.1.6.tgz", + "integrity": "sha512-HtcJhB2QFVXbLuJ5S3syhNbTUVxYvwqV4VRBDkQceBloC9bmTViUoRFP5PbSaDZb3HzfPmpuU/gG4ybVBz4FHA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^11.2.1", - "@inquirer/type": "^4.0.7" + "@inquirer/core": "^12.0.3", + "@inquirer/type": "4.1.1" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" @@ -1261,14 +1474,14 @@ } }, "node_modules/@inquirer/number": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.1.1.tgz", - "integrity": "sha512-XF4IXAbPnGPgw0wsbC/i2tPcyfdZgDpUlhsqU0SfT4IRIGWha6Xm9VRgN5yYxJq+jnyXlfXI/nQ3ulfk0iEICA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.2.3.tgz", + "integrity": "sha512-6Yuwh1NGSbu1Lo4N1EWjXs1jKRntLg/ZCwhmeorEHde90v1XxAozdbd4Iu30eOQLW+6h1hp2O9ujNfLSbTPJnA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^11.2.1", - "@inquirer/type": "^4.0.7" + "@inquirer/core": "^12.0.3", + "@inquirer/type": "4.1.1" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" @@ -1283,15 +1496,15 @@ } }, "node_modules/@inquirer/password": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.1.1.tgz", - "integrity": "sha512-3XBfF7DAsp5qeDsvN5Rd1HmbNokVvEQoUM0QLrRcybC9nX96w3Pbmu7qUsb3IT3J3jBvs2+mTXaKHOUsgHMLzg==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.2.2.tgz", + "integrity": "sha512-W9zYdyzogK+6110mqwaSJWCBu2yA5Q/OfnGSjjZB1bNpHlmUozXxTl0+QOZBNeVd6Qo81/qT75gW05gLAtITxw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^2.0.7", - "@inquirer/core": "^11.2.1", - "@inquirer/type": "^4.0.7" + "@inquirer/ansi": "^2.0.8", + "@inquirer/core": "^12.0.3", + "@inquirer/type": "4.1.1" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" @@ -1306,22 +1519,22 @@ } }, "node_modules/@inquirer/prompts": { - "version": "8.5.2", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.5.2.tgz", - "integrity": "sha512-IYR/3C/paEVVQYQvdDlFZVjRCJVYHHON0XXMH91KO9GSxs0TdKYWlUdvfQl2EfAHDxUaN3IBffkE/BDTh5nJ6g==", + "version": "8.7.2", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.7.2.tgz", + "integrity": "sha512-QoRB4wFIjgH5iOhSjoIKMkTvSHDuV+O3OITlIqAYO0oK5x364GJILXiMBvlPiE+klg7Xx9tq5XVqQHcGUDYYPA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/checkbox": "^5.2.1", - "@inquirer/confirm": "^6.1.1", - "@inquirer/editor": "^5.2.2", - "@inquirer/expand": "^5.1.1", - "@inquirer/input": "^5.1.2", - "@inquirer/number": "^4.1.1", - "@inquirer/password": "^5.1.1", - "@inquirer/rawlist": "^5.3.1", - "@inquirer/search": "^4.2.1", - "@inquirer/select": "^5.2.1" + "@inquirer/checkbox": "^5.2.5", + "@inquirer/confirm": "^6.3.2", + "@inquirer/editor": "^5.3.3", + "@inquirer/expand": "^5.1.5", + "@inquirer/input": "^5.1.6", + "@inquirer/number": "^4.2.3", + "@inquirer/password": "^5.2.2", + "@inquirer/rawlist": "^5.3.5", + "@inquirer/search": "^4.3.3", + "@inquirer/select": "^5.2.5" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" @@ -1336,14 +1549,14 @@ } }, "node_modules/@inquirer/rawlist": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.3.1.tgz", - "integrity": "sha512-QqdTqQddL3qPX/PPrjobpsO25NZ4dWXgTLenrR445L2ptLEYE6Z+PD5c5CNDJNx4ugRgELAIpSIJxZaO2jJ2Og==", + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.3.5.tgz", + "integrity": "sha512-1oHky1ONfCOwNrnkQGDE1oaSij/3fI6HFMSf2H/WsGO2lEyDX9My82iggITSy9ddSZ8yk8j9v41OI0fVoSIoaA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^11.2.1", - "@inquirer/type": "^4.0.7" + "@inquirer/core": "^12.0.3", + "@inquirer/type": "4.1.1" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" @@ -1358,15 +1571,15 @@ } }, "node_modules/@inquirer/search": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.2.1.tgz", - "integrity": "sha512-xJj8QWKRSrfKoBIITLZK61dD3zwo0Rz11fgDImku30/Oe81zMdIdGgrLY2h6RkJ+KZ/GhNYIRMKnH/62qBTA5g==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.3.3.tgz", + "integrity": "sha512-fyuIU1Nbpvwlikjg3gXwJFDI11+EFjqQ7P+iByfmivIKQ1vmaykNrD/vy5unHuUqUpsOsnvJ25//tPF7E/RBRA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^11.2.1", - "@inquirer/figures": "^2.0.7", - "@inquirer/type": "^4.0.7" + "@inquirer/core": "^12.0.3", + "@inquirer/figures": "^2.0.9", + "@inquirer/type": "4.1.1" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" @@ -1381,16 +1594,16 @@ } }, "node_modules/@inquirer/select": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.2.1.tgz", - "integrity": "sha512-FlDndEUww8m7BfukO2nJa25vhD+H5jxxCv4oGioKqzyWz3nPHhhw4LKdYRSlXuAx7DsdWia7iyaBPKKS95Evfw==", + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.2.5.tgz", + "integrity": "sha512-9kc15hr8r/kI+3DO/xLog5nOzTz1jqsHXa6JBFzmQKhkoJ8Slda1I1L/uD8ZSZ9tF1yp79wwXe7mclvX1rqR2Q==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^2.0.7", - "@inquirer/core": "^11.2.1", - "@inquirer/figures": "^2.0.7", - "@inquirer/type": "^4.0.7" + "@inquirer/ansi": "^2.0.8", + "@inquirer/core": "^12.0.3", + "@inquirer/figures": "^2.0.9", + "@inquirer/type": "4.1.1" }, "engines": { "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" @@ -1405,9 +1618,9 @@ } }, "node_modules/@inquirer/type": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.0.7.tgz", - "integrity": "sha512-t28inv14nMQ1PhKpsJPY+kEs/c00qzeCOS2gTNRyTjG5d6qsVA2fItxW4hkvGZ5lvanGLdtCzVIx5dwdRpN1+g==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.1.1.tgz", + "integrity": "sha512-yJoHYrMnxIsJZCY+0Vb66Dy3he3kL3e2wOBKhoSwWWAzZAY82emlxwgprCtp6yRixvNRNq9ztfRWQYPNr3Go7A==", "dev": true, "license": "MIT", "engines": { @@ -1422,107 +1635,66 @@ } } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "license": "ISC", - "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" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "node_modules/@keyv/bigmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@keyv/bigmap/-/bigmap-1.3.1.tgz", + "integrity": "sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "hashery": "^1.4.0", + "hookified": "^1.15.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", "engines": { - "node": ">=12" + "node": ">= 18" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependencies": { + "keyv": "^5.6.0" } }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "node_modules/@keyv/serialize": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz", + "integrity": "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==", "dev": true, "license": "MIT" }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "license": "MIT", "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 8" } }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": ">= 8" } }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": ">= 8" } }, "node_modules/@octokit/auth-token": { @@ -1536,17 +1708,17 @@ } }, "node_modules/@octokit/core": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.7.tgz", - "integrity": "sha512-DcB0M3KFgr9ECI328lhBMVsyFT2DnmNucSBTqEN3exyNKUzkkpUSCHmTRcunF41Eou2TIQKW4seewri8ON9bSA==", + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.8.tgz", + "integrity": "sha512-L7y8eYc+AwxGr2PWI4WFt1VG4TiJ66c26BD16mXpYIlXxG0SMigM1+m4aTSlYyBr5BlQsGAlz8uDCoZN4SEMcg==", "dev": true, "license": "MIT", "dependencies": { "@octokit/auth-token": "^6.0.0", - "@octokit/graphql": "^9.0.4", - "@octokit/request": "^10.0.13", - "@octokit/request-error": "^7.1.1", - "@octokit/types": "^17.0.0", + "@octokit/graphql": "^9.0.5", + "@octokit/request": "^10.0.16", + "@octokit/request-error": "^7.1.2", + "@octokit/types": "^18.0.0", "before-after-hook": "^4.0.0", "universal-user-agent": "^7.0.0" }, @@ -1555,30 +1727,30 @@ } }, "node_modules/@octokit/core/node_modules/@octokit/openapi-types": { - "version": "28.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-28.0.0.tgz", - "integrity": "sha512-0rFyLuyHvIj6uuZWuDslxkowFYdPXoNIkeAv4b27dzm2Tf4vGWXnPsMcxs7d65kLdMERgP3wc1AEPlqMz8e1cQ==", + "version": "29.0.1", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-29.0.1.tgz", + "integrity": "sha512-9qWOMFNxxLokERcms42rU0PTLqQmVs7g5E41TI4mCOxmpFayD1rfC7XxOL55cG9MBZLFlC31BrR37myMKardwg==", "dev": true, "license": "MIT" }, "node_modules/@octokit/core/node_modules/@octokit/types": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-17.0.0.tgz", - "integrity": "sha512-ByP1v7YL5SMveFPP7+sj0/ZuWCOOg/Chs4NafOMpq6WNIM/hdGY0S7C0TCGDBWu1aGmOxmUIhMx3cO+IdwYZ1Q==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-18.0.0.tgz", + "integrity": "sha512-l6bAF43PNxkJp6g+W4PjoUSSkxHomXw2nOum5CTftJz1NlV3vu93NImgOYtLf6CbBUb5j+fiuzW0PPQ5JTSvZA==", "dev": true, "license": "MIT", "dependencies": { - "@octokit/openapi-types": "^28.0.0" + "@octokit/openapi-types": "^29.0.1" } }, "node_modules/@octokit/endpoint": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.4.tgz", - "integrity": "sha512-f1cOWoHPmxryJFknxbtDdjODWfV8A9tc8Aae6ermXPNgHFZ/x91AtHIz4gicEjL8hkJiip+u21QHJORfBv/qiA==", + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.5.tgz", + "integrity": "sha512-iXa654H3yFafF/ieHkukfbgWo2rmXD2ceD0ZOtrPhw1bc3FDch1d9N/TNs0FQ1/cIbwb7kspUX8jzIs8nzb9DQ==", "dev": true, "license": "MIT", "dependencies": { - "@octokit/types": "^17.0.0", + "@octokit/types": "^18.0.0", "universal-user-agent": "^7.0.2" }, "engines": { @@ -1586,31 +1758,31 @@ } }, "node_modules/@octokit/endpoint/node_modules/@octokit/openapi-types": { - "version": "28.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-28.0.0.tgz", - "integrity": "sha512-0rFyLuyHvIj6uuZWuDslxkowFYdPXoNIkeAv4b27dzm2Tf4vGWXnPsMcxs7d65kLdMERgP3wc1AEPlqMz8e1cQ==", + "version": "29.0.1", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-29.0.1.tgz", + "integrity": "sha512-9qWOMFNxxLokERcms42rU0PTLqQmVs7g5E41TI4mCOxmpFayD1rfC7XxOL55cG9MBZLFlC31BrR37myMKardwg==", "dev": true, "license": "MIT" }, "node_modules/@octokit/endpoint/node_modules/@octokit/types": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-17.0.0.tgz", - "integrity": "sha512-ByP1v7YL5SMveFPP7+sj0/ZuWCOOg/Chs4NafOMpq6WNIM/hdGY0S7C0TCGDBWu1aGmOxmUIhMx3cO+IdwYZ1Q==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-18.0.0.tgz", + "integrity": "sha512-l6bAF43PNxkJp6g+W4PjoUSSkxHomXw2nOum5CTftJz1NlV3vu93NImgOYtLf6CbBUb5j+fiuzW0PPQ5JTSvZA==", "dev": true, "license": "MIT", "dependencies": { - "@octokit/openapi-types": "^28.0.0" + "@octokit/openapi-types": "^29.0.1" } }, "node_modules/@octokit/graphql": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-9.0.4.tgz", - "integrity": "sha512-5s15CCiY8XXQ+FG+b1YQcl6Z2FA++nwAz/tg2VUrTmnMncP+2nnGUEYANImdnxsA2Fnq+Mbl7hDjUTw7cFAwcg==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-9.0.5.tgz", + "integrity": "sha512-bt/hm03LeU6Vy7FwTrkkC9p3XGT/lBwClglMqxBSe5/q0E5CdJTXeAqEI0vlw89/LF/G6tryTIH8HirZ3prMVg==", "dev": true, "license": "MIT", "dependencies": { - "@octokit/request": "^10.0.13", - "@octokit/types": "^17.0.0", + "@octokit/request": "^10.0.16", + "@octokit/types": "^18.0.0", "universal-user-agent": "^7.0.0" }, "engines": { @@ -1618,20 +1790,20 @@ } }, "node_modules/@octokit/graphql/node_modules/@octokit/openapi-types": { - "version": "28.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-28.0.0.tgz", - "integrity": "sha512-0rFyLuyHvIj6uuZWuDslxkowFYdPXoNIkeAv4b27dzm2Tf4vGWXnPsMcxs7d65kLdMERgP3wc1AEPlqMz8e1cQ==", + "version": "29.0.1", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-29.0.1.tgz", + "integrity": "sha512-9qWOMFNxxLokERcms42rU0PTLqQmVs7g5E41TI4mCOxmpFayD1rfC7XxOL55cG9MBZLFlC31BrR37myMKardwg==", "dev": true, "license": "MIT" }, "node_modules/@octokit/graphql/node_modules/@octokit/types": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-17.0.0.tgz", - "integrity": "sha512-ByP1v7YL5SMveFPP7+sj0/ZuWCOOg/Chs4NafOMpq6WNIM/hdGY0S7C0TCGDBWu1aGmOxmUIhMx3cO+IdwYZ1Q==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-18.0.0.tgz", + "integrity": "sha512-l6bAF43PNxkJp6g+W4PjoUSSkxHomXw2nOum5CTftJz1NlV3vu93NImgOYtLf6CbBUb5j+fiuzW0PPQ5JTSvZA==", "dev": true, "license": "MIT", "dependencies": { - "@octokit/openapi-types": "^28.0.0" + "@octokit/openapi-types": "^29.0.1" } }, "node_modules/@octokit/openapi-types": { @@ -1704,17 +1876,17 @@ } }, "node_modules/@octokit/request": { - "version": "10.0.13", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.13.tgz", - "integrity": "sha512-v2269YxL9Yf+x3d+gRI63FP0vFQEiWgLyBzxe/Y+0yFDg2B/Tzf5dhh9VNfccVAQnfcfwQWyk/y6Bn7rUXXs7A==", + "version": "10.0.16", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.16.tgz", + "integrity": "sha512-A0zWGjHzISIb+9ccG8s0dq7LKO5zVpJLRICjgUb+sJxEWqn8RUHB1rD3AE51+PECvXHIxqZ1VVvs4fHTSD9nUQ==", "dev": true, "license": "MIT", "dependencies": { - "@octokit/endpoint": "^11.0.3", - "@octokit/request-error": "^7.1.1", - "@octokit/types": "^17.0.0", - "content-type": "^2.0.0", - "json-with-bigint": "^3.5.3", + "@octokit/endpoint": "^11.0.5", + "@octokit/request-error": "^7.1.2", + "@octokit/types": "^18.0.0", + "content-type": "^3.0.0", + "json-with-bigint": "^3.5.12", "universal-user-agent": "^7.0.2" }, "engines": { @@ -1722,50 +1894,50 @@ } }, "node_modules/@octokit/request-error": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.1.tgz", - "integrity": "sha512-+eaY7G2VVpSf2pc5Gn1+mph837V/d/TYTJAgWL9Tb0ogGYcpN3IlAVFgjL+Vv93F/sevrxkvsYCedtpLdcFLzA==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.1.2.tgz", + "integrity": "sha512-XZRuT3xZ84D3gYErI1DZvhJ33dCWVV6uzBtWkaBB4TvA/L6eOeTZodxLFVB44bBEEo3vEx7y00UfX1tBLrtLRg==", "dev": true, "license": "MIT", "dependencies": { - "@octokit/types": "^17.0.0" + "@octokit/types": "^18.0.0" }, "engines": { "node": ">= 20" } }, "node_modules/@octokit/request-error/node_modules/@octokit/openapi-types": { - "version": "28.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-28.0.0.tgz", - "integrity": "sha512-0rFyLuyHvIj6uuZWuDslxkowFYdPXoNIkeAv4b27dzm2Tf4vGWXnPsMcxs7d65kLdMERgP3wc1AEPlqMz8e1cQ==", + "version": "29.0.1", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-29.0.1.tgz", + "integrity": "sha512-9qWOMFNxxLokERcms42rU0PTLqQmVs7g5E41TI4mCOxmpFayD1rfC7XxOL55cG9MBZLFlC31BrR37myMKardwg==", "dev": true, "license": "MIT" }, "node_modules/@octokit/request-error/node_modules/@octokit/types": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-17.0.0.tgz", - "integrity": "sha512-ByP1v7YL5SMveFPP7+sj0/ZuWCOOg/Chs4NafOMpq6WNIM/hdGY0S7C0TCGDBWu1aGmOxmUIhMx3cO+IdwYZ1Q==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-18.0.0.tgz", + "integrity": "sha512-l6bAF43PNxkJp6g+W4PjoUSSkxHomXw2nOum5CTftJz1NlV3vu93NImgOYtLf6CbBUb5j+fiuzW0PPQ5JTSvZA==", "dev": true, "license": "MIT", "dependencies": { - "@octokit/openapi-types": "^28.0.0" + "@octokit/openapi-types": "^29.0.1" } }, "node_modules/@octokit/request/node_modules/@octokit/openapi-types": { - "version": "28.0.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-28.0.0.tgz", - "integrity": "sha512-0rFyLuyHvIj6uuZWuDslxkowFYdPXoNIkeAv4b27dzm2Tf4vGWXnPsMcxs7d65kLdMERgP3wc1AEPlqMz8e1cQ==", + "version": "29.0.1", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-29.0.1.tgz", + "integrity": "sha512-9qWOMFNxxLokERcms42rU0PTLqQmVs7g5E41TI4mCOxmpFayD1rfC7XxOL55cG9MBZLFlC31BrR37myMKardwg==", "dev": true, "license": "MIT" }, "node_modules/@octokit/request/node_modules/@octokit/types": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-17.0.0.tgz", - "integrity": "sha512-ByP1v7YL5SMveFPP7+sj0/ZuWCOOg/Chs4NafOMpq6WNIM/hdGY0S7C0TCGDBWu1aGmOxmUIhMx3cO+IdwYZ1Q==", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-18.0.0.tgz", + "integrity": "sha512-l6bAF43PNxkJp6g+W4PjoUSSkxHomXw2nOum5CTftJz1NlV3vu93NImgOYtLf6CbBUb5j+fiuzW0PPQ5JTSvZA==", "dev": true, "license": "MIT", "dependencies": { - "@octokit/openapi-types": "^28.0.0" + "@octokit/openapi-types": "^29.0.1" } }, "node_modules/@octokit/rest": { @@ -1824,47 +1996,36 @@ "url": "https://github.com/phun-ky/typeof?sponsor=1" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@release-it/conventional-changelog": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/@release-it/conventional-changelog/-/conventional-changelog-12.0.0.tgz", - "integrity": "sha512-b9N8/tUjO9JNH1u2fVSmq8QmbqnE//Y5iCgvPcytsk0pj0GhgGCp+VmfzhEBIdd+lVGZJKs+ZSaGaOHjtmtv7g==", + "node_modules/@release-it/conventional-changelog": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/@release-it/conventional-changelog/-/conventional-changelog-12.0.2.tgz", + "integrity": "sha512-mJsfycScVqud9O+GzVLT1wQBsIR2WO3kEe6Xm7ucf9yP9KyKRTY9yqoFe/kjLCNSu0lP0PzpuOooUYyzHm1oFw==", "dev": true, "license": "MIT", "dependencies": { - "@conventional-changelog/git-client": "^3.1.0", + "@conventional-changelog/git-client": "^3.1.2", "concat-stream": "^2.0.0", - "conventional-changelog": "^8.1.0", - "conventional-changelog-angular": "^9.2.1", - "conventional-changelog-conventionalcommits": "^10.2.1", + "conventional-changelog": "^8.1.3", + "conventional-changelog-angular": "^9.4.0", + "conventional-changelog-conventionalcommits": "^10.4.0", "conventional-recommended-bump": "^12.1.0", "semver": "^7.8.5" }, "engines": { - "node": "^22.21.0 || >=24.0.0" + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" }, "peerDependencies": { "release-it": "^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0" } }, "node_modules/@release-it/conventional-changelog/node_modules/conventional-changelog-conventionalcommits": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-10.2.1.tgz", - "integrity": "sha512-n4Kr1HFMTf3iMbES0TMxKIcYtUUv4rKqyQQp2JwfOEfFCOfGT3Tq4mCyJ8S9/YPyWhydjfKrrvnyl+gCjA+mJQ==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-10.4.0.tgz", + "integrity": "sha512-Rriac6ZrAlVm6cy9Bz4NSp+WMHpwNXoPIYex+HjCgduAVUSbnew29DQjQw0C4g9u3HtSYzGiGY+pdBXAZo+4aA==", "dev": true, "license": "ISC", "dependencies": { - "@conventional-changelog/template": "^1.2.1" + "@conventional-changelog/template": "^1.4.0" }, "engines": { "node": ">=22" @@ -1929,6 +2090,19 @@ "url": "https://ko-fi.com/dangreen" } }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@types/esrecurse": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", @@ -1954,13 +2128,6 @@ "glob": "*" } }, - "node_modules/@types/js-yaml": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", - "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -1976,13 +2143,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "26.2.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-26.2.0.tgz", - "integrity": "sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==", + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.2.tgz", + "integrity": "sha512-X1P21scMv4zGKLYqjdGjaKa7COa0RKVYYZZN/NfvLQ1JegxFhdhpZG/Lyn8AXx6CDUavKAd11v6BvfpkDByK8g==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~8.3.0" + "undici-types": "~8.9.0" } }, "node_modules/@types/parse-path": { @@ -1999,18 +2166,25 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/vscode-webview": { + "version": "1.57.5", + "resolved": "https://registry.npmjs.org/@types/vscode-webview/-/vscode-webview-1.57.5.tgz", + "integrity": "sha512-iBAUYNYkz+uk1kdsq05fEcoh8gJmwT3lqqFPN7MGyjQ3HVloViMdo7ZJ8DFIP8WOK74PjOEilosqAyxV2iUFUw==", + "dev": true, + "license": "MIT" + }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.67.0.tgz", - "integrity": "sha512-Un7Heoyj65NREbKAyIrFxeM143NZpExWmy1Nep4DLeQOeLlTeumPjoNKnBrU5D5moWXbPJgRa5Uwcdu0faVNGQ==", + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.70.1.tgz", + "integrity": "sha512-nDNrUQ/4ruSNYbu749TRY7cfrzPtoLHEXSNBI8aaNY32LlZCajixqRf3FqcKC4p5Cam4VOHYx/t+i5+nKXvrqA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.67.0", - "@typescript-eslint/type-utils": "8.67.0", - "@typescript-eslint/utils": "8.67.0", - "@typescript-eslint/visitor-keys": "8.67.0", + "@typescript-eslint/scope-manager": "8.70.1", + "@typescript-eslint/type-utils": "8.70.1", + "@typescript-eslint/utils": "8.70.1", + "@typescript-eslint/visitor-keys": "8.70.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -2023,22 +2197,22 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.67.0", + "@typescript-eslint/parser": "^8.70.1", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.67.0.tgz", - "integrity": "sha512-fUBfTuuEulWqX6V8+O3PtScV01tzYYRUDTAirHFKoRAt7nOzoGiPt0M/bB47wWNy0coOOcgEwAMUtBpykMxl6w==", + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.70.1.tgz", + "integrity": "sha512-nO974WLllwhSFWQXnMLj6nDGa8f0khKEz1JzpPJ1u7Vm/4X1X6ZHajpoknU4bb41vJyMB0HHVyS2GqdhWfIXZw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.67.0", - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/typescript-estree": "8.67.0", - "@typescript-eslint/visitor-keys": "8.67.0", + "@typescript-eslint/scope-manager": "8.70.1", + "@typescript-eslint/types": "8.70.1", + "@typescript-eslint/typescript-estree": "8.70.1", + "@typescript-eslint/visitor-keys": "8.70.1", "debug": "^4.4.3" }, "engines": { @@ -2054,14 +2228,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.67.0.tgz", - "integrity": "sha512-cvE8c7ulYeXN9fYuszhCeCsbzyVEXuhrRCybnBre7TUmqb5nRmBfQAwCj0O3WJFDeyAZt4VYv51vMCC9LHSdYw==", + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.70.1.tgz", + "integrity": "sha512-62xOgboPfwc3/IgPSX/W6oQR3ZbF04194FPGUGH8HL8iLFHbt/456/8Ph1wLNUgVF+s94FlHoipBsz+v7+LMnA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.67.0", - "@typescript-eslint/types": "^8.67.0", + "@typescript-eslint/tsconfig-utils": "^8.70.1", + "@typescript-eslint/types": "^8.70.1", "debug": "^4.4.3" }, "engines": { @@ -2076,14 +2250,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.67.0.tgz", - "integrity": "sha512-EgvsleTwS4E+WzzSvem8fAUubLwatMNF1B5hHSLQxcvs7q2dtRhGyujHwLJSYlG41niJ7GP24Aha2+0mb1b2kg==", + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.70.1.tgz", + "integrity": "sha512-Pa0EeSeAusQc1WbjQMac+YfenewYTBu0KjgYvkUKwhXaHUKbFog23Dm/rp0DX/6tyYOQ3Xl1a+3EcFNZynGHCw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/visitor-keys": "8.67.0" + "@typescript-eslint/types": "8.70.1", + "@typescript-eslint/visitor-keys": "8.70.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2094,9 +2268,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.67.0.tgz", - "integrity": "sha512-vV+LUSv5njUWsknE71fqKTlXUva+R76SaeORd6Zojcunk/6DvKFXONU3BrAs2H49mbygUXt6gbYunzwqNwlhdg==", + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.70.1.tgz", + "integrity": "sha512-jumze1fPI+sDOaM2TWGQdn39PDxTr7TZGeuyLkAbNyx2vtMT3uRnVKChN0hfht5V2TugphJzF6bYXvBcE09qqg==", "dev": true, "license": "MIT", "engines": { @@ -2111,15 +2285,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.67.0.tgz", - "integrity": "sha512-aVWDXbRmdXO9siTfX4ditQI1T9+zVcNazT48EJCD0v40/9RIFoUgZ05CmGEq9H2gixRpjUn/iplwvlcvutJW/Q==", + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.70.1.tgz", + "integrity": "sha512-7zKTnyvaVWqzLZHPFQtX1hVHqgkMC+WebPWakNCSyrQVbIP1AM0L0TlBZtACldIRb6PptI8Odk+jyZ5kP3B1VA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/typescript-estree": "8.67.0", - "@typescript-eslint/utils": "8.67.0", + "@typescript-eslint/types": "8.70.1", + "@typescript-eslint/typescript-estree": "8.70.1", + "@typescript-eslint/utils": "8.70.1", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -2136,9 +2310,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.67.0.tgz", - "integrity": "sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==", + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.70.1.tgz", + "integrity": "sha512-Dm1ypdhhrGCTyyehxElhgJ6kgk8MVCv5qXdoOVqPr1uqk42jX8KjrZqhROvdShczA8qrDoYiOWn1ykWlx2k81Q==", "dev": true, "license": "MIT", "engines": { @@ -2150,16 +2324,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.67.0.tgz", - "integrity": "sha512-EKQBCE9yNlRJYm7jdTW5AhDacDUmSwQb0FAJAmK2EKYrNXIsa2vxcSZx6PvJ/dEdI6lS+Y9W+EXckLj0iPFGcw==", + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.70.1.tgz", + "integrity": "sha512-TU8PwyGN0PQJUcE96mw8eCQ44SmxGdQlJmlWakHaHQ15eIuuvye5yNtmh/i6oS88jzXVQB71xdNkbkB/fMwL0g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.67.0", - "@typescript-eslint/tsconfig-utils": "8.67.0", - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/visitor-keys": "8.67.0", + "@typescript-eslint/project-service": "8.70.1", + "@typescript-eslint/tsconfig-utils": "8.70.1", + "@typescript-eslint/types": "8.70.1", + "@typescript-eslint/visitor-keys": "8.70.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -2178,16 +2352,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.67.0.tgz", - "integrity": "sha512-U9D1FdwEWBwok3hxxSdhclMb0twvt9QnjIQ0VfQ1AiX2epnpSgv2ubVDsayOFyY8K6FX+AQ7E0FKWVG3iKsj1A==", + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.70.1.tgz", + "integrity": "sha512-Esgul8MsnKnRLdYU2Eb2cRV9bS5HJYtKj1ByJnOzzG2M58DGdSUQ1jUuILxipqcpB2h9WLrbD5GijIWUjX/Tqw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.67.0", - "@typescript-eslint/types": "8.67.0", - "@typescript-eslint/typescript-estree": "8.67.0" + "@typescript-eslint/scope-manager": "8.70.1", + "@typescript-eslint/types": "8.70.1", + "@typescript-eslint/typescript-estree": "8.70.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2202,13 +2376,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.67.0.tgz", - "integrity": "sha512-fkv8dHRDqfGtTHuJeebdrQ7cX6Ad4WAS00rgHh9UGvMycF1mjBfsxry1XsLIFhWZ6Judlh6UdzK+TYlbpCXgnA==", + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.70.1.tgz", + "integrity": "sha512-Vwj9lUIW5Xq3wQ9w6gv3R86g1hMK8f2zNOdGTAgeXUMMXFK78G9ruCjjqutHMNJc0+CH7LYRnHeUB9IT8wFmcw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.67.0", + "@typescript-eslint/types": "8.70.1", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -2440,6 +2614,16 @@ "node": ">=4" } }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/async-function": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", @@ -2755,34 +2939,31 @@ } } }, - "node_modules/c12/node_modules/chokidar": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", - "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "node_modules/c12/node_modules/dotenv": { + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", + "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", "dev": true, - "license": "MIT", - "dependencies": { - "readdirp": "^5.0.0" - }, + "license": "BSD-2-Clause", "engines": { - "node": ">= 20.19.0" + "node": ">=12" }, "funding": { - "url": "https://paulmillr.com/funding/" + "url": "https://dotenvx.com" } }, - "node_modules/c12/node_modules/readdirp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", - "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "node_modules/cacheable": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-2.5.0.tgz", + "integrity": "sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" + "dependencies": { + "@cacheable/memory": "^2.2.0", + "@cacheable/utils": "^2.5.0", + "hookified": "^1.15.0", + "keyv": "^5.6.0", + "qified": "^0.10.1" } }, "node_modules/cachedir": { @@ -2891,16 +3072,16 @@ "license": "MIT" }, "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", "dev": true, "license": "MIT", "dependencies": { - "readdirp": "^4.0.1" + "readdirp": "^5.0.0" }, "engines": { - "node": ">= 14.16.0" + "node": ">= 20.19.0" }, "funding": { "url": "https://paulmillr.com/funding/" @@ -3098,6 +3279,13 @@ "dev": true, "license": "MIT" }, + "node_modules/colord": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.10.0.tgz", + "integrity": "sha512-AidJptpBJmjTclAp9BkLwJi0T93fo5epJnbaZslpg6QVzpHjAiveF55mE9AcUJiGMqRHgMDY8soMsQtuNYMHfw==", + "dev": true, + "license": "MIT" + }, "node_modules/commitizen": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.3.2.tgz", @@ -3224,13 +3412,13 @@ "license": "MIT" }, "node_modules/content-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", - "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-3.0.0.tgz", + "integrity": "sha512-AIi5H6p0xk5uknXcN3/rmhP8jgp69OfSe/JuKiQAFprJ7UGw7mwj7m4XcmDzlrnJDG+cGpphAINGdU3g3g7kDw==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" + "node": ">=22" }, "funding": { "type": "opencollective", @@ -3238,19 +3426,20 @@ } }, "node_modules/conventional-changelog": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-8.1.0.tgz", - "integrity": "sha512-idt1JK+3+Nt7gqH/d/sEYWdDeR+5XPov/jssmFN6XxmYSRlonTWSDWhWUPkmm0zbwYjtVdt+4My5aiPkKyvocw==", + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-8.1.3.tgz", + "integrity": "sha512-fOMwLCxm46znJKPB08jLxl1FD8SOZOQHktlzCVhvhhVUfq0KgQSryoYXsRRHs1aRlZPR1/QK5wztnY8sBNC2AA==", "dev": true, "license": "MIT", "dependencies": { - "@conventional-changelog/git-client": "^3.1.0", + "@conventional-changelog/git-client": "^3.1.2", "@simple-libs/hosted-git-info": "^2.0.0", "@simple-libs/normalize-package-data": "^1.0.0", "argue-cli": "^3.1.0", "conventional-changelog-preset-loader": "^6.0.1", - "conventional-changelog-writer": "^9.2.0", - "conventional-commits-parser": "^7.1.0", + "conventional-changelog-writer": "^9.2.1", + "conventional-commits-filter": "^6.0.1", + "conventional-commits-parser": "^7.1.2", "fd-package-json": "^2.0.0" }, "bin": { @@ -3261,13 +3450,13 @@ } }, "node_modules/conventional-changelog-angular": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-9.2.1.tgz", - "integrity": "sha512-oWSL6ZhnXbYraOFTK3PgRAQJ8fADDAEv5K6AdeyQPLvjFmhG8+ejL0jZZp/R7vTmGJaBvZEE+sE7dB4bCv7sAw==", + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-9.4.0.tgz", + "integrity": "sha512-HdxRxuS8bBXVIuo4V82gvSwAXT0vYQUizrjs/izmPg5JdDstr8v8I5hduGL3iQbG+o310dUDxC4+LetuS5hu9w==", "dev": true, "license": "ISC", "dependencies": { - "@conventional-changelog/template": "^1.2.1" + "@conventional-changelog/template": "^1.4.0" }, "engines": { "node": ">=22" @@ -3297,13 +3486,13 @@ } }, "node_modules/conventional-changelog-writer": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-9.2.0.tgz", - "integrity": "sha512-eACD5BaAQCYjeI3RExkCZopNaaIuXzCP4kaAb2lEFXcGa/KOuxJfj8v/SnjhvF6377pYn0A2Gji+6GhwUK8rEA==", + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-9.2.1.tgz", + "integrity": "sha512-StlYSmW3wLedRaqohJMpP3YuWiAqtgD0/cpsai9frdDkXv7rxj0hRbpJrubPYvJxJsjplONsOobEQnPuS9UgCg==", "dev": true, "license": "MIT", "dependencies": { - "@conventional-changelog/template": "^1.2.1", + "@conventional-changelog/template": "^1.3.0", "@simple-libs/stream-utils": "^2.0.0", "argue-cli": "^3.1.0", "conventional-commits-filter": "^6.0.1", @@ -3334,9 +3523,9 @@ } }, "node_modules/conventional-commits-parser": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-7.1.1.tgz", - "integrity": "sha512-B0f42jI++V5Vb7qK+DDw68r0dNxz5hk+RdKUkx2NOi39emc9hsHa3u2M3doF7QQhRFzCrAj7uM90teG+RBTaYQ==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-7.1.2.tgz", + "integrity": "sha512-O+x4N2yH+ijvqWlIyTHsXTAP+algNWgGbjY2duCe8w2vUMvUB95cLRslCPfTMQyLAKlet3bhZTdu6ozn4M+QJQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3378,9 +3567,9 @@ "license": "MIT" }, "node_modules/cosmiconfig": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", - "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.2.tgz", + "integrity": "sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==", "dev": true, "license": "MIT", "dependencies": { @@ -3423,9 +3612,9 @@ } }, "node_modules/cosmiconfig/node_modules/js-yaml": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", - "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", "dev": true, "funding": [ { @@ -3460,6 +3649,43 @@ "node": ">= 8" } }, + "node_modules/css-functions-list": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.3.3.tgz", + "integrity": "sha512-8HFEBPKhOpJPEPu70wJJetjKta86Gw9+CCyCnB3sui2qQfOvRyqBy4IKLKKAwdMpWb2lHXWk9Wb4Z6AmaUT1Pg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/cz-conventional-changelog": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-3.3.0.tgz", @@ -3482,15 +3708,18 @@ } }, "node_modules/cz-emoji-conventional": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/cz-emoji-conventional/-/cz-emoji-conventional-1.2.1.tgz", - "integrity": "sha512-ge1bnmUlRjQKCck65yqjPc2/dBtI9cBBE3e/j/2XkFVGXX94xQM7q9bD9a0NlKf9RvMb7oRGZwi86zgxkY3ujQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/cz-emoji-conventional/-/cz-emoji-conventional-1.3.0.tgz", + "integrity": "sha512-77Poz4EMKWNeNryvdGgfj8rOK6K90NiwIIh9EGJykjVeeGBlNVXAWWUXCHKO6XDORX2jx0a96jIVt/UNXziZvg==", "dev": true, "license": "ISC", "dependencies": { "chalk": "4.1.2", - "commitizen": "^4.3.0", - "word-wrap": "^1.2.3" + "commitizen": "^4.3.2", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">=18" } }, "node_modules/cz-emoji-conventional/node_modules/ansi-styles": { @@ -3661,19 +3890,6 @@ } } }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", @@ -3689,9 +3905,9 @@ "license": "MIT" }, "node_modules/default-browser": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", - "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.1.tgz", + "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==", "dev": true, "license": "MIT", "dependencies": { @@ -3833,9 +4049,9 @@ } }, "node_modules/diff": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", - "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-9.0.0.tgz", + "integrity": "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -3856,11 +4072,14 @@ } }, "node_modules/dotenv": { - "version": "17.4.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", - "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", + "version": "18.0.4", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-18.0.4.tgz", + "integrity": "sha512-jGt9uI5BIxpVO15kvy+iEFqNAwxYClKWnkptLjSNPnFLC003Imd0ofr3aEVsbpHdSBdSsbcApNIlz4nbyGMwdA==", "dev": true, "license": "BSD-2-Clause", + "bin": { + "dotenv": "dist/index.cjs" + }, "engines": { "node": ">=12" }, @@ -3883,13 +4102,6 @@ "node": ">= 0.4" } }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, - "license": "MIT" - }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -4054,15 +4266,16 @@ } }, "node_modules/es-toolkit": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.50.0.tgz", - "integrity": "sha512-OyZKhUVvEep9ITEiwHn8GKnMRQIVqoSIX7WnRbkWgJkllCujilqP2rD0u979tkl8wqyc8ICwlc1UBVv/Sl1G6w==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.52.0.tgz", + "integrity": "sha512-XTNEJQh1tY1ZJVcf6ayP/2n4ZPyaHlW2FWs7xvw5ddPuhUVjLD3olQVQS7kf58JbAB48iL0uL/jerTrjtV3lDA==", "dev": true, "license": "MIT", "workspaces": [ "docs", "benchmarks", - "tests/types" + "tests/types", + "tests/browser-compat" ] }, "node_modules/esbuild": { @@ -4150,9 +4363,9 @@ } }, "node_modules/eslint": { - "version": "10.8.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.8.1.tgz", - "integrity": "sha512-wqA7W2jbsC/BnV9Iv1UZpKVFkO1AdNoSmYW8NWG4HNOBbkAMvIqDZ27pI2f07dqn583NcIC44ckjAcOXDL1QbQ==", + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.11.0.tgz", + "integrity": "sha512-P7a6UEEqb9G95MYAtqkmsTbVXIYyzIfl6NGOIJk162PaahFxFyeGcrlXYFSiagECg4sEm8IseJdZBKR3rx6MsQ==", "dev": true, "license": "MIT", "workspaces": [ @@ -4164,7 +4377,7 @@ "@eslint/config-array": "^0.23.5", "@eslint/config-helpers": "^0.7.0", "@eslint/core": "^1.2.1", - "@eslint/plugin-kit": "^0.7.2", + "@eslint/plugin-kit": "^0.7.3", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -4179,7 +4392,7 @@ "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", + "file-entry-cache": "11.1.5 || >11.1.6 <12", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", @@ -4208,6 +4421,118 @@ } } }, + "node_modules/eslint-formatter-gha": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/eslint-formatter-gha/-/eslint-formatter-gha-2.0.1.tgz", + "integrity": "sha512-HbiPXXjIley/JRcQ9zRZ4HJhhU8ZIf0wVLbfyQKm/7HIcbvOsA2xwl/Lblyd8fhYalUWxKcodJOwsOwxw7O0Cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-formatter-json": "^9.0.0", + "eslint-formatter-stylish": "^9.0.0" + } + }, + "node_modules/eslint-formatter-json": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/eslint-formatter-json/-/eslint-formatter-json-9.0.1.tgz", + "integrity": "sha512-EQ/X+bPjiOUDo4frNbkY+5R6emaHTL7t2jHsJw5s8p8w1BTJ6ao6S7g/PaRyx/CqqaYcjJkWAPHH/onNyFlJBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/eslint-formatter-stylish": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/eslint-formatter-stylish/-/eslint-formatter-stylish-9.0.1.tgz", + "integrity": "sha512-FlhMRUiDUHztGj+bhm3pYo5DJ6Gbjh/FGPClcDENme7f9+Sc3+HZg6wMq80KJmRD8/oj/Ib6gy4D/ppjmHfGVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/eslint-formatter-stylish/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint-formatter-stylish/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint-formatter-stylish/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint-formatter-stylish/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint-formatter-stylish/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint-formatter-stylish/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/eslint-scope": { "version": "9.1.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", @@ -4431,6 +4756,36 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -4463,9 +4818,9 @@ } }, "node_modules/fast-uri": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", - "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", + "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", "dev": true, "funding": [ { @@ -4489,6 +4844,26 @@ "fast-string-width": "^3.0.2" } }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.3.tgz", + "integrity": "sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/fd-package-json": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fd-package-json/-/fd-package-json-2.0.0.tgz", @@ -4516,16 +4891,13 @@ } }, "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "version": "11.1.5", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-11.1.5.tgz", + "integrity": "sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q==", "dev": true, "license": "MIT", "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" + "flat-cache": "^6.1.23" } }, "node_modules/fill-range": { @@ -4576,6 +4948,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/find-up-simple": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", + "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/findup-sync": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", @@ -4592,34 +4977,22 @@ "node": ">= 8" } }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "license": "BSD-3-Clause", - "bin": { - "flat": "cli.js" - } - }, "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "version": "6.1.23", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.23.tgz", + "integrity": "sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==", "dev": true, "license": "MIT", "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" + "cacheable": "^2.5.0", + "flatted": "^3.4.2", + "hookified": "^1.15.0" } }, "node_modules/flatted": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", - "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", + "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", "dev": true, "license": "ISC" }, @@ -4639,36 +5012,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "dev": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -4984,9 +5327,9 @@ } }, "node_modules/globals": { - "version": "17.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.11.0.tgz", - "integrity": "sha512-Z2I8hM+PbJDXQDq3Icgpzv+mPdwr68iZUU9d5WW4FuXfDUQfkZaZuvjMv42/5crNyw154+9+VWXbYrUgDXbxNw==", + "version": "17.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.12.0.tgz", + "integrity": "sha512-cezEd/DTyyht9cvSSURyygXPfy04GtWO/5e6ZPvH7fCtjKz9PYOmuawphw1Ctd1f6C+5JypXfGD7ahNMXvevBA==", "dev": true, "license": "MIT", "engines": { @@ -5013,6 +5356,35 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/globby": { + "version": "16.2.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-16.2.4.tgz", + "integrity": "sha512-c8B/VNLmxRcmqqenRA9t+9IyOjf9+V6lTxPaUJLqOCONdQkWZ0ETYgX0qbtJqPsgCNusT9MZ5Jeidw8Eb9tn2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.5", + "is-path-inside": "^4.0.0", + "micromatch": "^4.0.8", + "slash": "^5.1.0", + "unicorn-magic": "^0.4.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globjoin": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", + "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==", + "dev": true, + "license": "MIT" + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -5114,6 +5486,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hashery": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/hashery/-/hashery-1.5.1.tgz", + "integrity": "sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "hookified": "^1.15.0" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/hasown": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", @@ -5127,16 +5512,6 @@ "node": ">= 0.4" } }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "license": "MIT", - "bin": { - "he": "bin/he" - } - }, "node_modules/homedir-polyfill": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", @@ -5150,6 +5525,26 @@ "node": ">=0.10.0" } }, + "node_modules/hookified": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.15.1.tgz", + "integrity": "sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/html-tags": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-5.1.0.tgz", + "integrity": "sha512-n6l5uca7/y5joxZ3LUePhzmBFUJ+U2YWzhMa8XUTecSeSlQiZdF5XAd/Q3/WUl0VsXgUwWi8I7CNIwdI5WN1SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/http-proxy-agent": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", @@ -5233,9 +5628,9 @@ "license": "BSD-3-Clause" }, "node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.9.tgz", + "integrity": "sha512-brTTsvFRt5C1gGHtPst/281UjPD5t9fBqbgoMPlVWy11ZLTPfu7HxK4ZYqO9H7o/yC9rSTCI85EaQ4OoY12qYw==", "dev": true, "license": "MIT", "engines": { @@ -5276,6 +5671,17 @@ "node": ">=4" } }, + "node_modules/import-meta-resolve": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -5483,9 +5889,9 @@ } }, "node_modules/ip-address": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.3.1.tgz", - "integrity": "sha512-1e9d3kb97NHJTIJDZW9rKqW2h6+dFa50Dy0fpPSMQp2ADje5gvKsXmdiK6dwY5t76TaTt5+P5N1Y/LoToIxP6g==", + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.3.tgz", + "integrity": "sha512-A1kdq/tSb5QjvKvAMgIoEvDBIgL7qaqVP/jkvSwYYRZ9iEzvPpopxp2wQfu3SuZRHtpHNxMn8Fs0bS+gf5Xmwg==", "dev": true, "license": "MIT", "engines": { @@ -5847,13 +6253,16 @@ } }, "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-plain-obj": { @@ -6101,22 +6510,6 @@ "node": "^18.17 || >=20.6.1" } }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, "node_modules/jiti": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", @@ -6135,9 +6528,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.3.0.tgz", - "integrity": "sha512-muutsYr+e2+d3rTgUGslq5rxbBlUy3cJ61IsHag2QNDQV+7zXWjkUpmALIajhrlLlrgRUiymj6U3zUr/TMK84Q==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.4.2.tgz", + "integrity": "sha512-m+aqu+LwO1O6sIopafj8HUVl5aawITwZQe/yHpMCKjaWBaA/d07B/QdMb3529REftiU+RMMHL3Vlsw3hON7vWg==", "dev": true, "funding": [ { @@ -6157,13 +6550,6 @@ "js-yaml": "bin/js-yaml.mjs" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, "node_modules/json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -6193,9 +6579,9 @@ "license": "MIT" }, "node_modules/json-with-bigint": { - "version": "3.5.10", - "resolved": "https://registry.npmjs.org/json-with-bigint/-/json-with-bigint-3.5.10.tgz", - "integrity": "sha512-Vcx+JVNEBts/xfcoCS69sKrOhOk/3TVlvlT+XzUOefVKnnrbYSCKpDCm10pohsJFtsJVYnwa/cXRZ4eElzaM6w==", + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/json-with-bigint/-/json-with-bigint-3.5.12.tgz", + "integrity": "sha512-uwbF/wSSuOgC7qqlq27Xp5B6a2MHVug3t0idZdTqu0JnlFvgJuH7ju+KAk/J06C7GfhoYy2gnb9wz2INqcne7w==", "dev": true, "license": "MIT" }, @@ -6266,13 +6652,23 @@ } }, "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", + "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", "dev": true, "license": "MIT", "dependencies": { - "json-buffer": "3.0.1" + "@keyv/serialize": "^1.1.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, "node_modules/levn": { @@ -6411,6 +6807,13 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.uniqby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", @@ -6521,13 +6924,6 @@ "node": ">=0.10.0" } }, - "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, "node_modules/macos-release": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-3.4.0.tgz", @@ -6551,6 +6947,24 @@ "node": ">= 0.4" } }, + "node_modules/mathml-tag-names": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-4.0.0.tgz", + "integrity": "sha512-aa6AU2Pcx0VP/XWnh8IGL0SYSgQHDT6Ucror2j2mXeFAlN3ahaNs8EZtG1YiticMkSLj3Gt6VPFfZogt7G5iFQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true, + "license": "CC0-1.0" + }, "node_modules/memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", @@ -6560,6 +6974,19 @@ "node": ">= 0.10.0" } }, + "node_modules/meow": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-14.1.0.tgz", + "integrity": "sha512-EDYo6VlmtnumlcBCbh1gLJ//9jvM/ndXHfVXIFrZVr6fGcwTUyCTFNTLCKuY3ffbK8L/+3Mzqnd58RojiZqHVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/merge": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/merge/-/merge-2.1.1.tgz", @@ -6567,6 +6994,16 @@ "dev": true, "license": "MIT" }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -6668,228 +7105,112 @@ } }, "node_modules/mocha": { - "version": "11.8.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.8.0.tgz", - "integrity": "sha512-VyCeUdGN3A9lmCTTgG4yuvY9ixxaDk+xt2R/7/+1AP6EqNG+G9OKkzBwhVtVYoNX8YsxNSgAl8mOv3IAeOpFbw==", + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-12.0.2.tgz", + "integrity": "sha512-SjAulGHxlMJLCD1bhvJBAiYwYxglydRzA9PDQ5MALq1oLRMMtIhxSQJ0olCFgA7c9YbTdxC0KOV0wl8JEDYVhA==", "dev": true, "license": "MIT", "dependencies": { "browser-stdout": "^1.3.1", - "chokidar": "^4.0.1", + "chokidar": "^5.0.0", "debug": "^4.3.5", - "diff": "^7.0.0", - "escape-string-regexp": "^4.0.0", - "find-up": "^5.0.0", - "glob": "^10.4.5", - "he": "^1.2.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "log-symbols": "^4.1.0", - "minimatch": "^9.0.5", + "diff": "^9.0.0", + "find-up-simple": "^1.0.1", + "glob": "^13.0.0", + "is-path-inside": "^4.0.0", + "is-unicode-supported": "^0.1.0", + "js-yaml": "^5.0.0", + "minimatch": "^10.2.2", "ms": "^2.1.3", "picocolors": "^1.1.1", - "serialize-javascript": "^6.0.2", - "strip-json-comments": "^3.1.1", + "serialize-javascript": "^7.1.1", + "strip-json-comments": "^5.0.3", "supports-color": "^8.1.1", - "workerpool": "^9.2.0", - "yargs": "^17.7.2", - "yargs-parser": "^21.1.1", - "yargs-unparser": "^2.0.0" + "workerpool": "^10.0.0" }, "bin": { - "_mocha": "bin/_mocha", "mocha": "bin/mocha.js" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/mocha/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", - "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", + "node_modules/mocha/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/mocha/node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/mocha/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "node_modules/mocha/node_modules/strip-json-comments": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz", + "integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==", "dev": true, "license": "MIT", "engines": { - "node": ">=10" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mocha/node_modules/glob": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, - "license": "ISC", + "license": "MIT", "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" }, - "bin": { - "glob": "dist/esm/bin.mjs" + "engines": { + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/mocha/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/mocha/node_modules/js-yaml": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", - "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true, + "license": "ISC" + }, + "node_modules/nanoid": { + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", "dev": true, "funding": [ { "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/nodeca" + "url": "https://github.com/sponsors/ai" } ], "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.2" + "nanoid": "bin/nanoid.cjs" }, "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/mocha/node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/mocha/node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true, - "license": "ISC" - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true, "license": "MIT" }, @@ -6939,6 +7260,16 @@ "dev": true, "license": "MIT" }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/npm-run-all": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", @@ -7147,18 +7478,18 @@ } }, "node_modules/open": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz", - "integrity": "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==", + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/open/-/open-11.0.4.tgz", + "integrity": "sha512-++Zlftm0kVLPmzC06t6epuWmcRMDbI4z5P3NNX979WA/k23+NtSOynEGzsVfZwguKw2mi5umVgnBlJQMwRz4Pg==", "dev": true, "license": "MIT", "dependencies": { - "default-browser": "^5.4.0", + "default-browser": "^5.5.1", "define-lazy-prop": "^3.0.0", "is-in-ssh": "^1.0.0", "is-inside-container": "^1.0.0", - "powershell-utils": "^0.1.0", - "wsl-utils": "^0.3.0" + "powershell-utils": "^0.2.1", + "wsl-utils": "^1.0.0" }, "engines": { "node": ">=20" @@ -7525,13 +7856,6 @@ "quickjs-wasi": "^2.2.0" } }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true, - "license": "BlueOak-1.0.0" - }, "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -7761,10 +8085,87 @@ "node": ">= 0.4" } }, + "node_modules/postcss": { + "version": "8.5.28", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz", + "integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.18", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-safe-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.1.0.tgz", + "integrity": "sha512-1WzZxRLaAFwEh6Do+zyGpjWV3nGJNxxhuh7Ubu/q1ICImMgZJnLwhoaEpRbG4pJppp2Y1ncL9ffA2f+LhrefQg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-selector-parser": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.6.tgz", + "integrity": "sha512-7qASPzhKF2l2KLboRZux8CCTRMdGiV08vWmyKzPz22qZ7ZjQBOeY7rNzNoCLSUiftJ7HUq0GERHmxw/t0dCdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, "node_modules/powershell-utils": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", - "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.2.1.tgz", + "integrity": "sha512-C+y9x90UElAddDZmV4qOx9W53B61PO7cIqWz2dQsWlwswuq4mr8NEwytdGKboYbQlGZ3awrkTeNvcZiZNHnQ8A==", "dev": true, "license": "MIT", "engines": { @@ -7906,6 +8307,47 @@ "node": ">=6" } }, + "node_modules/qified": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/qified/-/qified-0.10.1.tgz", + "integrity": "sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hookified": "^2.1.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/qified/node_modules/hookified": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-2.2.0.tgz", + "integrity": "sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==", + "dev": true, + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/quickjs-wasi": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/quickjs-wasi/-/quickjs-wasi-2.2.0.tgz", @@ -7913,16 +8355,6 @@ "dev": true, "license": "MIT" }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, "node_modules/rc9": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/rc9/-/rc9-3.0.1.tgz", @@ -7995,13 +8427,13 @@ } }, "node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", + "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", "dev": true, "license": "MIT", "engines": { - "node": ">= 14.18.0" + "node": ">= 20.19.0" }, "funding": { "type": "individual", @@ -8053,9 +8485,9 @@ } }, "node_modules/release-it": { - "version": "21.0.2", - "resolved": "https://registry.npmjs.org/release-it/-/release-it-21.0.2.tgz", - "integrity": "sha512-QwyDnWiQNB4d8Hc2b5FLMHcsKz9S2O1dMNnPB7w+0knsL5r8+qbnznDA1X7Bw5D863+Ud7eRHc71Cfth5Tlrgg==", + "version": "21.1.0", + "resolved": "https://registry.npmjs.org/release-it/-/release-it-21.1.0.tgz", + "integrity": "sha512-jR179wu8Z9BKfhd0wVmUmzjshCnezUkULdHW5rSCjKTXApdr6mAJjw/R339uXS43mLCz6iAFO6ffS27+N1dy8A==", "dev": true, "funding": [ { @@ -8069,7 +8501,7 @@ ], "license": "MIT", "dependencies": { - "@inquirer/prompts": "8.5.2", + "@inquirer/prompts": "8.7.2", "@octokit/rest": "22.0.1", "@phun-ky/typeof": "2.0.3", "async-retry": "1.3.3", @@ -8082,21 +8514,21 @@ "lodash.merge": "4.6.2", "mime-types": "3.0.2", "new-github-release-url": "2.0.0", - "open": "11.0.0", + "open": "11.0.4", "ora": "9.4.1", "os-name": "7.0.0", "proxy-agent": "8.0.2", - "semver": "7.8.5", "tinyglobby": "0.2.17", "undici": "7.29.0", "url-join": "5.0.0", + "verkit": "0.4.0", "wildcard-match": "5.1.4" }, "bin": { "release-it": "bin/release-it.js" }, "engines": { - "node": "^22.21.0 || >=24.0.0" + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" } }, "node_modules/release-it/node_modules/ansi-regex": { @@ -8299,16 +8731,6 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -8389,6 +8811,17 @@ "node": ">= 4" } }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/right-pad": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/right-pad/-/right-pad-1.1.1.tgz", @@ -8423,6 +8856,30 @@ "node": ">=0.12.0" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/rxjs": { "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", @@ -8530,13 +8987,13 @@ } }, "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.1.1.tgz", + "integrity": "sha512-k3CMsaIvvdSwm8oLB4MXSl0wH2/cwlH7xGcnRd2DaeRmBkbzYmyT8j0tsX60DwD1eRwHTpNpH8ljKu9oUT1MeQ==", "dev": true, "license": "BSD-3-Clause", - "dependencies": { - "randombytes": "^2.1.0" + "engines": { + "node": ">=20.0.0" } }, "node_modules/set-function-length": { @@ -8714,6 +9171,73 @@ "dev": true, "license": "ISC" }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -8776,6 +9300,16 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -8864,22 +9398,6 @@ "node": ">=8" } }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/string.prototype.padend": { "version": "3.1.6", "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz", @@ -8971,20 +9489,6 @@ "node": ">=8" } }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -9008,6 +9512,209 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/stylelint": { + "version": "17.15.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-17.15.0.tgz", + "integrity": "sha512-mWIkesYQvQjf4Kvdeu9ns0IL8/K/wtjaGxPqsPd6DlLZvaQxGysJsocxUDrBcyHQ5VleAk4uSMat4yMrVED7PA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + }, + { + "type": "github", + "url": "https://github.com/sponsors/stylelint" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^3.3.0", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-syntax-patches-for-csstree": "^1.1.9", + "@csstools/css-tokenizer": "^4.0.0", + "@csstools/media-query-list-parser": "^5.0.0", + "@csstools/selector-resolve-nested": "^4.0.1", + "@csstools/selector-specificity": "^6.0.0", + "colord": "^2.10.0", + "cosmiconfig": "^9.0.2", + "css-functions-list": "^3.3.3", + "css-tree": "^3.2.1", + "debug": "^4.4.3", + "fast-glob": "^3.3.3", + "fastest-levenshtein": "^1.0.16", + "file-entry-cache": "^11.1.5", + "global-modules": "^2.0.0", + "globby": "^16.2.4", + "globjoin": "^0.1.4", + "html-tags": "^5.1.0", + "ignore": "^7.0.6", + "import-meta-resolve": "^4.2.0", + "mathml-tag-names": "^4.0.0", + "meow": "^14.1.0", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.5.26", + "postcss-safe-parser": "^7.0.1", + "postcss-selector-parser": "^7.1.5", + "postcss-value-parser": "^4.2.0", + "string-width": "^8.2.2", + "supports-hyperlinks": "^4.5.0", + "svg-tags": "^1.0.0", + "table": "^6.9.0", + "write-file-atomic": "^7.0.1" + }, + "bin": { + "stylelint": "bin/stylelint.mjs" + }, + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/stylelint-config-recommended": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-18.0.0.tgz", + "integrity": "sha512-mxgT2XY6YZ3HWWe3Di8umG6aBmWmHTblTgu/f10rqFXnyWxjKWwNdjSWkgkwCtxIKnqjSJzvFmPT5yabVIRxZg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + }, + { + "type": "github", + "url": "https://github.com/sponsors/stylelint" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "stylelint": "^17.0.0" + } + }, + "node_modules/stylelint-config-standard": { + "version": "40.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-40.0.0.tgz", + "integrity": "sha512-EznGJxOUhtWck2r6dJpbgAdPATIzvpLdK9+i5qPd4Lx70es66TkBPljSg4wN3Qnc6c4h2n+WbUrUynQ3fanjHw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + }, + { + "type": "github", + "url": "https://github.com/sponsors/stylelint" + } + ], + "license": "MIT", + "dependencies": { + "stylelint-config-recommended": "^18.0.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "stylelint": "^17.0.0" + } + }, + "node_modules/stylelint/node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/stylelint/node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/stylelint/node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/stylelint/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/stylelint/node_modules/string-width": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.2.tgz", + "integrity": "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stylelint/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/stylelint/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -9021,6 +9728,49 @@ "node": ">=4" } }, + "node_modules/supports-hyperlinks": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-4.5.0.tgz", + "integrity": "sha512-ZW2OvfeCXrNTbLakPUzjQG922EeGCOteFSVoek5DKStTh898wf7zgtuFlzQN8HfZCxC3Eh02yJVrRW51hADf+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^5.0.1", + "supports-color": "^10.2.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" + } + }, + "node_modules/supports-hyperlinks/node_modules/has-flag": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-5.0.1.tgz", + "integrity": "sha512-CsNUt5x9LUdx6hnk/E2SZLsDyvfqANZSUq4+D3D8RzDJ2M+HDTIkF60ibS1vHaK55vzgiZw1bEPFG9yH7l33wA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-hyperlinks/node_modules/supports-color": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", + "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -9034,6 +9784,36 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", + "dev": true + }, + "node_modules/table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", @@ -9042,9 +9822,9 @@ "license": "MIT" }, "node_modules/tinyexec": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.2.tgz", - "integrity": "sha512-M/Q0B2cp4K7kynaT/vnED1j8TlLY+Pp7C6Wl2bl/7u/F0mUVwdyOpwomQb8JpYLitHUssAJRmLZdMCGsrx7i+g==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.1.tgz", + "integrity": "sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==", "dev": true, "license": "MIT", "engines": { @@ -9133,9 +9913,9 @@ "license": "0BSD" }, "node_modules/tsx": { - "version": "4.23.12", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.12.tgz", - "integrity": "sha512-FDf4L4sYzKtzWYhU/Xm0AQFdTjdIxNo9ElTf2mxXM6k8YMHXzYUe4yODVaXP4V9uMFbVg8c0qyBccK2OOxb45Q==", + "version": "4.23.15", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.15.tgz", + "integrity": "sha512-Yiex1Ovn8z2xPpOWckIiysV1SSyRMY9BkLF++q0yKiDxCqRhosKfMg3janKkiLBwZ5c/YryloKwGZcrEmtwxKw==", "dev": true, "license": "MIT", "dependencies": { @@ -9277,16 +10057,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.67.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.67.0.tgz", - "integrity": "sha512-S2udFs8tCKEKffuJ4TB1idGUZiXdCPGi3IPBGWXarbLQ5UPXORV8QEVzJ4gCRduURMb5EkpNCdjbk0eDIuI8Yg==", + "version": "8.70.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.70.1.tgz", + "integrity": "sha512-AcWG7KDjZ2THNXsgwttMaGmzVi0VFRlFYfqFHYQRbDpF3owuYbuiL8c7UUrd2k8s3PoSfIQrWfrGXfcElrWLYA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.67.0", - "@typescript-eslint/parser": "8.67.0", - "@typescript-eslint/typescript-estree": "8.67.0", - "@typescript-eslint/utils": "8.67.0" + "@typescript-eslint/eslint-plugin": "8.70.1", + "@typescript-eslint/parser": "8.70.1", + "@typescript-eslint/typescript-estree": "8.70.1", + "@typescript-eslint/utils": "8.70.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -9330,12 +10110,25 @@ } }, "node_modules/undici-types": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", - "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.9.0.tgz", + "integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==", "dev": true, "license": "MIT" }, + "node_modules/unicorn-magic": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.0.tgz", + "integrity": "sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/universal-user-agent": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", @@ -9391,6 +10184,19 @@ "spdx-expression-parse": "^3.0.0" } }, + "node_modules/verkit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/verkit/-/verkit-0.4.0.tgz", + "integrity": "sha512-sXMwN6DMHeouPfCxkxWkKAmxphWKEenHYY5H1nIBzU3PmDsmJp6kBXJdshjVdpMZuWCmL9SH7KFRx29AylpP6g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, "node_modules/walk-up-path": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-4.0.0.tgz", @@ -9552,19 +10358,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/windows-release/node_modules/powershell-utils": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.2.0.tgz", - "integrity": "sha512-ZlsFlG7MtSFCoc5xreOvBAozCJ6Pf06opgJjh9ONEv418xpZSAzNjstD36C6+JwOnfSqOW/9uDkqKjezTdxZhw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -9576,9 +10369,9 @@ } }, "node_modules/workerpool": { - "version": "9.3.4", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz", - "integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==", + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-10.0.3.tgz", + "integrity": "sha512-6z2Iis68Wqth93/G/wJP9u+R3O+d2XTlgWChGCwuT1qLbBsOYueGRZuJ++v3mtDP5KjYdy+WzvWC+VWETSVXJA==", "dev": true, "license": "Apache-2.0" }, @@ -9600,61 +10393,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -9698,10 +10436,36 @@ "dev": true, "license": "ISC" }, + "node_modules/write-file-atomic": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-7.0.1.tgz", + "integrity": "sha512-OTIk8iR8/aCRWBqvxrzxR0hgxWpnYBblY1S5hDWBQfk/VFmJwzmJgQFN3WsoUKHISv2eAwe+PpbUzyL1CKTLXg==", + "dev": true, + "license": "ISC", + "dependencies": { + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/wsl-utils": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.1.tgz", - "integrity": "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-1.0.0.tgz", + "integrity": "sha512-Hl0ZOAs672vg+06kfujwRhoS6/jehvULrlFkuF2dRu6pHgA8U06h3xqNIqNNU1LTXPcedxByAR4GS6pwQK0mgA==", "dev": true, "license": "MIT", "dependencies": { @@ -9715,6 +10479,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/wsl-utils/node_modules/powershell-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", + "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -9743,42 +10520,6 @@ "node": "^20.19.0 || ^22.12.0 || >=23" } }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser/node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/yargs/node_modules/ansi-regex": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", diff --git a/package.json b/package.json index 874904a9..a1d374b2 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "gitlab-component-helper", "displayName": "GitLab Component Helper", "description": "Provides intellisense for GitLab CI components", - "version": "0.16.12", + "version": "0.17.21", "icon": "images/icon.png", "engines": { "node": ">=22.0.0", @@ -213,6 +213,14 @@ ], "default": "warning", "description": "Severity of the 'newer component version available' diagnostic." + }, + "gitlabComponentHelper.versionPreferences": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "default": {}, + "markdownDescription": "Version that completion and the Component Browser offer for a component, keyed by `//`, for example `gitlab.com/components/opentofu/full-pipeline`. The value is a version, or `~latest` for the highest stable version available when you insert. Set from the Component Browser by right-clicking a version dropdown and choosing **Set as Default Version** or **Always Use Latest**." } } }, @@ -280,8 +288,13 @@ "watch:esbuild": "node esbuild.js --watch", "watch:tsc": "tsc --noEmit --watch --project tsconfig.json", "package": "npm run check-types && node esbuild.js --production", - "check-types": "tsc --noEmit && tsc --noEmit --project tsconfig.tests.json", - "lint": "eslint --max-warnings 0", + "check-types": "tsc --noEmit && tsc --noEmit --project tsconfig.tests.json && tsc --noEmit --project src/webview/client", + "lint": "npm-run-all -c lint:eslint lint:stylelint", + "lint:eslint": "eslint --max-warnings 0", + "lint:stylelint": "stylelint \"src/webview/**/*.css\"", + "lint:ci": "npm-run-all -c lint:ci:*", + "lint:ci:eslint": "eslint --max-warnings 0 --format gha", + "lint:ci:stylelint": "stylelint \"src/webview/**/*.css\" --custom-formatter @csstools/stylelint-formatter-github", "pretest": "npm run compile", "prepare": "husky", "test": "mocha", @@ -304,41 +317,45 @@ "commitizen": "commitizen init cz-conventional-changelog --save-dev --save-exact --force" }, "devDependencies": { - "@commitlint/cli": "^21.2.2", + "@commitlint/cli": "^21.2.3", "@commitlint/config-conventional": "^21.0.2", + "@csstools/stylelint-formatter-github": "^2.0.0", "@digitalroute/cz-conventional-changelog-for-jira": "^8.0.1", "@eslint/js": "^10.0.1", - "@octokit/core": "^7.0.7", + "@octokit/core": "^7.0.8", "@octokit/plugin-paginate-rest": "^15.0.0", - "@release-it/conventional-changelog": "^12.0.0", + "@release-it/conventional-changelog": "^12.0.2", "@types/glob": "^9.0.0", - "@types/js-yaml": "^4.0.9", "@types/mocha": "^10.0.10", - "@types/node": "^26.2.0", + "@types/node": "^26.6.2", "@types/vscode": "^1.120.0", - "@typescript-eslint/eslint-plugin": "^8.67.0", - "@typescript-eslint/parser": "^8.67.0", + "@types/vscode-webview": "^1.57.5", + "@typescript-eslint/eslint-plugin": "^8.70.1", + "@typescript-eslint/parser": "^8.70.1", "@vscode/test-electron": "^3.1.0", "commitizen": "^4.3.2", "conventional-changelog-conventionalcommits": "^9.3.1", "cz-conventional-changelog": "^3.3.0", - "cz-emoji-conventional": "^1.1.0", + "cz-emoji-conventional": "^1.3.0", "dateformat": "^5.0.3", - "dotenv": "^17.4.2", + "dotenv": "^18.0.3", "esbuild": "^0.28.2", - "eslint": "^10.8.1", - "globals": "^17.11.0", + "eslint": "^10.11.0", + "eslint-formatter-gha": "^2.0.1", + "globals": "^17.12.0", "husky": "^9.1.6", "is-ci": "^4.0.0", - "js-yaml": "^5.3.0", + "js-yaml": "^5.4.2", "minimatch": "^10.2.6", - "mocha": "^11.8.0", + "mocha": "^12.0.2", "npm-run-all": "^4.1.5", - "release-it": "^21.0.2", + "release-it": "^21.1.0", "semver": "^7.8.5", - "tsx": "^4.23.12", + "stylelint": "^17.15.0", + "stylelint-config-standard": "^40.0.0", + "tsx": "^4.23.15", "typescript": "^6.0.3", - "typescript-eslint": "^8.67.0" + "typescript-eslint": "^8.70.1" }, "keywords": [], "author": "eFAILution", diff --git a/scripts/demo-gifs/fixtures/settings.json b/scripts/demo-gifs/fixtures/settings.json new file mode 100644 index 00000000..367dbe2d --- /dev/null +++ b/scripts/demo-gifs/fixtures/settings.json @@ -0,0 +1,59 @@ +{ + "workbench.startupEditor": "none", + "workbench.tips.enabled": false, + "workbench.colorTheme": "Dark Modern", + "editor.minimap.enabled": false, + "editor.fontSize": 15, + "editor.lineHeight": 24, + "editor.hover.delay": 300, + "editor.stickyScroll.enabled": false, + "editor.renderWhitespace": "none", + "telemetry.telemetryLevel": "off", + "update.mode": "none", + "extensions.autoCheckUpdates": false, + "extensions.autoUpdate": "off", + "extensions.ignoreRecommendations": true, + "workbench.enableExperiments": false, + "chat.disableAIFeatures": true, + "security.workspace.trust.enabled": false, + "git.enabled": false, + "breadcrumbs.enabled": false, + "window.commandCenter": false, + "workbench.layoutControl.enabled": false, + "window.restoreWindows": "none", + "files.autoSave": "off", + "workbench.secondarySideBar.defaultVisibility": "hidden", + "gitlabComponentHelper.logLevel": "ERROR", + "gitlabComponentHelper.componentSources": [ + { + "name": "OpenTofu", + "path": "components/opentofu", + "gitlabInstance": "gitlab.com" + }, + { + "name": "SAST", + "path": "components/sast", + "gitlabInstance": "gitlab.com" + }, + { + "name": "Secret Detection", + "path": "components/secret-detection", + "gitlabInstance": "gitlab.com" + }, + { + "name": "Code Quality", + "path": "components/code-quality", + "gitlabInstance": "gitlab.com" + } + ], + "workbench.statusBar.visible": true, + "editor.quickSuggestions": { + "other": true, + "comments": false, + "strings": true + }, + "redhat.telemetry.enabled": false, + "yaml.schemaStore.enable": false, + "window.dialogStyle": "custom", + "editor.wordBasedSuggestions": "off" +} diff --git a/scripts/demo-gifs/fixtures/templates/deploy.yml b/scripts/demo-gifs/fixtures/templates/deploy.yml new file mode 100644 index 00000000..9a0648c5 --- /dev/null +++ b/scripts/demo-gifs/fixtures/templates/deploy.yml @@ -0,0 +1,16 @@ +spec: + inputs: + environment: + description: Where to deploy. + options: [staging, production] + app_name: + description: Name of the app to deploy. + replicas: + type: number + default: 2 + description: How many pods to run. +--- +deploy-$[[ inputs.environment ]]: + stage: deploy + script: + - ./deploy.sh "$[[ inputs.app_name ]]" "$[[ inputs.environment ]]" "$[[ inputs.replicas ]]" diff --git a/scripts/demo-gifs/lib/config.mjs b/scripts/demo-gifs/lib/config.mjs new file mode 100644 index 00000000..1230a81b --- /dev/null +++ b/scripts/demo-gifs/lib/config.mjs @@ -0,0 +1,38 @@ +import os from 'node:os'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +export const DEMO_DIR = path.dirname(path.dirname(fileURLToPath(import.meta.url))); +export const REPO_ROOT = path.resolve(DEMO_DIR, '../..'); +export const FIXTURES_DIR = path.join(DEMO_DIR, 'fixtures'); +export const OUT_DIR = path.join(DEMO_DIR, 'out'); + +const WORK_DIR_PREFIX = 'gch-demo'; + +/** The work dir is wiped on every run, so only accept a folder whose own name marks it as ours. */ +function resolveWorkDir(requested) { + const dir = path.resolve(requested); + const isOurs = path.basename(dir).startsWith(WORK_DIR_PREFIX); + const holdsSomethingPrecious = [os.homedir(), REPO_ROOT].some((p) => !path.relative(dir, p).startsWith('..')); + if (!isOurs || holdsSomethingPrecious) { + throw new Error(`GCH_DEMO_DIR must be a throwaway folder named ${WORK_DIR_PREFIX}*, got ${dir}`); + } + return dir; +} + +// VS Code's IPC socket lives in the profile and its path must stay under ~103 characters, so keep this short. +export const WORK_DIR = resolveWorkDir(process.env.GCH_DEMO_DIR ?? '/tmp/gch-demo'); +export const PROFILE_DIR = path.join(WORK_DIR, 'profile'); +export const EXTENSIONS_DIR = path.join(WORK_DIR, 'extensions'); +// The folder name shows in the window title, so it doubles as the demo's project name. +export const WORKSPACE_DIR = path.join(WORK_DIR, 'my-pipelines'); +export const FRAMES_DIR = path.join(WORK_DIR, 'frames'); +export const VSIX_PATH = path.join(WORK_DIR, 'extension.vsix'); + +const VSCODE_APP = '/Applications/Visual Studio Code.app/Contents'; +export const VSCODE_BIN = process.env.VSCODE_BIN ?? `${VSCODE_APP}/MacOS/Code`; +export const VSCODE_CLI = process.env.VSCODE_CLI ?? `${VSCODE_APP}/Resources/app/bin/code`; + +export const VIEWPORT = { width: 1280, height: 800 }; +export const DEVICE_SCALE = 2; +export const GIF = { width: 1100, fps: 12, colors: 192 }; diff --git a/scripts/demo-gifs/lib/input.mjs b/scripts/demo-gifs/lib/input.mjs new file mode 100644 index 00000000..fd7b2650 --- /dev/null +++ b/scripts/demo-gifs/lib/input.mjs @@ -0,0 +1,86 @@ +// Mouse, keyboard, and a drawn cursor. The screencast doesn't capture the OS pointer, so the scripts draw their own +// in the top document (above the webview iframes) and move it in step with Playwright's synthetic mouse. +import { VIEWPORT } from './config.mjs'; +import { sleep } from './vscode.mjs'; + +const CURSOR_ID = 'demo-cursor'; +const CURSOR_SVG = ""; +const FRAME_MS = 16; +const TOP_SAFE_PX = 90; + +let cursor = { x: VIEWPORT.width / 2, y: VIEWPORT.height / 2 }; + +export async function showCursor(page, x, y) { + await page.evaluate(({ id, svg, x, y }) => { + document.getElementById(id)?.remove(); + const el = document.createElement('div'); + el.id = id; + el.style.cssText = `position:fixed;left:0;top:0;width:22px;height:28px;z-index:2147483647;pointer-events:none;transform:translate(${x}px,${y}px);background:url("data:image/svg+xml;utf8,${encodeURIComponent(svg)}") no-repeat`; + document.body.appendChild(el); + }, { id: CURSOR_ID, svg: CURSOR_SVG, x, y }); + await page.mouse.move(x, y); + cursor = { x, y }; +} + +const easeInOut = (t) => (t < 0.5 ? 2 * t * t : 1 - (-2 * t + 2) ** 2 / 2); + +export async function moveTo(page, x, y, ms = 500) { + const steps = Math.max(8, Math.round(ms / FRAME_MS)); + const from = cursor; + for (let i = 1; i <= steps; i++) { + const e = easeInOut(i / steps); + const point = { x: from.x + (x - from.x) * e, y: from.y + (y - from.y) * e }; + await page.evaluate(({ id, point }) => { + const el = document.getElementById(id); + if (el) el.style.transform = `translate(${point.x}px,${point.y}px)`; + }, { id: CURSOR_ID, point }); + await page.mouse.move(point.x, point.y); + await sleep(ms / steps); + } + cursor = { x, y }; +} + +export async function centerOf(locator) { + const box = await locator.boundingBox(); + if (!box) throw new Error('Element has no bounding box'); + return { x: box.x + box.width / 2, y: box.y + box.height / 2 }; +} + +export async function clickOn(page, locator, { ms = 600, pause = 250 } = {}) { + const { x, y } = await centerOf(locator); + await moveTo(page, x, y, ms); + await sleep(pause); + await page.mouse.click(x, y); +} + +/** Middle of `word` on the first editor line containing `lineText`. */ +export async function wordPosition(page, lineText, word) { + const line = page.locator('.view-line', { hasText: lineText }).first(); + return centerOf(line.locator('span span', { hasText: word }).first()); +} + +/** Type with a little jitter so it reads as a person typing. */ +export async function typeSlow(page, text, delay = 70) { + for (const ch of text) { + await (ch === '\n' ? page.keyboard.press('Enter') : page.keyboard.type(ch)); + await sleep(delay + Math.random() * 30); + } +} + +export async function wheel(page, deltaY, { steps = 10, ms = 600 } = {}) { + for (let i = 0; i < steps; i++) { + await page.mouse.wheel(0, deltaY / steps); + await sleep(ms / steps); + } +} + +/** Scroll the pane under `x` with the wheel until `locator` is on screen, the way a person would. */ +export async function scrollIntoView(page, locator, x, { margin = 40 } = {}) { + const MAX_SCROLLS = 12; + for (let i = 0; i < MAX_SCROLLS; i++) { + const box = await locator.boundingBox(); + if (box && box.y > TOP_SAFE_PX && box.y + box.height < VIEWPORT.height - margin) return; + await moveTo(page, x, VIEWPORT.height / 2, 250); + await wheel(page, box && box.y < TOP_SAFE_PX ? -200 : 200, { steps: 6, ms: 300 }); + } +} diff --git a/scripts/demo-gifs/lib/recorder.mjs b/scripts/demo-gifs/lib/recorder.mjs new file mode 100644 index 00000000..61f2e6fc --- /dev/null +++ b/scripts/demo-gifs/lib/recorder.mjs @@ -0,0 +1,71 @@ +// Captures the workbench with CDP screencast frames, then encodes them to a GIF with ffmpeg. +import fs from 'node:fs'; +import path from 'node:path'; +import { execFileSync } from 'node:child_process'; +import { DEVICE_SCALE, FRAMES_DIR, GIF, OUT_DIR, VIEWPORT } from './config.mjs'; +import { sleep } from './vscode.mjs'; + +const JPEG_QUALITY = 95; +const SHEET_COLUMNS = 6; +const SHEET_TILE_WIDTH = 400; + +export class Recorder { + constructor(cdp, name) { + this.cdp = cdp; + this.name = name; + this.dir = path.join(FRAMES_DIR, name); + this.frames = []; + this.onFrame = (event) => this.saveFrame(event); + } + + async saveFrame({ data, metadata, sessionId }) { + const file = path.join(this.dir, `${String(this.frames.length).padStart(5, '0')}.jpg`); + fs.writeFileSync(file, Buffer.from(data, 'base64')); + this.frames.push({ file, time: metadata.timestamp }); + await this.cdp.send('Page.screencastFrameAck', { sessionId }).catch(() => {}); + } + + async start() { + fs.rmSync(this.dir, { recursive: true, force: true }); + fs.mkdirSync(this.dir, { recursive: true }); + this.cdp.on('Page.screencastFrame', this.onFrame); + await this.cdp.send('Page.startScreencast', { + format: 'jpeg', quality: JPEG_QUALITY, + maxWidth: VIEWPORT.width * DEVICE_SCALE, maxHeight: VIEWPORT.height * DEVICE_SCALE, + }); + } + + /** Stop and write an ffmpeg concat list. Frames only arrive on change, so each frame lasts until the next one. */ + async stop(holdSeconds = 2) { + await this.cdp.send('Page.stopScreencast'); + this.cdp.off('Page.screencastFrame', this.onFrame); + await sleep(300); + const entries = this.frames.map((frame, i) => { + const next = this.frames[i + 1]?.time ?? frame.time + holdSeconds; + return `file '${frame.file}'\nduration ${Math.max(0.01, next - frame.time).toFixed(3)}`; + }); + // The concat demuxer ignores the last duration unless the final file is listed again. + fs.writeFileSync(path.join(this.dir, 'concat.txt'), [...entries, `file '${this.frames.at(-1).file}'`].join('\n') + '\n'); + return this.frames.at(-1).time + holdSeconds - this.frames[0].time; + } +} + +export function encodeGif(name) { + fs.mkdirSync(OUT_DIR, { recursive: true }); + const output = path.join(OUT_DIR, `${name}.gif`); + const filters = `fps=${GIF.fps},scale=${GIF.width}:-1:flags=lanczos,split[a][b];` + + `[a]palettegen=max_colors=${GIF.colors}:stats_mode=diff[p];[b][p]paletteuse=dither=sierra2_4a:diff_mode=rectangle`; + execFileSync('ffmpeg', ['-y', '-loglevel', 'error', '-f', 'concat', '-safe', '0', + '-i', path.join(FRAMES_DIR, name, 'concat.txt'), '-vf', filters, '-loop', '0', output]); + return output; +} + +/** One frame per second, tiled, so a person can check every moment for private details before publishing. */ +export function writeReviewSheet(name, durationSeconds) { + const rows = Math.ceil(durationSeconds / SHEET_COLUMNS); + const output = path.join(OUT_DIR, `${name}-review.png`); + execFileSync('ffmpeg', ['-y', '-loglevel', 'error', '-i', path.join(OUT_DIR, `${name}.gif`), + '-vf', `fps=1,scale=${SHEET_TILE_WIDTH}:-1,tile=${SHEET_COLUMNS}x${rows}:padding=4:color=white`, + '-frames:v', '1', output]); + return output; +} diff --git a/scripts/demo-gifs/lib/vscode.mjs b/scripts/demo-gifs/lib/vscode.mjs new file mode 100644 index 00000000..618cdbf7 --- /dev/null +++ b/scripts/demo-gifs/lib/vscode.mjs @@ -0,0 +1,135 @@ +// Launches VS Code with a debug port and drives the workbench through Playwright over CDP. +import fs from 'node:fs'; +import path from 'node:path'; +import { spawn } from 'node:child_process'; +import { chromium } from 'playwright-core'; +import { DEVICE_SCALE, EXTENSIONS_DIR, PROFILE_DIR, VIEWPORT, VSCODE_BIN, WORKSPACE_DIR } from './config.mjs'; +import { writeWorkspaceFile } from './workspace.mjs'; + +export const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); + +const POLL_MS = 250; +const LAUNCH_ATTEMPTS = 120; + +async function poll(attempt, attempts = LAUNCH_ATTEMPTS) { + for (let i = 0; i < attempts; i++) { + const result = await attempt().catch(() => undefined); + if (result) return result; + await sleep(POLL_MS); + } + return undefined; +} + +/** Port 0 lets Chromium pick a free port and write it here, so we always attach to the copy we just started. */ +async function readDebugPort() { + const file = path.join(PROFILE_DIR, 'DevToolsActivePort'); + return poll(async () => Number(fs.readFileSync(file, 'utf8').split('\n')[0]) || undefined); +} + +async function attach(child) { + const port = await readDebugPort(); + if (!port) throw new Error('VS Code never wrote DevToolsActivePort'); + const browser = await poll(() => chromium.connectOverCDP(`http://127.0.0.1:${port}`)); + if (!browser) throw new Error(`VS Code never answered on debug port ${port}`); + const page = await poll(async () => browser.contexts().flatMap((c) => c.pages()).find((p) => p.url().includes('workbench'))); + if (!page) throw new Error('VS Code workbench window not found'); + await page.waitForSelector('.monaco-workbench', { timeout: 30000 }); + const cdp = await page.context().newCDPSession(page); + // Emulating the viewport (instead of resizing the window) keeps every recording the same size on any screen. + await cdp.send('Emulation.setDeviceMetricsOverride', { ...VIEWPORT, deviceScaleFactor: DEVICE_SCALE, mobile: false }); + await sleep(800); + return { browser, page, cdp, child }; +} + +export async function launchVsCode() { + const child = spawn(VSCODE_BIN, [ + '--remote-debugging-port=0', `--user-data-dir=${PROFILE_DIR}`, `--extensions-dir=${EXTENSIONS_DIR}`, + '--disable-workspace-trust', '--skip-welcome', '--skip-release-notes', '--new-window', WORKSPACE_DIR, + ], { stdio: 'ignore' }); + try { + return await attach(child); + } catch (error) { + child.kill('SIGKILL'); + throw error; + } +} + +export async function stopVsCode({ browser, child }) { + await browser.close().catch(() => {}); + // SIGKILL because a modal dialog can make VS Code ignore SIGTERM. The profile is throwaway. + child.kill('SIGKILL'); + await sleep(1000); +} + +const focusedPaletteLabel = (page) => + page.evaluate(() => document.querySelector('.quick-input-list .monaco-list-row.focused')?.getAttribute('aria-label') ?? ''); + +/** Run a Command Palette entry, refusing to press Enter until the exact command is highlighted. */ +export async function runCommand(page, name, { typeText } = {}) { + await page.keyboard.press('Meta+Shift+P'); + await sleep(400); + await (typeText ? typeText(name) : page.keyboard.type(name, { delay: 8 })); + const matches = async () => (await focusedPaletteLabel(page)).toLowerCase().startsWith(name.toLowerCase()); + if (!(await poll(matches, 20))) { + await page.keyboard.press('Escape'); + throw new Error(`Command Palette did not highlight "${name}"`); + } + await page.keyboard.press('Enter'); +} + +const isVisible = (page, selector) => page.evaluate((sel) => { + const el = document.querySelector(sel); + return !!el && el.offsetWidth > 0 && el.offsetHeight > 0; +}, selector); + +/** Only toggle commands exist for some parts, so check visibility first to make the result deterministic. */ +async function hidePart(page, selector, commandName) { + if (!(await isVisible(page, selector))) return; + await runCommand(page, commandName); + await sleep(400); +} + +async function closeEverything(page) { + const MAX_EDITORS = 6; + for (let i = 0; i < MAX_EDITORS; i++) { + const closed = await runCommand(page, 'View: Revert and Close Editor').then(() => true, () => false); + if (!closed) break; + await sleep(300); + } + await runCommand(page, 'View: Close All Editors'); + await sleep(500); + await page.keyboard.press('Escape'); +} + +export async function openFile(page, relativePath) { + await page.keyboard.press('Meta+P'); + await sleep(300); + await page.keyboard.type(relativePath, { delay: 5 }); + await sleep(600); + await page.keyboard.press('Enter'); + await sleep(800); +} + +/** Start each scene from a clean editor: no open tabs, no side bars or panel, one freshly written file. */ +export async function prepareScene(page, { file = '.gitlab-ci.yml', content, cursorAtEnd = true }) { + await closeEverything(page); + await hidePart(page, '.part.sidebar', 'View: Toggle Primary Side Bar Visibility'); + await hidePart(page, '.part.auxiliarybar', 'View: Hide Secondary Side Bar'); + await hidePart(page, '.part.panel', 'View: Toggle Panel Visibility'); + writeWorkspaceFile(file, content); + await openFile(page, file); + if (cursorAtEnd) await page.keyboard.press('Meta+ArrowDown'); + await sleep(2500); +} + +/** Webviews are out-of-process iframes; return the newest live one that contains `selector`. */ +export async function webviewFrame(page, selector) { + const find = async () => { + const live = page.frames().filter((f) => f.url().includes('fake.html') && !f.isDetached()); + const counts = await Promise.all(live.map((f) => f.locator(selector).count().catch(() => 0))); + return live.filter((_, i) => counts[i] > 0).at(-1); + }; + const frame = await poll(find, 80); + if (!frame) throw new Error(`No webview contains ${selector}`); + return frame; +} diff --git a/scripts/demo-gifs/lib/workspace.mjs b/scripts/demo-gifs/lib/workspace.mjs new file mode 100644 index 00000000..6c0c54c9 --- /dev/null +++ b/scripts/demo-gifs/lib/workspace.mjs @@ -0,0 +1,35 @@ +// Builds the throwaway VS Code profile and demo workspace. Nothing here touches the user's own VS Code setup. +import fs from 'node:fs'; +import path from 'node:path'; +import { execFileSync } from 'node:child_process'; +import { + DEMO_DIR, EXTENSIONS_DIR, FIXTURES_DIR, PROFILE_DIR, REPO_ROOT, VSCODE_CLI, VSIX_PATH, WORK_DIR, WORKSPACE_DIR, +} from './config.mjs'; + +export function resetWorkDir() { + fs.rmSync(WORK_DIR, { recursive: true, force: true }); + fs.mkdirSync(path.join(PROFILE_DIR, 'User'), { recursive: true }); + fs.mkdirSync(EXTENSIONS_DIR, { recursive: true }); + fs.mkdirSync(WORKSPACE_DIR, { recursive: true }); + fs.copyFileSync(path.join(FIXTURES_DIR, 'settings.json'), path.join(PROFILE_DIR, 'User', 'settings.json')); + fs.cpSync(path.join(FIXTURES_DIR, 'templates'), path.join(WORKSPACE_DIR, 'templates'), { recursive: true }); +} + +/** Package the extension as Marketplace users get it, so the window title has no "[Extension Development Host]". */ +export function installExtension() { + const vsce = path.join(DEMO_DIR, 'node_modules', '.bin', 'vsce'); + execFileSync(vsce, ['package', '--no-dependencies', '-o', VSIX_PATH], { cwd: REPO_ROOT, stdio: 'inherit' }); + execFileSync(VSCODE_CLI, [ + `--user-data-dir=${PROFILE_DIR}`, `--extensions-dir=${EXTENSIONS_DIR}`, '--install-extension', VSIX_PATH, + ], { stdio: 'inherit' }); +} + +export function readFixtureSettings() { + return JSON.parse(fs.readFileSync(path.join(FIXTURES_DIR, 'settings.json'), 'utf8')); +} + +export function writeWorkspaceFile(relativePath, content) { + const target = path.join(WORKSPACE_DIR, relativePath); + fs.mkdirSync(path.dirname(target), { recursive: true }); + fs.writeFileSync(target, content); +} diff --git a/scripts/demo-gifs/package-lock.json b/scripts/demo-gifs/package-lock.json new file mode 100644 index 00000000..cab5251d --- /dev/null +++ b/scripts/demo-gifs/package-lock.json @@ -0,0 +1,1705 @@ +{ + "name": "gitlab-component-helper-demo-gifs", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "gitlab-component-helper-demo-gifs", + "dependencies": { + "@vscode/vsce": "4.0.0", + "playwright-core": "1.55.0" + } + }, + "node_modules/@azure/abort-controller": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.2.0.tgz", + "integrity": "sha512-fNAjWnA/nZ2jz31kxR/AqRaUT8ewHBw/WuBIosK0moMy1C9e5ValbDfFdIxJzVOOYaYkV/b2F1S4H/aHiqfVQg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-auth": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.11.0.tgz", + "integrity": "sha512-IUZydyTUkDnYdstOW9pFOOUQlBjAepK5teihDE3x6yxsPJs/hsAaaYpeGxdxrgtOiJbBKSjKW7MDk7AEhb4LRg==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-util": "^1.13.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-client": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.11.1.tgz", + "integrity": "sha512-2QygG2F76ZpMP2eMztiJvAiFMu71M9rDeU7vO/QKg5Css7MgM4frUOslFjhVjRhbGaCNPtz/S8M6y46/fFKVuQ==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-rest-pipeline": "^1.22.0", + "@azure/core-tracing": "^1.3.0", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-process": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@azure/core-process/-/core-process-1.0.0.tgz", + "integrity": "sha512-/shnJ+ooO8WPxDhPEeI/2oRQuubn16gZ6CvlbpWbEswZfzwI9tI/sMAHmF3x1LuQ9yZYXfLW3TjzGMLEC5blKg==", + "license": "MIT", + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline": { + "version": "1.25.0", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.25.0.tgz", + "integrity": "sha512-bMs8ekJLjX8wPV+9IPBges1SLPyuDtE9g5gLDWOpxzKcoOFQnpLGkbcT1tdw3FaAmDS1gnPmMmJ6y/T5B96kIA==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-tracing": "^1.3.0", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", + "@typespec/ts-http-runtime": "^0.3.4", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-tracing": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.4.0.tgz", + "integrity": "sha512-eGwxD0AtncrxeBM4tG8R55Pc3rdX1hNW2WibJAgYpCVA6E93mvvVH+LcssoVjOBrSKWS55yEIHsk0X8ctHmfOQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-util": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.14.0.tgz", + "integrity": "sha512-9n2pWK61veAuN0V20t9lOuoV4CFMdyAZ1ygZzvBGk/pBBJRib/PjL9PLXa/aI2CcPpyHfqVsxxqLCYl6uZlfDw==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/identity": { + "version": "4.13.3", + "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.13.3.tgz", + "integrity": "sha512-zGQPtqvXPgSA8yfV2CkIQ1qirqk0p9AIVpC5uEkdXQYcKl07QHvyaGYRnZOk0AsQUmxNb4wfkcwY5di8Z5xa9A==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.9.0", + "@azure/core-client": "^1.9.2", + "@azure/core-process": "^1.0.0", + "@azure/core-rest-pipeline": "^1.17.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.11.0", + "@azure/logger": "^1.0.0", + "@azure/msal-browser": "^5.5.0", + "@azure/msal-node": "^6.0.0", + "open": "^10.1.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/logger": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.4.0.tgz", + "integrity": "sha512-rbAE25KUfjU/s3XHUdJgceoCP5dEOpMx85J04kF+QMdta73XkuG9JGHHinch+XIoKpBdqljin+KqURpJriSzLA==", + "license": "MIT", + "dependencies": { + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/msal-browser": { + "version": "5.23.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-5.23.0.tgz", + "integrity": "sha512-IRCwkRCK47hBXK+7bu67UZWY7HS0Jx1dZgi4C1HVbjlBum8Jy8fb2l87xFr6HxdQJWy951zRUHtwwDITHFAtaA==", + "license": "MIT", + "dependencies": { + "@azure/msal-common": "16.14.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-common": { + "version": "16.14.1", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-16.14.1.tgz", + "integrity": "sha512-Or6xhPNyi4zHW25158yxBoyxuCqNSPa5YBVqfF1J5Ks4MJWBo/USXdp05DQIPu1Zli00YZu6t0+h6KvHJealxQ==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-node": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-6.0.1.tgz", + "integrity": "sha512-ixSO1Y/kCVRthRs+hSx/5qkwaunX1/RAePhlMN0wIpIQ4WEZ6AREGGnGd1AP0qspHVsAwzWQKGubpjh50JyJIQ==", + "license": "MIT", + "dependencies": { + "@azure/msal-common": "16.14.1", + "jsonwebtoken": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@napi-rs/keyring": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@napi-rs/keyring/-/keyring-1.3.0.tgz", + "integrity": "sha512-WrOw/bcXm0f9qHkumlT1QlArXSTWqaY9sunsDpOk+yCCorCKMxvWT/a3xko4EYHVdeZoh00yI2TydXn6eyICDA==", + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@napi-rs/keyring-darwin-arm64": "1.3.0", + "@napi-rs/keyring-darwin-x64": "1.3.0", + "@napi-rs/keyring-freebsd-x64": "1.3.0", + "@napi-rs/keyring-linux-arm-gnueabihf": "1.3.0", + "@napi-rs/keyring-linux-arm64-gnu": "1.3.0", + "@napi-rs/keyring-linux-arm64-musl": "1.3.0", + "@napi-rs/keyring-linux-riscv64-gnu": "1.3.0", + "@napi-rs/keyring-linux-x64-gnu": "1.3.0", + "@napi-rs/keyring-linux-x64-musl": "1.3.0", + "@napi-rs/keyring-win32-arm64-msvc": "1.3.0", + "@napi-rs/keyring-win32-ia32-msvc": "1.3.0", + "@napi-rs/keyring-win32-x64-msvc": "1.3.0" + } + }, + "node_modules/@napi-rs/keyring-darwin-arm64": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@napi-rs/keyring-darwin-arm64/-/keyring-darwin-arm64-1.3.0.tgz", + "integrity": "sha512-pl76hJvdYUBn6I24bXiOBMA9nbDapo3I5B+f3OorjDU4dUMSypXeKbOVehJe8fhgTiH24flMyTS3aAIy43xegQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/keyring-darwin-x64": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@napi-rs/keyring-darwin-x64/-/keyring-darwin-x64-1.3.0.tgz", + "integrity": "sha512-YcJtEV5LA3cvA4z3BurgxH5IhTsW1JfIvcAAcqcecwk06Si9F9NqkxbZVIfDwQ8oRHgaBmT3zZJnLAotCrVahw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/keyring-freebsd-x64": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@napi-rs/keyring-freebsd-x64/-/keyring-freebsd-x64-1.3.0.tgz", + "integrity": "sha512-vlLf31TGhfRAaxLDBhg8b89ss0HHD/lyNmL5F3UjSaz5CUXElsJmKYq9fqA/B+cZKUEUcLHHGhF0I/CqcFdaVw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/keyring-linux-arm-gnueabihf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@napi-rs/keyring-linux-arm-gnueabihf/-/keyring-linux-arm-gnueabihf-1.3.0.tgz", + "integrity": "sha512-KiWdMMu/Inz/bHHIAGrnF7r54FZDYXuHO6UFF/rhIrshUsxbMG1Rl9lEymNtqqsVo927G0VYcb02FzWQ3iBQRQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/keyring-linux-arm64-gnu": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@napi-rs/keyring-linux-arm64-gnu/-/keyring-linux-arm64-gnu-1.3.0.tgz", + "integrity": "sha512-eyKGpY40lm9Jvs1aD294XRH4y7+TlJM0YVAryZeXA6TX0mb4gMkxVXwSQv7MCwgah7raeUd0dKUb4BPAYIgcMg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/keyring-linux-arm64-musl": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@napi-rs/keyring-linux-arm64-musl/-/keyring-linux-arm64-musl-1.3.0.tgz", + "integrity": "sha512-iIK6JWHXAJqDrEyLY3TmswwloVyt2vj+04TZnew+uSJ9gnDO8EwRbp3/iw3LpWaXiDO7VomGO6y8I0Id8uBZSw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/keyring-linux-riscv64-gnu": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@napi-rs/keyring-linux-riscv64-gnu/-/keyring-linux-riscv64-gnu-1.3.0.tgz", + "integrity": "sha512-/PGqrwn6EwgtK6vccASSXJRfOSP4vN1F4ASsIQ+7MdrK6hNvAJ1FZPrIuD5gGGdxezo3F++To2Wq7DbuGIeuNQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/keyring-linux-x64-gnu": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@napi-rs/keyring-linux-x64-gnu/-/keyring-linux-x64-gnu-1.3.0.tgz", + "integrity": "sha512-2PDK1WKWTu9lBGq9VvNEkSlQD3O7YwVpmnyN2M3cy4v7NJ/8gDMd9GXv3G+FVXN13uhp4gnnPBS+ScefmEeD2A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/keyring-linux-x64-musl": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@napi-rs/keyring-linux-x64-musl/-/keyring-linux-x64-musl-1.3.0.tgz", + "integrity": "sha512-oJ2HkX8YUo46QBkn0pG+HuIKQNqr523q6vBobCn+P95s4C4K6/kLBqHY/1bg5J4ap31DzsznhnFKcfBNBsjCnw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/keyring-win32-arm64-msvc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@napi-rs/keyring-win32-arm64-msvc/-/keyring-win32-arm64-msvc-1.3.0.tgz", + "integrity": "sha512-tOd3c/uAaeoE4ycVlmAdSvygz0Zt3zdca6Y7gokBeIbaRDWpjDIUOpU3MvML59XAaqyuKGsVVu0F/DZb1lHPmw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/keyring-win32-ia32-msvc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@napi-rs/keyring-win32-ia32-msvc/-/keyring-win32-ia32-msvc-1.3.0.tgz", + "integrity": "sha512-sPSqeAFZMGqP1R++M2JTza7GQJJ/TpCo6JU6Vcd4jnebvOaEDs9b7eipakU1PJdSvhpC2yXMCNRk9gXfrhuwHQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/keyring-win32-x64-msvc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@napi-rs/keyring-win32-x64-msvc/-/keyring-win32-x64-msvc-1.3.0.tgz", + "integrity": "sha512-4DnCWXwDc0HRKwyRlG5y0VhKZW2tNRQfKKfyj6IX/KWfDNyq9hn4n+GL1auyDcOO/v8PwnhmYo2+rOOqCkvvOg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@secretlint/core": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/core/-/core-10.2.2.tgz", + "integrity": "sha512-6rdwBwLP9+TO3rRjMVW1tX+lQeo5gBbxl1I5F8nh8bgGtKwdlCMhMKsBWzWg1ostxx/tIG7OjZI0/BxsP8bUgw==", + "license": "MIT", + "dependencies": { + "@secretlint/profiler": "^10.2.2", + "@secretlint/types": "^10.2.2", + "debug": "^4.4.1", + "structured-source": "^4.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/profiler": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/profiler/-/profiler-10.2.2.tgz", + "integrity": "sha512-qm9rWfkh/o8OvzMIfY8a5bCmgIniSpltbVlUVl983zDG1bUuQNd1/5lUEeWx5o/WJ99bXxS7yNI4/KIXfHexig==", + "license": "MIT" + }, + "node_modules/@secretlint/secretlint-rule-no-dotenv": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-no-dotenv/-/secretlint-rule-no-dotenv-10.2.2.tgz", + "integrity": "sha512-KJRbIShA9DVc5Va3yArtJ6QDzGjg3PRa1uYp9As4RsyKtKSSZjI64jVca57FZ8gbuk4em0/0Jq+uy6485wxIdg==", + "license": "MIT", + "dependencies": { + "@secretlint/types": "^10.2.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/secretlint-rule-preset-recommend": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-preset-recommend/-/secretlint-rule-preset-recommend-10.2.2.tgz", + "integrity": "sha512-K3jPqjva8bQndDKJqctnGfwuAxU2n9XNCPtbXVI5JvC7FnQiNg/yWlQPbMUlBXtBoBGFYp08A94m6fvtc9v+zA==", + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/source-creator": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/source-creator/-/source-creator-10.2.2.tgz", + "integrity": "sha512-h6I87xJfwfUTgQ7irWq7UTdq/Bm1RuQ/fYhA3dtTIAop5BwSFmZyrchph4WcoEvbN460BWKmk4RYSvPElIIvxw==", + "license": "MIT", + "dependencies": { + "@secretlint/types": "^10.2.2", + "istextorbinary": "^9.5.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/types": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/types/-/types-10.2.2.tgz", + "integrity": "sha512-Nqc90v4lWCXyakD6xNyNACBJNJ0tNCwj2WNk/7ivyacYHxiITVgmLUFXTBOeCdy79iz6HtN9Y31uw/jbLrdOAg==", + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@typespec/ts-http-runtime": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.9.tgz", + "integrity": "sha512-edSdeAqkdxBVzA1yL1LrLCml1YjyCVvPMtMqJpbF+6K609tHe8V6sQUzFQSGcYNhcuhOceZtjvN32+mpIth30A==", + "license": "MIT", + "dependencies": { + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@vscode/vsce": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-4.0.0.tgz", + "integrity": "sha512-NImwuLaenMmb5D5Jer9/lzi/F9ZQUBOp8Azhj/BVYcTFgixv8KehFXqEUDjQlD2tAiw2E6dDGyjTuAB//di60A==", + "license": "MIT", + "dependencies": { + "@azure/identity": "^4.13.2", + "@napi-rs/keyring": "^1.3.0", + "@secretlint/core": "^10.2.2", + "@secretlint/secretlint-rule-no-dotenv": "^10.2.2", + "@secretlint/secretlint-rule-preset-recommend": "^10.2.2", + "@secretlint/source-creator": "^10.2.2", + "@secretlint/types": "^10.2.2", + "@vscode/vsce-sign": "^2.1.0", + "azure-devops-node-api": "^12.5.0", + "cockatiel": "^3.2.1", + "commander": "^12.1.0", + "hosted-git-info": "^4.1.0", + "jsonc-parser": "^3.3.1", + "marked": "^18.0.11", + "mime": "^1.6.0", + "minimatch": "^10.2.6", + "parse5": "^8.0.1", + "proper-lockfile": "^4.1.2", + "read": "^1.0.7", + "semver": "^7.8.5", + "tinyglobby": "^0.2.17", + "typed-rest-client": "^1.8.11", + "url-join": "^4.0.1", + "xml2js": "^0.5.0", + "yauzl": "^3.4.0", + "yazl": "^2.5.1" + }, + "bin": { + "vsce": "vsce" + }, + "engines": { + "node": ">= 22" + } + }, + "node_modules/@vscode/vsce-sign": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign/-/vsce-sign-2.1.0.tgz", + "integrity": "sha512-9AQrqazrBgTgRSuwleLVXUrIUphY02/SFCh2TKYoLV/xifJAdblhdmEmw5gUrYSPQ3sRwNs9iyCMD14sATEE6g==", + "hasInstallScript": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optionalDependencies": { + "@vscode/vsce-sign-alpine-arm64": "2.0.6", + "@vscode/vsce-sign-alpine-x64": "2.0.6", + "@vscode/vsce-sign-darwin-arm64": "2.0.6", + "@vscode/vsce-sign-darwin-x64": "2.0.6", + "@vscode/vsce-sign-linux-arm": "2.0.6", + "@vscode/vsce-sign-linux-arm64": "2.0.6", + "@vscode/vsce-sign-linux-x64": "2.0.6", + "@vscode/vsce-sign-win32-arm64": "2.0.6", + "@vscode/vsce-sign-win32-x64": "2.0.6" + } + }, + "node_modules/@vscode/vsce-sign-alpine-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-arm64/-/vsce-sign-alpine-arm64-2.0.6.tgz", + "integrity": "sha512-wKkJBsvKF+f0GfsUuGT0tSW0kZL87QggEiqNqK6/8hvqsXvpx8OsTEc3mnE1kejkh5r+qUyQ7PtF8jZYN0mo8Q==", + "cpu": [ + "arm64" + ], + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "alpine" + ] + }, + "node_modules/@vscode/vsce-sign-alpine-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-x64/-/vsce-sign-alpine-x64-2.0.6.tgz", + "integrity": "sha512-YoAGlmdK39vKi9jA18i4ufBbd95OqGJxRvF3n6ZbCyziwy3O+JgOpIUPxv5tjeO6gQfx29qBivQ8ZZTUF2Ba0w==", + "cpu": [ + "x64" + ], + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "alpine" + ] + }, + "node_modules/@vscode/vsce-sign-darwin-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-arm64/-/vsce-sign-darwin-arm64-2.0.6.tgz", + "integrity": "sha512-5HMHaJRIQuozm/XQIiJiA0W9uhdblwwl2ZNDSSAeXGO9YhB9MH5C4KIHOmvyjUnKy4UCuiP43VKpIxW1VWP4tQ==", + "cpu": [ + "arm64" + ], + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@vscode/vsce-sign-darwin-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-x64/-/vsce-sign-darwin-x64-2.0.6.tgz", + "integrity": "sha512-25GsUbTAiNfHSuRItoQafXOIpxlYj+IXb4/qarrXu7kmbH94jlm5sdWSCKrrREs8+GsXF1b+l3OB7VJy5jsykw==", + "cpu": [ + "x64" + ], + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@vscode/vsce-sign-linux-arm": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm/-/vsce-sign-linux-arm-2.0.6.tgz", + "integrity": "sha512-UndEc2Xlq4HsuMPnwu7420uqceXjs4yb5W8E2/UkaHBB9OWCwMd3/bRe/1eLe3D8kPpxzcaeTyXiK3RdzS/1CA==", + "cpu": [ + "arm" + ], + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/vsce-sign-linux-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm64/-/vsce-sign-linux-arm64-2.0.6.tgz", + "integrity": "sha512-cfb1qK7lygtMa4NUl2582nP7aliLYuDEVpAbXJMkDq1qE+olIw/es+C8j1LJwvcRq1I2yWGtSn3EkDp9Dq5FdA==", + "cpu": [ + "arm64" + ], + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/vsce-sign-linux-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-x64/-/vsce-sign-linux-x64-2.0.6.tgz", + "integrity": "sha512-/olerl1A4sOqdP+hjvJ1sbQjKN07Y3DVnxO4gnbn/ahtQvFrdhUi0G1VsZXDNjfqmXw57DmPi5ASnj/8PGZhAA==", + "cpu": [ + "x64" + ], + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/vsce-sign-win32-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-arm64/-/vsce-sign-win32-arm64-2.0.6.tgz", + "integrity": "sha512-ivM/MiGIY0PJNZBoGtlRBM/xDpwbdlCWomUWuLmIxbi1Cxe/1nooYrEQoaHD8ojVRgzdQEUzMsRbyF5cJJgYOg==", + "cpu": [ + "arm64" + ], + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vscode/vsce-sign-win32-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-x64/-/vsce-sign-win32-x64-2.0.6.tgz", + "integrity": "sha512-mgth9Kvze+u8CruYMmhHw6Zgy3GRX2S+Ed5oSokDEK5vPEwGGKnmuXua9tmFhomeAnhgJnL4DCna3TiNuGrBTQ==", + "cpu": [ + "x64" + ], + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/azure-devops-node-api": { + "version": "12.5.0", + "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-12.5.0.tgz", + "integrity": "sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og==", + "license": "MIT", + "dependencies": { + "tunnel": "0.0.6", + "typed-rest-client": "^1.8.4" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/binaryextensions": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-6.11.0.tgz", + "integrity": "sha512-sXnYK/Ij80TO3lcqZVV2YgfKN5QjUWIRk/XSm2J/4bd/lPko3lvk0O4ZppH6m+6hB2/GTu+ptNwVFe1xh+QLQw==", + "license": "Artistic-2.0", + "dependencies": { + "editions": "^6.21.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/boundary": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/boundary/-/boundary-2.0.0.tgz", + "integrity": "sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA==", + "license": "BSD-2-Clause" + }, + "node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/bundle-name": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.1.tgz", + "integrity": "sha512-DdH81/zPLVS11EUgWq3tEu/xn+EzljlMYooDNdzWEnFha3R3NBMpMV1UqYIpjYHV/SgpFKMIX1Oh7o06SjM/oA==", + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/cockatiel": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/cockatiel/-/cockatiel-3.2.1.tgz", + "integrity": "sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/default-browser": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.1.tgz", + "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==", + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/editions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/editions/-/editions-6.22.0.tgz", + "integrity": "sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==", + "license": "Artistic-2.0", + "dependencies": { + "version-range": "^4.15.0" + }, + "engines": { + "ecmascript": ">= es5", + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/entities": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.1.0.tgz", + "integrity": "sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/istextorbinary": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-9.5.0.tgz", + "integrity": "sha512-5mbUj3SiZXCuRf9fT3ibzbSSEWiy63gFfksmGfdOzujPjW3k+z8WvIBxcJHBoQNlaZaiyB25deviif2+osLmLw==", + "license": "Artistic-2.0", + "dependencies": { + "binaryextensions": "^6.11.0", + "editions": "^6.21.0", + "textextensions": "^6.11.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "license": "MIT" + }, + "node_modules/jsonwebtoken": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", + "license": "MIT", + "dependencies": { + "jws": "^4.0.1", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/marked": { + "version": "18.0.14", + "resolved": "https://registry.npmjs.org/marked/-/marked-18.0.14.tgz", + "integrity": "sha512-mBHK6FBHuBAlhgRe88w9F0O1AbwwXJUcQibUbC/QcdTbVGAD7aWza+xt3N6oT/jCZx3/OMeS+8rnuiHZcQ9s7A==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "license": "ISC" + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "license": "MIT", + "dependencies": { + "entities": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "license": "MIT" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/playwright-core": { + "version": "1.55.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.55.0.tgz", + "integrity": "sha512-GvZs4vU3U5ro2nZpeiwyb0zuFaqb9sUiAJuyrWpcGouD8y9/HLgGbNRjIph7zU9D3hnPaisMl9zG9CgFi/biIg==", + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/qs": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", + "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", + "license": "ISC", + "dependencies": { + "mute-stream": "~0.0.4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", + "integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/structured-source": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/structured-source/-/structured-source-4.0.0.tgz", + "integrity": "sha512-qGzRFNJDjFieQkl/sVOI2dUjHKRyL9dAJi2gCPGJLbJHBIkyOHxjuocpIEfbLioX+qSJpvbYdT49/YCdMznKxA==", + "license": "BSD-2-Clause", + "dependencies": { + "boundary": "^2.0.0" + } + }, + "node_modules/textextensions": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-6.11.0.tgz", + "integrity": "sha512-tXJwSr9355kFJI3lbCkPpUH5cP8/M0GGy2xLO34aZCjMXBaK3SoPnZwr/oWmo1FdCnELcs4npdCIOFtq9W3ruQ==", + "license": "Artistic-2.0", + "dependencies": { + "editions": "^6.21.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "license": "MIT", + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/typed-rest-client": { + "version": "1.8.11", + "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz", + "integrity": "sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==", + "license": "MIT", + "dependencies": { + "qs": "^6.9.1", + "tunnel": "0.0.6", + "underscore": "^1.12.1" + } + }, + "node_modules/underscore": { + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.8.tgz", + "integrity": "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==", + "license": "MIT" + }, + "node_modules/url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", + "license": "MIT" + }, + "node_modules/version-range": { + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/version-range/-/version-range-4.15.0.tgz", + "integrity": "sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg==", + "license": "Artistic-2.0", + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, + "node_modules/yauzl": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.4.0.tgz", + "integrity": "sha512-jIH9yLR9wqr0wOS0TpBvo/g/2UgZH5qePVbjgRliiF0BYvOZyaBknKsF+x9Iht0O6sqgnB93rCICdOZFecJuDw==", + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3" + } + } + } +} diff --git a/scripts/demo-gifs/package.json b/scripts/demo-gifs/package.json new file mode 100644 index 00000000..e24697af --- /dev/null +++ b/scripts/demo-gifs/package.json @@ -0,0 +1,13 @@ +{ + "name": "gitlab-component-helper-demo-gifs", + "private": true, + "description": "Records the README demo GIFs by driving a real VS Code. Maintainer tool, never packaged.", + "type": "module", + "scripts": { + "record": "node record.mjs" + }, + "dependencies": { + "@vscode/vsce": "4.0.0", + "playwright-core": "1.55.0" + } +} diff --git a/scripts/demo-gifs/record.mjs b/scripts/demo-gifs/record.mjs new file mode 100644 index 00000000..0a3ae7b6 --- /dev/null +++ b/scripts/demo-gifs/record.mjs @@ -0,0 +1,61 @@ +// Re-records the README demo GIFs in a throwaway VS Code profile. Usage and publishing steps live in +// .ai/workflows.yaml (record_demo_gifs). +// +// npm install && npm run record # every scene +// npm run record -- hover versions # just these +import * as browse from './scenes/browse.mjs'; +import * as complete from './scenes/complete.mjs'; +import * as hover from './scenes/hover.mjs'; +import * as validate from './scenes/validate.mjs'; +import * as versions from './scenes/versions.mjs'; +import { showCursor } from './lib/input.mjs'; +import { Recorder, encodeGif, writeReviewSheet } from './lib/recorder.mjs'; +import { launchVsCode, prepareScene, runCommand, sleep, stopVsCode, webviewFrame } from './lib/vscode.mjs'; +import { installExtension, readFixtureSettings, resetWorkDir } from './lib/workspace.mjs'; + +const SCENES = { browse, complete, hover, validate, versions }; +const SOURCE_COUNT = readFixtureSettings()['gitlabComponentHelper.componentSources'].length; + +/** Open the Component Browser once so every source is cached before the first take. */ +async function warmCache(page) { + await prepareScene(page, { content: 'include:\n' }); + await runCommand(page, 'GitLab CI: Browse Components'); + const list = await webviewFrame(page, '.source-group'); + await list.locator('.source-group').nth(SOURCE_COUNT - 1).waitFor({ timeout: 60000 }); +} + +async function recordScene({ page, cdp }, name) { + const scene = SCENES[name]; + await scene.prepare(page); + await showCursor(page, scene.cursorStart.x, scene.cursorStart.y); + const recorder = new Recorder(cdp, name); + await recorder.start(); + await sleep(1000); + await scene.perform(page); + const duration = await recorder.stop(); + const gif = encodeGif(name); + const sheet = writeReviewSheet(name, duration); + console.log(`${name}: ${gif} (${duration.toFixed(1)}s), review sheet ${sheet}`); +} + +async function main() { + const requested = process.argv.slice(2); + const unknown = requested.filter((name) => !SCENES[name]); + if (unknown.length) throw new Error(`Unknown scene(s): ${unknown.join(', ')}. Pick from ${Object.keys(SCENES).join(', ')}`); + const names = requested.length ? requested : Object.keys(SCENES); + + resetWorkDir(); + installExtension(); + const session = await launchVsCode(); + try { + await warmCache(session.page); + for (const name of names) await recordScene(session, name); + } finally { + await stopVsCode(session); + } +} + +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/scripts/demo-gifs/scenes/browse.mjs b/scripts/demo-gifs/scenes/browse.mjs new file mode 100644 index 00000000..98863940 --- /dev/null +++ b/scripts/demo-gifs/scenes/browse.mjs @@ -0,0 +1,42 @@ +// Component Browser: search, open details, pick inputs, insert, then show the result full width. +import { centerOf, clickOn, moveTo, scrollIntoView, typeSlow } from '../lib/input.mjs'; +import { prepareScene, runCommand, sleep, webviewFrame } from '../lib/vscode.mjs'; + +export const cursorStart = { x: 700, y: 520 }; + +export async function prepare(page) { + await prepareScene(page, { content: 'stages:\n - test\n\ninclude:\n' }); +} + +const tabClose = (page, label) => page.locator(`.tab[aria-label^="${label}"] .tab-actions .action-label`).first(); + +export async function perform(page) { + await runCommand(page, 'GitLab CI: Browse Components', { typeText: (t) => typeSlow(page, t, 45) }); + const list = await webviewFrame(page, '#search'); + await sleep(1500); + await clickOn(page, list.locator('#search')); + await typeSlow(page, 'secret', 110); + await sleep(1500); + await clickOn(page, list.locator('.component-card[data-name="secret-detection"] [data-action="viewDetails"]')); + const details = await webviewFrame(page, '#parametersContainer .parameter'); + await sleep(1500); + // Closing the list leaves editor | details side by side, which reads better than three narrow columns. + await clickOn(page, tabClose(page, 'GitLab CI/CD Components'), { ms: 700 }); + await moveTo(page, 900, 300, 400); + await sleep(1100); + const panelX = (await centerOf(details.locator('#componentName'))).x; + for (const input of ['stage', 'historic_scan', 'excluded_paths']) { + const checkbox = details.locator(`#input-${input}`); + await scrollIntoView(page, checkbox, panelX); + await clickOn(page, checkbox, { ms: 450 }); + await sleep(450); + } + const insert = details.locator('button[data-action="insertComponent"]'); + await scrollIntoView(page, insert, panelX); + await sleep(400); + await clickOn(page, insert); + await sleep(2200); + await clickOn(page, tabClose(page, 'Component: secret-detection'), { ms: 800 }); + await moveTo(page, 820, 520, 500); + await sleep(3000); +} diff --git a/scripts/demo-gifs/scenes/complete.mjs b/scripts/demo-gifs/scenes/complete.mjs new file mode 100644 index 00000000..28185b19 --- /dev/null +++ b/scripts/demo-gifs/scenes/complete.mjs @@ -0,0 +1,46 @@ +// Completion: component names after `component:`, then the version list after `@`. +import { typeSlow } from '../lib/input.mjs'; +import { prepareScene, sleep } from '../lib/vscode.mjs'; + +export const cursorStart = { x: 1100, y: 640 }; + +export async function prepare(page) { + await prepareScene(page, { content: 'stages:\n - validate\n - build\n - deploy\n\ninclude:\n' }); +} + +async function press(page, key, times = 1, gap = 90) { + for (let i = 0; i < times; i++) { + await page.keyboard.press(key); + await sleep(gap); + } +} + +export async function perform(page) { + await typeSlow(page, ' - component: ', 75); + await sleep(1800); + await typeSlow(page, 'plan', 160); + await sleep(1800); + await press(page, 'ArrowDown', 1, 500); + await press(page, 'ArrowUp', 1, 700); + await page.keyboard.press('Enter'); + await sleep(1500); + // Drop the version that came with the suggestion to show the version picker. + const line = await page.locator('.view-line', { hasText: 'opentofu/plan@' }).first().innerText(); + await press(page, 'Backspace', line.trimEnd().length - line.lastIndexOf('@') - 1); + await sleep(600); + await page.keyboard.press('Control+Space'); + await sleep(1800); + await press(page, 'ArrowDown', 1, 450); + await press(page, 'ArrowUp', 1, 600); + await page.keyboard.press('Enter'); + await sleep(1200); + await page.keyboard.press('End'); + await page.keyboard.press('Enter'); + // Auto-indent already lines the new entry up under the first one. + await typeSlow(page, '- component: ', 60); + await sleep(1200); + await typeSlow(page, 'secret', 140); + await sleep(1300); + await page.keyboard.press('Enter'); + await sleep(2500); +} diff --git a/scripts/demo-gifs/scenes/hover.mjs b/scripts/demo-gifs/scenes/hover.mjs new file mode 100644 index 00000000..0db58052 --- /dev/null +++ b/scripts/demo-gifs/scenes/hover.mjs @@ -0,0 +1,56 @@ +// Hover: component docs with version status, an input's docs, and an outdated pin. +import { moveTo, wordPosition } from '../lib/input.mjs'; +import { prepareScene, sleep } from '../lib/vscode.mjs'; + +export const cursorStart = { x: 1000, y: 650 }; +const REST = { x: 1000, y: 650 }; +const URL_OFFSET_PX = 120; + +export async function prepare(page) { + await prepareScene(page, { + cursorAtEnd: false, + content: `stages: + - validate + - build + - test + +include: + - component: gitlab.com/components/opentofu/validate-plan@4.9.0 + inputs: + opentofu_version: 1.12.6 + root_dir: infra/ + - component: gitlab.com/components/sast/sast@3.3.0 + inputs: + excluded_paths: "spec, tmp" +`, + }); + // The version check runs on open/save, so save once to make the outdated pin's hint ready before recording. + await page.keyboard.press('Meta+S'); + await sleep(4000); +} + +async function hoverWord(page, lineText, word, { offset = 0, hold = 3500 } = {}) { + const { x, y } = await wordPosition(page, lineText, word); + await moveTo(page, x + offset, y, 850); + await sleep(hold); +} + +export async function perform(page) { + await hoverWord(page, 'opentofu/validate-plan', 'gitlab.com', { offset: URL_OFFSET_PX }); + const hover = page.locator('.monaco-hover:visible .monaco-scrollable-element').first(); + const box = await hover.boundingBox(); + await moveTo(page, box.x + box.width / 2, box.y + box.height / 2, 600); + for (let i = 0; i < 8; i++) { + await page.mouse.wheel(0, 60); + await sleep(180); + } + await sleep(2000); + await moveTo(page, REST.x, REST.y, 500); + await sleep(600); + await hoverWord(page, 'opentofu_version', 'opentofu_version'); + await moveTo(page, REST.x, REST.y, 500); + await sleep(600); + await hoverWord(page, 'sast/sast', 'gitlab.com', { offset: URL_OFFSET_PX, hold: 4000 }); + await moveTo(page, 1100, 700, 600); + await sleep(800); +} diff --git a/scripts/demo-gifs/scenes/validate.mjs b/scripts/demo-gifs/scenes/validate.mjs new file mode 100644 index 00000000..68ff56ec --- /dev/null +++ b/scripts/demo-gifs/scenes/validate.mjs @@ -0,0 +1,77 @@ +// Input checks: Quick Fix a mistyped remote input, then fill a local template's inputs until its error clears. +import { moveTo, typeSlow, wordPosition } from '../lib/input.mjs'; +import { prepareScene, sleep } from '../lib/vscode.mjs'; + +export const cursorStart = { x: 1100, y: 650 }; +const REST = { x: 1100, y: 650 }; + +export async function prepare(page) { + await prepareScene(page, { + content: `stages: + - test + - deploy + +include: + - component: gitlab.com/components/sast/sast@3.5.0 + inputs: + excluded_path: "spec, tmp" +`, + }); + await page.keyboard.press('Meta+S'); + await sleep(3000); +} + +async function pickSuggestion(page, downPresses) { + await page.keyboard.press('Control+Space'); + await sleep(1500); + for (let i = 0; i < downPresses; i++) { + await page.keyboard.press('ArrowDown'); + await sleep(550); + } + await page.keyboard.press('Enter'); + await sleep(500); +} + +async function fixTypo(page) { + const typo = await wordPosition(page, 'excluded_path', 'excluded_path'); + await moveTo(page, typo.x, typo.y, 900); + await sleep(2800); + await page.mouse.click(typo.x, typo.y); + await sleep(300); + await page.keyboard.press('Meta+.'); + await sleep(1500); + // The suggestions aren't ranked yet (#333), so walk down to `excluded_paths`. + for (let i = 0; i < 2; i++) { + await page.keyboard.press('ArrowDown'); + await sleep(500); + } + await sleep(500); + await page.keyboard.press('Enter'); + await moveTo(page, REST.x, REST.y, 500); + await sleep(1200); +} + +export async function perform(page) { + await fixTypo(page); + await page.keyboard.press('Meta+ArrowDown'); + await typeSlow(page, ' - local: templates/deploy.yml', 55); + await page.keyboard.press('Enter'); + await typeSlow(page, ' inputs:', 60); + await page.keyboard.press('Enter'); + await typeSlow(page, ' ', 60); + await pickSuggestion(page, 1); // environment + await pickSuggestion(page, 1); // production + await page.keyboard.press('Meta+S'); + await sleep(2000); + const local = await wordPosition(page, 'local:', 'templates/deploy.yml'); + await moveTo(page, local.x, local.y, 900); + await sleep(3500); + await moveTo(page, REST.x, REST.y, 500); + await page.keyboard.press('Meta+ArrowDown'); + await page.keyboard.press('End'); + await page.keyboard.press('Enter'); + await pickSuggestion(page, 0); // app_name, the only missing input left + await typeSlow(page, 'billing-api', 90); + await page.keyboard.press('Meta+S'); + await sleep(3000); +} diff --git a/scripts/demo-gifs/scenes/versions.mjs b/scripts/demo-gifs/scenes/versions.mjs new file mode 100644 index 00000000..09a5969b --- /dev/null +++ b/scripts/demo-gifs/scenes/versions.mjs @@ -0,0 +1,43 @@ +// Version upgrades: hover an outdated pin, Quick Fix it, then update the rest from the Command Palette. +import { moveTo, typeSlow, wordPosition } from '../lib/input.mjs'; +import { prepareScene, runCommand, sleep } from '../lib/vscode.mjs'; + +export const cursorStart = { x: 1100, y: 650 }; + +export async function prepare(page) { + await prepareScene(page, { + cursorAtEnd: false, + content: `stages: + - validate + - build + - test + - deploy + +include: + - component: gitlab.com/components/opentofu/validate-plan-apply@4.6.0 + - component: gitlab.com/components/sast/sast@3.3.0 + - component: gitlab.com/components/secret-detection/secret-detection@2.1.0 + - component: gitlab.com/components/code-quality/code-quality@1.0.6 +`, + }); + await page.keyboard.press('Meta+S'); + await sleep(5000); +} + +export async function perform(page) { + const pin = await wordPosition(page, 'sast/sast', '3.3.0'); + await moveTo(page, pin.x, pin.y, 900); + await sleep(3800); + await page.mouse.click(pin.x, pin.y); + await sleep(300); + await page.keyboard.press('Meta+.'); + await sleep(1700); + await page.keyboard.press('Enter'); + await sleep(1200); + await moveTo(page, 1100, 650, 600); + await sleep(800); + await runCommand(page, 'GitLab CI: Update All Component Versions to Latest', { typeText: (t) => typeSlow(page, t, 45) }); + await sleep(3500); + await page.keyboard.press('Meta+S'); + await sleep(2500); +} diff --git a/src/constants/cache.ts b/src/constants/cache.ts index 4d8b6fb3..2d23fc91 100644 --- a/src/constants/cache.ts +++ b/src/constants/cache.ts @@ -22,7 +22,6 @@ export const DEFAULT_COMPONENT_TYPE_PROJECT = 'project' as const; export const DEFAULT_COMPONENT_TYPE_GROUP = 'group' as const; // Source Names -export const SOURCE_LOCAL = 'Local' as const; export const SOURCE_COMPONENTS_PREFIX = 'Components from' as const; // Parameter Types diff --git a/src/extension.ts b/src/extension.ts index 876bfcc7..8b55ba35 100755 --- a/src/extension.ts +++ b/src/extension.ts @@ -5,8 +5,8 @@ import { CompletionProvider } from './providers/completionProvider'; import { ComponentDocumentLinkProvider } from './providers/documentLinkProvider'; import { ComponentBrowserProvider } from './providers/componentBrowserProvider'; import { detectIncludeComponent, Component } from './providers/componentDetector'; -import { stripTagPrefix } from './services/component/tagScoping'; import { getComponentCacheManager, ComponentCacheManager } from './services/cache/componentCacheManager'; +import { assetRoots } from './webview/webviewHtml'; import { Logger } from './utils/logger'; import { ValidationProvider } from './providers/validationProvider'; import type { CachedComponent } from './types/cache'; @@ -16,22 +16,6 @@ import type { HoverContext } from './providers/hoverContentBuilder'; /** Component payload passed to the `detachHover` command. Adds the hover-builder's location context. */ type DetachableComponent = Component & { _hoverContext?: HoverContext }; -/** - * Type-guard narrowing a `Component`-shaped value to one that also satisfies `CachedComponent`. - * - * @param component A `Component` (typically `activeComponent` in the detach-hover panel) that may - * or may not have been enriched with cache details. - * @returns `true` if all `CachedComponent` required fields are present and string-typed, - * narrowing `component` to `Component & CachedComponent` in the truthy branch. - * `false` if any field is missing. - */ -function isCachedComponentShape(component: Component): component is Component & CachedComponent { - return typeof component.source === 'string' - && typeof component.sourcePath === 'string' - && typeof component.gitlabInstance === 'string' - && typeof component.version === 'string' - && typeof component.url === 'string'; -} import { getPerformanceMonitor } from './utils/performanceMonitor'; import { isGitLabCIFile, invalidateFileGlobsCache } from './utils/gitlabCiFileMatcher'; @@ -212,8 +196,7 @@ export function activate(context: vscode.ExtensionContext) { const confirmation = await vscode.window.showWarningMessage( 'Are you sure you want to reset the cache? This will clear all cached components and force them to be re-downloaded.', { modal: true }, - 'Reset Cache', - 'Cancel' + 'Reset Cache' ); if (confirmation === 'Reset Cache') { @@ -335,7 +318,7 @@ export function activate(context: vscode.ExtensionContext) { { enableScripts: true, retainContextWhenHidden: true, - localResourceRoots: [] + localResourceRoots: assetRoots(context.extensionUri) } ); @@ -420,7 +403,7 @@ export function activate(context: vscode.ExtensionContext) { // (cacheManager.fetchComponentVersions) scopes to this component instead of returning every repo tag. const enriched = await componentBrowser.lookupComponentDetails(activeComponent); activeComponent = { ...activeComponent, ...enriched }; - panel.webview.html = componentBrowser.getComponentDetailsHtml(activeComponent); + panel.webview.html = componentBrowser.getComponentDetailsHtml(panel.webview, activeComponent); // Ensure the original editor remains focused after panel creation setTimeout(async () => { @@ -430,145 +413,7 @@ export function activate(context: vscode.ExtensionContext) { }); }, PANEL_FOCUS_DELAY_MS); - // Handle messages from the detached webview - panel.webview.onDidReceiveMessage(async (message) => { - switch (message.command) { - case 'insertComponent': - try { - // Ensure the original editor is active and focused - await vscode.window.showTextDocument(originalEditor.document, originalEditor.viewColumn); - - // Wait a brief moment for the editor to fully activate - await new Promise(resolve => setTimeout(resolve, PANEL_FOCUS_DELAY_MS)); - - // Verify we have the correct active editor - const currentEditor = vscode.window.activeTextEditor; - if (!currentEditor || currentEditor.document.uri.toString() !== originalEditor.document.uri.toString()) { - vscode.window.showErrorMessage('Could not activate the original editor'); - return; - } - - // Handle different insertion options - const { version, includeInputs, selectedInputs } = message; - - // Update component version if specified - if (version && version !== activeComponent.version) { - if (!activeComponent.sourcePath || !activeComponent.gitlabInstance) { - vscode.window.showErrorMessage(`Cannot fetch version: component is missing source path or GitLab instance.`); - return; - } - const updatedComponent = await cacheManager.fetchSpecificVersion( - activeComponent.name, - activeComponent.sourcePath, - activeComponent.gitlabInstance, - version - ); - if (updatedComponent) { - if (activeComponent._hoverContext) { - await componentBrowser.editExistingComponentFromDetached( - updatedComponent, - activeComponent._hoverContext.documentUri, - activeComponent._hoverContext.position, - includeInputs || false, - selectedInputs || [] - ); - } else { - await componentBrowser.insertComponentFromDetached( - updatedComponent, - includeInputs || false, - selectedInputs || [] - ); - } - } else { - vscode.window.showErrorMessage(`Failed to fetch version ${version} of component ${activeComponent.name}`); - } - } else { - if (activeComponent._hoverContext) { - await componentBrowser.editExistingComponentFromDetached( - activeComponent, - activeComponent._hoverContext.documentUri, - activeComponent._hoverContext.position, - includeInputs || false, - selectedInputs || [] - ); - } else { - await componentBrowser.insertComponentFromDetached( - activeComponent, - includeInputs || false, - selectedInputs || [] - ); - } - } - - // Close the panel after successful insertion/edit - panel.dispose(); - } catch (error) { - logger.error(`[Extension] Error inserting component from detached view: ${error}`, 'Extension'); - vscode.window.showErrorMessage(`Error inserting component: ${error}`); - } - break; - case 'fetchVersions': - try { - if (!isCachedComponentShape(activeComponent)) { - throw new Error('Component is missing required fields (source, sourcePath, gitlabInstance, version) for version lookup.'); - } - const versions = await cacheManager.fetchComponentVersions(activeComponent); - // For a monorepo source, map each full tag to its stripped {version} so the dropdown shows short - // labels while keeping the full tag as the option value (the inserted ref). - let versionLabels: Record | undefined; - if (activeComponent.tagPattern) { - versionLabels = {}; - for (const v of versions) { - versionLabels[v] = stripTagPrefix(v, activeComponent.name, activeComponent.tagPattern); - } - } - panel.webview.postMessage({ - command: 'versionsLoaded', - versions: versions, - versionLabels, - currentVersion: activeComponent.version - }); - } catch (error) { - panel.webview.postMessage({ - command: 'versionsError', - error: error instanceof Error ? error.message : String(error) - }); - } - break; - case 'versionChanged': - try { - const { selectedVersion } = message; - if (!activeComponent.sourcePath || !activeComponent.gitlabInstance) { - vscode.window.showErrorMessage(`Cannot change version: component is missing source path or GitLab instance.`); - return; - } - const updatedComponent = await cacheManager.fetchSpecificVersion( - activeComponent.name, - activeComponent.sourcePath, - activeComponent.gitlabInstance, - selectedVersion - ); - if (updatedComponent) { - activeComponent = updatedComponent; - panel.webview.postMessage({ - command: 'componentDetailsUpdated', - component: updatedComponent - }); - } else { - panel.webview.postMessage({ - command: 'versionChangeError', - error: `Failed to fetch details for version ${selectedVersion}` - }); - } - } catch (error) { - panel.webview.postMessage({ - command: 'versionChangeError', - error: error instanceof Error ? error.message : String(error) - }); - } - break; - } - }); + componentBrowser.registerDetailsPanelMessageHandler(panel, activeComponent, { detachedFrom: originalEditor }); }) ); diff --git a/src/parsers/parameterDefaultShape.ts b/src/parsers/parameterDefaultShape.ts new file mode 100644 index 00000000..7d151164 --- /dev/null +++ b/src/parsers/parameterDefaultShape.ts @@ -0,0 +1,31 @@ +/** + * Shared type-guard for "is this value usable as an input's `default:`?". + * + * `vscode`-free and pure so the Mocha unit suite (and `specParser`, which must load under plain Node) can import it + * directly. Both spec parsers narrow the same union, so they share one definition rather than a copy each. + */ + +import type { ParameterDefault } from '../types/git-component'; + +/** + * Narrow an unknown value to {@link ParameterDefault}, the union accepted by an input's `default:` field. + * + * Guards the boundary where a parsed spec becomes a typed parameter: YAML and the catalog API both hand back + * `unknown`, and anything outside the union (a mapping, a nested array) is rejected rather than carried forward as + * a default no consumer can render. + * + * @param value - A value of unknown shape, typically straight from a YAML parse or an API response. + * @returns `true` when `value` is a string, number, boolean, `null`, or an array of those primitives. + */ +export function isParameterDefault(value: unknown): value is ParameterDefault { + if (value === null) return true; + const t = typeof value; + if (t === 'string' || t === 'number' || t === 'boolean') return true; + if (Array.isArray(value)) { + return value.every(v => { + const vt = typeof v; + return vt === 'string' || vt === 'number' || vt === 'boolean'; + }); + } + return false; +} diff --git a/src/parsers/specParser.ts b/src/parsers/specParser.ts index 2386a19a..acf6b000 100644 --- a/src/parsers/specParser.ts +++ b/src/parsers/specParser.ts @@ -3,17 +3,97 @@ import { Logger } from '../utils/logger'; // Import direct from errors/types (not the barrel) so this module can load from plain Node โ€” the barrel re-exports // from errors/handler.ts which imports `vscode` at module load. Required for the Mocha unit suite. import { ParseError } from '../errors/types'; +import type { ParameterDefault } from '../types/git-component'; +import { isParameterDefault } from './parameterDefaultShape'; +import * as yaml from 'js-yaml'; +import { isYamlNode, GITLAB_CI_SCHEMA } from '../utils/yamlParser'; const logger = Logger.getInstance(); +/** + * Resolve one already-trimmed scalar to the value YAML reads it as. + * + * @param trimmed - A single scalar's text, surrounding whitespace already removed. + * @returns The parsed value, or the text with surrounding quotes stripped when it isn't a parseable YAML scalar. + */ +function parseScalar(trimmed: string): ParameterDefault { + try { + // `yaml.load` directly rather than `parseYaml`: these probes are one-off strings, so memoising them only evicts + // the document parses sharing that cache. + const parsed = yaml.load(`probe: ${trimmed}`, { schema: GITLAB_CI_SCHEMA }); + if (isYamlNode(parsed) && isParameterDefault(parsed.probe)) { + return parsed.probe; + } + } catch { + // Not valid YAML on its own (an unquoted `*`, a stray `{`, โ€ฆ) โ€” fall back to the literal text. + } + return trimmed.replace(/^["']|["']$/g, '').trim(); +} + +/** + * Parse the text after `default:` into the value the input's type says it is. + * + * This parser reads the spec line-by-line rather than as a document, so a `default:` value arrives as raw text. Left + * as text, `default: false` on a `type: boolean` input becomes the string `"false"`, which downstream renders back + * as a quoted `"false"` โ€” a string where GitLab expects a boolean. + * + * A `string` input's default is text by declaration, so it is never sent through YAML: `default: 1.0` stays `"1.0"` + * and `0755` keeps its leading zero. That covers an omitted `type:` as well โ€” GitLab resolves an untyped input as + * `StringInput` (its `matches?` accepts a spec with no `:type` key) and coerces the default with `to_s`, so an + * untyped default is a string no matter what it looks like. + * + * @param rawValue - The text following `default:` on the line, e.g. `false`, `"0"`, `[a, b]`. + * @param inputType - The input's resolved `type:`; `'string'` when the spec omits it. + * @returns The parsed value, or the trimmed raw text when it doesn't parse as a YAML scalar. + */ +function parseDefaultValue(rawValue: string, inputType: string): ParameterDefault { + const trimmed = rawValue.trim(); + // An empty `default:` is an explicit empty string, not an absent default โ€” absent inputs are marked required. + if (trimmed.length === 0) { + return ''; + } + if (inputType === 'string') { + return trimmed.replace(/^["']|["']$/g, '').trim(); + } + return parseScalar(trimmed); +} + +/** + * Parse one `options:` entry into the value YAML says it is. + * + * Kept in step with {@link parseDefaultValue}: an entry and a default that read the same in the spec must produce + * the same value, or a `default: false` never matches the `false` in `options: [true, false]` and fails to + * pre-select. A `string` input โ€” declared or by omission โ€” keeps entries literal for the same reason defaults do. + * + * @param entry - One option's raw text, quotes and surrounding whitespace included. + * @param inputType - The input's resolved `type:`; `'string'` when the spec omits it. + * @returns The entry as a string, number, or boolean. + */ +function parseOptionEntry(entry: string, inputType: string): string | number | boolean { + const trimmed = entry.trim(); + if (inputType === 'string') { + return trimmed.replace(/^["']|["']$/g, '').trim(); + } + const parsed = parseScalar(trimmed); + // `options:` entries are scalars; a null or nested-array entry isn't meaningful, so keep those as their text. + return parsed === null || Array.isArray(parsed) ? trimmed.replace(/^["']|["']$/g, '').trim() : parsed; +} + export interface ComponentVariable { name: string; description: string; required: boolean; type: string; - default?: string; - /** Allowed values from the input's `options:` list, in declaration order; absent when no `options:` is given. */ - options?: string[]; + /** + * The input's `default:`, as the value YAML says it is โ€” `default: false` is the boolean `false`, not `"false"`. + * Consumers render it back to YAML by type, so a string default here must be a genuine string. + */ + default?: ParameterDefault; + /** + * Allowed values from the input's `options:` list, in declaration order; absent when no `options:` is given. + * Entries carry their YAML types, so they compare equal to a `default` that names one of them. + */ + options?: Array; } export interface ParsedSpec { @@ -26,11 +106,12 @@ export interface ParsedSpec { * Parse the inline form of an `options:` value (`options: [a, "b", c]`). * * Returns an empty array for the expanded form (`options:` with the values on following `- item` lines), which the - * caller then fills in as it reads those lines. Surrounding brackets and per-entry quotes are stripped; blank entries - * (e.g. a trailing comma) are dropped. + * caller then fills in as it reads those lines. Surrounding brackets are stripped and blank entries (e.g. a trailing + * comma) are dropped, but each entry stays raw text โ€” {@link parseOptionEntry} types it once the input's `type:` is + * known, which may be declared after `options:`. * * @param rawValue - The text after `options:` on the same line, e.g. `[a, "b", c]` (or empty for the expanded form). - * @returns The parsed option values, or an empty array when the value isn't an inline `[...]` list. + * @returns The raw option entries, or an empty array when the value isn't an inline `[...]` list. */ function parseInlineOptions(rawValue: string): string[] { if (!rawValue.startsWith('[')) { @@ -39,7 +120,7 @@ function parseInlineOptions(rawValue: string): string[] { return rawValue .replace(/^\[|\]$/g, '') .split(',') - .map(entry => entry.trim().replace(/^["']|["']$/g, '').trim()) + .map(entry => entry.trim()) .filter(entry => entry.length > 0); } @@ -146,6 +227,35 @@ export class GitLabSpecParser { .filter(line => line.trim() && !line.trim().startsWith('#')); let currentInput: ComponentVariable | null = null; + // Indentation of the first input name seen, which every sibling input shares. Input names and their own keys are + // told apart by depth rather than by name: an input may legitimately be called `type` or `default`, and a spec + // indented `inputs:` at column 0 puts both at four spaces. + let inputIndent: number | null = null; + // The `default:` text for `currentInput`, held until the input ends so the declared `type:` can steer the parse. + let rawDefault: string | null = null; + // Raw `options:` entries for `currentInput`, typed by `finalizeInput` for the same reason as `rawDefault`. + let rawOptions: string[] | null = null; + + /** + * Resolve the pending `default:` and `options:` against the declared type and mark a defaultless input + * required. Deferred to here because `type:` may be declared after either of them. + */ + const finalizeInput = (input: ComponentVariable): ComponentVariable => { + // An omitted `type:` is `string` to GitLab, and `input.type` already holds that fallback. + if (rawDefault !== null) { + input.default = parseDefaultValue(rawDefault, input.type); + } else { + // GitLab CI/CD component behavior: an input with no default is required. + input.required = true; + } + if (rawOptions !== null) { + // Typed against the input's type so an entry matches a `default` naming the same value. + input.options = rawOptions.map(entry => parseOptionEntry(entry, input.type)); + } + rawDefault = null; + rawOptions = null; + return input; + }; for (const line of inputLines) { const trimmedLine = line.trim(); @@ -157,19 +267,24 @@ export class GitLabSpecParser { break; } + const indent = line.length - line.trimStart().length; + // New input parameter (indented under inputs) - handle both 2-space and 4-space indentation. // Match lines like " name:" where the input name ends with ":" and has only whitespace after. // The name class includes `-`: GitLab input names are commonly hyphenated (e.g. `job-name`). Without // it, a hyphenated key isn't recognised as a new input, so its `description:`/`default:` lines bleed // onto the previous (non-hyphenated) input and mis-map every field after it (issue #211). - if (line.match(/^\s{2,4}[a-zA-Z_][a-zA-Z0-9_-]*:\s*$/)) { + // + // Siblings must share the first input's indentation. A valueless `default:` under a spec indented `inputs:` + // at column 0 sits at four spaces and matches the shape of an input name, so without the depth check it + // opens a phantom input named `default` and swallows the real input's value. Depth rather than a list of + // reserved key names, because `type`, `default` and `options` are all legal input names. + const looksLikeInputName = /^\s{2,4}[a-zA-Z_][a-zA-Z0-9_-]*:\s*$/.test(line); + if (looksLikeInputName && (inputIndent === null || indent === inputIndent)) { + inputIndent = indent; // If we have a current input, finalize it before starting a new one if (currentInput) { - // Mark as required if no default was specified (GitLab CI/CD component behavior) - if (currentInput.default === undefined) { - currentInput.required = true; - } - extractedVariables.push(currentInput); + extractedVariables.push(finalizeInput(currentInput)); } const inputName = trimmedLine.split(':')[0]; currentInput = { @@ -181,32 +296,30 @@ export class GitLabSpecParser { }; logger.debug(`${logPrefix} Found input parameter: ${inputName}`, 'SpecParser'); } - // Property of current input (more deeply indented) - handle 4+ spaces of indentation - else if (currentInput && line.match(/^\s{4,}/)) { + // Property of the current input: anything indented deeper than the input names themselves. + else if (currentInput && inputIndent !== null && indent > inputIndent) { if (trimmedLine.startsWith('description:')) { currentInput.description = trimmedLine.substring(12).replace(/^["']|["']$/g, '').trim(); } else if (trimmedLine.startsWith('default:')) { - currentInput.default = trimmedLine.substring(8).replace(/^["']|["']$/g, '').trim(); + // Kept as text until the input is complete: `type:` may follow `default:`, and the declared type decides + // whether the value is parsed as YAML or kept literal. Resolved by `finalizeInput`. + rawDefault = trimmedLine.substring(8); } else if (trimmedLine.startsWith('type:')) { currentInput.type = trimmedLine.substring(5).replace(/^["']|["']$/g, '').trim(); } else if (trimmedLine.startsWith('options:')) { // Open the options list. An inline form (`options: [a, b]`) carries its values on the same line; // the expanded form leaves them for the `- item` lines below. - currentInput.options = parseInlineOptions(trimmedLine.substring(8).trim()); - } else if (trimmedLine.startsWith('- ') && currentInput.options) { + rawOptions = parseInlineOptions(trimmedLine.substring(8).trim()); + } else if (trimmedLine.startsWith('- ') && rawOptions) { // Expanded list item belonging to the open `options:` block. - currentInput.options.push(trimmedLine.substring(2).replace(/^["']|["']$/g, '').trim()); + rawOptions.push(trimmedLine.substring(2).trim()); } } } // Add the last input if (currentInput) { - // Mark as required if no default was specified (GitLab CI/CD component behavior) - if (currentInput.default === undefined) { - currentInput.required = true; - } - extractedVariables.push(currentInput); + extractedVariables.push(finalizeInput(currentInput)); } logger.debug(`${logPrefix} Extracted ${extractedVariables.length} input parameters from spec`, 'SpecParser'); @@ -274,7 +387,8 @@ export class GitLabSpecParser { description: `Parameter: ${varName}`, required: false, type: 'string', - default: defaultValue || undefined + // The legacy format declares no per-variable type, so values stay the text they appear as. + default: defaultValue ? parseDefaultValue(defaultValue, 'string') : undefined }; }); diff --git a/src/providers/completionInputContext.ts b/src/providers/completionInputContext.ts index f1e089de..9ff7b962 100644 --- a/src/providers/completionInputContext.ts +++ b/src/providers/completionInputContext.ts @@ -7,7 +7,7 @@ import { parseYaml, parseYamlDocuments, findDocumentWith, isYamlNode, type YamlNode } from '../utils/yamlParser'; import { findIncludeLine } from '../utils/includeMatcher'; -import type { ComponentParameter } from '../types/git-component'; +import type { ComponentParameter, ParameterDefault } from '../types/git-component'; /** * The completion slot a YAML cursor position resolves to. @@ -324,6 +324,22 @@ export function renderOptionValue(value: string | number | boolean): string { return typeof value === 'string' ? quoteYamlIfUnsafe(value) : String(value); } +/** + * Render an input's `default` as the YAML text to insert for it. + * + * Arrays become flow sequences (`[a, b]`); strings are bare or double-quoted by round-trip safety; everything else + * (booleans, numbers, `null`) is its bare scalar form, so a `false` default inserts as `false` and not `"false"`. + * + * @param value - The declared default for the input. + * @returns The YAML text for that value. + */ +export function renderDefaultValue(value: ParameterDefault): string { + if (Array.isArray(value)) { + return `[${value.map((v) => (typeof v === 'string' ? quoteYamlIfUnsafe(v, true) : String(v))).join(', ')}]`; + } + return typeof value === 'string' ? quoteYamlIfUnsafe(value) : String(value); +} + /** * Narrow a parameter default to the scalar shapes an `options:` entry can take (string/number/boolean), excluding * the `null` and array forms a default may also hold. @@ -335,6 +351,28 @@ function isOptionScalar(value: unknown): value is string | number | boolean { return typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean'; } +/** + * The values an input is allowed to take, if that set is known and finite. + * + * An explicit `options:` list is used as declared. A `boolean` input has no `options:` in the spec but is still a + * closed two-value enum, so it yields `true, false` โ€” conventional reading order, which is what a reader scanning + * the dropdown expects. A declared default is floated to the front by the caller, so it still pre-selects. + * + * Shared by both completion slots so the input-name snippet and the value-slot dropdown always agree. + * + * @param param - The input being completed. + * @returns The allowed values, or `undefined` when the input accepts free-form text. + */ +export function allowedValuesFor(param: ComponentParameter): Array | undefined { + if (param.options && param.options.length > 0) { + return param.options; + } + if (param.type === 'boolean') { + return [true, false]; + } + return undefined; +} + /** * Build the value portion of the snippet inserted after `param.name: ` when an input is accepted from completion. * @@ -343,20 +381,24 @@ function isOptionScalar(value: unknown): value is string | number | boolean { * Values are inserted bare where a bare YAML scalar round-trips to the same string โ€” GitLab CI parses a bare scalar * by the input's declared type, so a string input is a bare scalar, not a quoted one. Strings that bare YAML would * reinterpret (indicators, embedded `: `/` #`, type-like tokens, etc.) are double-quoted; see {@link quoteYamlIfUnsafe}. - * Precedence: an `options:` enum becomes a `${1|...|}` choice (with the default, if any, pre-selected first) so the - * allowed values stay one keystroke away; otherwise an explicit `default` is rendered as the YAML it represents; - * otherwise a type-appropriate placeholder. + * Precedence: an `options:` enum โ€” or a `boolean` input, which is a closed two-value enum โ€” becomes a `${1|...|}` + * choice (with the default, if any, pre-selected first) so the allowed values stay one keystroke away; otherwise an + * explicit `default` is rendered as the YAML it represents; otherwise a type-appropriate placeholder. * * @param param - The input parameter spec (type, optional default, optional `options` enum, requiredness). * @returns The snippet body to insert after `param.name: ` โ€” a `${1|...|}` choice, a rendered value, or a `${1:...}` placeholder. */ export function buildInputInsertValue(param: ComponentParameter): string { - if (param.options && param.options.length > 0) { - // Offer the allowed values (`options:`) as a choice. Entries stay unquoted so a number/boolean option isn't + // Includes a `boolean` input's implicit true/false. Falling through to the default-rendering branch below would + // pre-fill the default with no alternatives shown. + const options = allowedValuesFor(param); + + if (options && options.length > 0) { + // Offer the allowed values as a choice. Entries stay unquoted so a number/boolean option isn't // turned into a string; string entries are quoted only when bare YAML would reinterpret them. When the input // also has a default, float the matching option to the front โ€” VS Code pre-selects the first choice entry, so // accepting the input keeps the default while leaving the alternatives one arrow-key away. - const rendered = param.options.map(renderOptionValue); + const rendered = options.map(renderOptionValue); // Only a scalar default can name one of the options; a null or array default has no matching entry. const defaultRendered = isOptionScalar(param.default) ? renderOptionValue(param.default) : undefined; const ordered = @@ -367,17 +409,11 @@ export function buildInputInsertValue(param: ComponentParameter): string { } if (param.default !== undefined) { - // Render the default as the YAML the input expects: arrays as flow sequences (`[a, b]`), - // strings bare-or-quoted by round-trip safety, everything else as its bare scalar form. - if (Array.isArray(param.default)) { - return `[${param.default.map((v) => (typeof v === 'string' ? quoteYamlIfUnsafe(v, true) : String(v))).join(', ')}]`; - } - return typeof param.default === 'string' ? quoteYamlIfUnsafe(param.default) : String(param.default); + return renderDefaultValue(param.default); } switch (param.type) { - case 'boolean': - return param.required ? '${1|true,false|}' : '${1|false,true|}'; + // `boolean` is handled above as a two-value choice, with or without a default. case 'number': return '${1:0}'; case 'integer': diff --git a/src/providers/completionProvider.ts b/src/providers/completionProvider.ts index 084d3f1a..4e8f9c57 100755 --- a/src/providers/completionProvider.ts +++ b/src/providers/completionProvider.ts @@ -1,11 +1,14 @@ import * as vscode from 'vscode'; -import { getComponentUnderCursor, getGitRepositoryContext } from './componentDetector'; +import { createReferenceResolver, getComponentUnderCursor, resolveServerFqdn } from './componentDetector'; import { getComponentCacheManager } from '../services/cache/componentCacheManager'; -import { getVariableCompletions, containsGitLabVariables, expandComponentUrl } from '../utils/gitlabVariables'; +import { getVariableCompletions } from '../utils/gitlabVariables'; +import { buildComponentReference, parseVersionCompletionPrefix } from '../utils/componentReference'; import { Logger } from '../utils/logger'; import { isGitLabCIFile } from '../utils/gitlabCiFileMatcher'; import { resolveLocalComponent } from './localComponentResolver'; -import { findCompletionInputContextAtLine, buildInputInsertValue, renderOptionValue } from './completionInputContext'; +import { chooseComponentVersion } from './componentBrowserTransform'; +import { readVersionPreferences } from './versionPreferenceSettings'; +import { findCompletionInputContextAtLine, buildInputInsertValue, renderOptionValue, allowedValuesFor } from './completionInputContext'; import type { ComponentParameter } from '../types/git-component'; import type { CachedComponent } from '../types/cache'; @@ -39,17 +42,17 @@ export class CompletionProvider implements vscode.CompletionItemProvider { // Check for version completions after @ this.logger.debug(`[CompletionProvider] Checking for version pattern in line prefix: "${linePrefix}"`, 'CompletionProvider'); - const versionMatch = linePrefix.match(/https:\/\/[^@\s]+@(.*)$/); + const versionMatch = parseVersionCompletionPrefix(linePrefix); this.logger.debug(`[CompletionProvider] Version regex match result: ${versionMatch ? 'MATCHED' : 'NO MATCH'}`, 'CompletionProvider'); if (versionMatch) { this.logger.debug(`[CompletionProvider] Detected version completion request after @`, 'CompletionProvider'); - return this.provideVersionCompletions(linePrefix); + return this.provideVersionCompletions(linePrefix, document.uri); } // Suggest components after "component: " if (linePrefix.trim().endsWith('component:') || linePrefix.trim().endsWith('component: ')) { this.logger.debug(`[CompletionProvider] Detected component completion request`, 'CompletionProvider'); - return this.provideComponentCompletions(); + return this.provideComponentCompletions(document); } // Detect if we're in a component and suggest parameters @@ -69,30 +72,31 @@ export class CompletionProvider implements vscode.CompletionItemProvider { /** * Provide version/tag completions for a component URL after @ */ - private async provideVersionCompletions(linePrefix: string): Promise { + private async provideVersionCompletions(linePrefix: string, forUri: vscode.Uri): Promise { this.logger.debug(`[CompletionProvider] Starting version completions for: "${linePrefix}"`, 'CompletionProvider'); // Extract the component URL before the @ - const urlMatch = linePrefix.match(/(https:\/\/[^@\s]+)@(.*)$/); + const urlMatch = parseVersionCompletionPrefix(linePrefix); if (!urlMatch) { this.logger.warn(`[CompletionProvider] Could not parse component URL from line prefix`, 'CompletionProvider'); return []; } - const componentUrlBase = urlMatch[1]; - const currentVersionInput = urlMatch[2]; + const componentUrlBase = urlMatch.base; + const currentVersionInput = urlMatch.partialVersion; this.logger.debug(`[CompletionProvider] Component URL base: ${componentUrlBase}`, 'CompletionProvider'); this.logger.debug(`[CompletionProvider] Current version input: "${currentVersionInput}"`, 'CompletionProvider'); - // Parse the component URL to extract GitLab instance, project path, and component/template name - // Accepts URLs like: - // https://gitlab.com/components/opentofu/full-pipeline - // https://gitlab.instance.com/group/project/componentName - // https://gitlab.instance.com/group/project/templateName - // We'll treat the last path segment as the component/template name, and the rest as the project path + const resolved = await createReferenceResolver(forUri)(componentUrlBase); + if (!resolved.resolved) { + this.logger.debug(`[CompletionProvider] Can't resolve GitLab variables for version completion: ${componentUrlBase}`, 'CompletionProvider'); + return []; + } + + // The last path segment is the component/template name; the rest is the project path. try { - const url = new URL(componentUrlBase); + const url = new URL(resolved.url); const gitlabInstance = url.host; const pathSegments = url.pathname.split('/').filter(Boolean); // remove empty segments if (pathSegments.length < 2) { @@ -141,8 +145,13 @@ export class CompletionProvider implements vscode.CompletionItemProvider { const filteredVersions = availableVersions.filter(version => version.toLowerCase().includes(currentVersionInput.toLowerCase()) ); + // The version the component would be inserted with leads the list, so the 10-entry cap never drops it. + const chosenVersion = chooseComponentVersion(availableVersions, targetComponent, readVersionPreferences(), 'main'); + const orderedVersions = filteredVersions.includes(chosenVersion) + ? [chosenVersion, ...filteredVersions.filter(version => version !== chosenVersion)] + : filteredVersions; // Limit to top 10 versions to avoid overwhelming the user - const versionsToShow = filteredVersions.slice(0, 10); + const versionsToShow = orderedVersions.slice(0, 10); for (const version of versionsToShow) { const item = new vscode.CompletionItem(version, vscode.CompletionItemKind.Reference); item.detail = `Version ${version}`; @@ -150,12 +159,15 @@ export class CompletionProvider implements vscode.CompletionItemProvider { // Set the insertion text to just the version (since we're after the @) item.insertText = version; // Add sort priority based on version type - if (version === 'main' || version === 'master') { - item.sortText = '0' + version; // High priority for main branches + if (version === chosenVersion) { + item.sortText = '0' + version; + item.preselect = true; + } else if (version === 'main' || version === 'master') { + item.sortText = '1' + version; // High priority for main branches } else if (version.match(/^\d+\.\d+\.\d+$/)) { - item.sortText = '1' + version; // Medium priority for semantic versions + item.sortText = '2' + version; // Medium priority for semantic versions } else { - item.sortText = '2' + version; // Lower priority for other versions + item.sortText = '3' + version; // Lower priority for other versions } completionItems.push(item); } @@ -170,7 +182,7 @@ export class CompletionProvider implements vscode.CompletionItemProvider { /** * Provide component completions after "component: " */ - private async provideComponentCompletions(): Promise { + private async provideComponentCompletions(document: vscode.TextDocument): Promise { this.logger.debug(`[CompletionProvider] Providing component completions`, 'CompletionProvider'); const cacheManager = getComponentCacheManager(); @@ -180,6 +192,8 @@ export class CompletionProvider implements vscode.CompletionItemProvider { const completionItems: vscode.CompletionItem[] = []; const seenComponents = new Set(); + const preferences = readVersionPreferences(); + const serverFqdn = await resolveServerFqdn(document.uri); for (const component of components) { // Create a unique key for each component to avoid duplicates @@ -190,14 +204,16 @@ export class CompletionProvider implements vscode.CompletionItemProvider { } seenComponents.add(componentKey); - // Get the best version to suggest - let bestVersion = 'main'; - if (component.availableVersions && component.availableVersions.length > 0) { - // Find the best version using priority logic - bestVersion = this.getBestVersionForComponent(component.availableVersions, component.name); - } + const bestVersion = chooseComponentVersion(component.availableVersions ?? [], component, preferences, 'main'); - let componentUrl = `https://${component.gitlabInstance}/${component.sourcePath}/${component.name}`; + // Suggest the best version; the user can change it afterwards. + const componentUrl = buildComponentReference( + component.gitlabInstance, + component.sourcePath, + component.name, + bestVersion, + serverFqdn, + ); const item = new vscode.CompletionItem(component.name, vscode.CompletionItemKind.Module); item.detail = `Component from ${component.source}`; @@ -217,14 +233,6 @@ export class CompletionProvider implements vscode.CompletionItemProvider { item.documentation = new vscode.MarkdownString(documentation); - // For now, suggest the URL with the best version - user can change the version later - if (componentUrl.includes('@')) { - const urlBase = componentUrl.split('@')[0]; - componentUrl = `${urlBase}@${bestVersion}`; - } else { - componentUrl = `${componentUrl}@${bestVersion}`; - } - item.insertText = componentUrl; completionItems.push(item); } @@ -233,69 +241,6 @@ export class CompletionProvider implements vscode.CompletionItemProvider { return completionItems; } - /** - * Get the best version for a component based on priority logic - */ - private getBestVersionForComponent(availableVersions: string[], componentName: string): string { - if (!availableVersions || availableVersions.length === 0) { - return 'main'; - } - - // Check user preferences first - const config = vscode.workspace.getConfiguration('gitlabComponentHelper'); - const defaultVersions = config.get>('defaultVersions', {}); - const alwaysLatest = config.get('alwaysUseLatest', []); - - if (alwaysLatest.includes(componentName)) { - // User wants always latest - find the highest semantic version or fall back to main - const semanticVersions = availableVersions.filter(v => v.match(/^\d+\.\d+\.\d+$/)); - if (semanticVersions.length > 0) { - // Sort semantic versions in descending order - semanticVersions.sort((a, b) => { - const aParts = a.split('.').map(Number); - const bParts = b.split('.').map(Number); - for (let i = 0; i < 3; i++) { - if (aParts[i] !== bParts[i]) { - return bParts[i] - aParts[i]; - } - } - return 0; - }); - return semanticVersions[0]; - } - } - - if (defaultVersions[componentName] && availableVersions.includes(defaultVersions[componentName])) { - return defaultVersions[componentName]; - } - - // Default priority: main > master > highest semantic version > first available - if (availableVersions.includes('main')) { - return 'main'; - } - if (availableVersions.includes('master')) { - return 'master'; - } - - // Find highest semantic version - const semanticVersions = availableVersions.filter(v => v.match(/^\d+\.\d+\.\d+$/)); - if (semanticVersions.length > 0) { - semanticVersions.sort((a, b) => { - const aParts = a.split('.').map(Number); - const bParts = b.split('.').map(Number); - for (let i = 0; i < 3; i++) { - if (aParts[i] !== bParts[i]) { - return bParts[i] - aParts[i]; - } - } - return 0; - }); - return semanticVersions[0]; - } - - return availableVersions[0]; - } - private provideParameterCompletions(parameters: ComponentParameter[]): vscode.CompletionItem[] { return parameters.map(param => { const item = new vscode.CompletionItem(param.name, vscode.CompletionItemKind.Property); @@ -389,16 +334,21 @@ export class CompletionProvider implements vscode.CompletionItemProvider { // it also declares a default โ€” the default is just the pre-filled choice, not a reason to hide the others. if (context.slot === 'value') { const param = component.parameters.find((p: ComponentParameter) => p.name === context.inputName); - if (!param?.options?.length) { + // A `boolean` input is a closed two-value enum, so offer `true`/`false` even though it declares no `options:`. + const values = param ? allowedValuesFor(param) : undefined; + if (!values?.length) { this.logger.debug(`[CompletionProvider] Value slot for ${context.inputName} has no options to offer`, 'CompletionProvider'); return null; } - return param.options.map((value, index) => { + return values.map((value, index) => { const rendered = renderOptionValue(value); const item = new vscode.CompletionItem(String(value), vscode.CompletionItemKind.EnumMember); item.insertText = rendered; - item.detail = `${param.type || 'string'} option`; - // Preserve the declared order of `options:` in the dropdown. + // Flag the declared default rather than reordering around it โ€” the list stays in a stable, scannable + // order (`true` before `false`, or the spec's own `options:` order) whatever the default happens to be. + const isDefault = param?.default !== undefined && param.default === value; + item.detail = `${param?.type || 'string'} option${isDefault ? ' (default)' : ''}`; + // Preserve the declared order of the allowed values in the dropdown. item.sortText = String(index).padStart(4, '0'); return item; }); @@ -443,32 +393,19 @@ export class CompletionProvider implements vscode.CompletionItemProvider { // Helper method to find component in cache (similar to validation provider). // `forUri` is the active document's URI โ€” used so variable expansion picks // the GitLab host matching the file's containing repo, not workspace[0]. - private async findComponentInCache(componentUrl: string, forUri?: vscode.Uri): Promise { + private async findComponentInCache(componentUrl: string, forUri: vscode.Uri): Promise { try { const cacheManager = getComponentCacheManager(); const components = await cacheManager.getComponents(); - // Expand GitLab variables (e.g. $CI_SERVER_FQDN) before parsing, otherwise - // `new URL()` below throws and we never find the component in the cache. - let resolvedUrl = componentUrl; - if (containsGitLabVariables(componentUrl)) { - const gitContext = await getGitRepositoryContext(forUri); - if (gitContext.gitlabInstance) { - resolvedUrl = expandComponentUrl(componentUrl, { - gitlabInstance: gitContext.gitlabInstance, - projectPath: gitContext.projectPath, - serverUrl: `https://${gitContext.gitlabInstance}`, - commitSha: gitContext.commitSha || 'main' - }); - this.logger.debug(`[CompletionProvider] Expanded component URL with variables: ${componentUrl} -> ${resolvedUrl}`, 'CompletionProvider'); - } else { - this.logger.debug(`[CompletionProvider] Component URL contains GitLab variables but no Git context available to expand: ${componentUrl}`, 'CompletionProvider'); - return null; - } + const resolved = await createReferenceResolver(forUri)(componentUrl); + if (!resolved.resolved) { + this.logger.debug(`[CompletionProvider] Can't resolve GitLab variables in component URL: ${componentUrl}`, 'CompletionProvider'); + return null; } // Parse the component URL to get instance, project path, and component name - const url = new URL(resolvedUrl.split('@')[0]); // Remove version if present + const url = new URL(resolved.url.split('@')[0]); // Remove version if present const gitlabInstance = url.host; const pathSegments = url.pathname.split('/').filter(Boolean); diff --git a/src/providers/componentBrowserGenerate.ts b/src/providers/componentBrowserGenerate.ts index e4282e0e..38336368 100644 --- a/src/providers/componentBrowserGenerate.ts +++ b/src/providers/componentBrowserGenerate.ts @@ -4,6 +4,7 @@ * inside the unit suite. */ +import { buildComponentReference } from '../utils/componentReference'; import { containsGitLabVariables } from '../utils/gitlabVariables'; /** @@ -47,7 +48,8 @@ type ExistingComponent = { inputs?: Record }; * - If `component.originalUrl` contains GitLab variables (e.g. `${CI_SERVER_FQDN}`), use it verbatim and either * append `@version` or replace the existing trailing `@โ€ฆ` with the new version. This preserves user-written * variable expressions on round-trip. - * - Otherwise rebuild the URL from `gitlabInstance`, `sourcePath`, `name`, and `version`. + * - Otherwise rebuild the reference from `gitlabInstance`, `sourcePath`, `name`, and `version`, without a scheme โ€” + * GitLab rejects `https://` in a `component:` value. A component on `serverFqdn` is written as `$CI_SERVER_FQDN/โ€ฆ`. * * Inputs strategy: * - With no `selectedInputs` and `includeInputs === false`, emit no `inputs:` section. @@ -62,6 +64,8 @@ type ExistingComponent = { inputs?: Record }; * @param selectedInputs Names of inputs to keep when editing โ€” only these will appear in the `inputs:` block. * @param existingComponent Previous inputs to preserve verbatim during an edit; defaults are only used for newly * selected inputs that weren't already set. + * @param serverFqdn GitLab host of the target file's repository (from its git remote), or `undefined` when the + * file isn't in a GitLab repository. * @returns YAML snippet ready to splice into a `.gitlab-ci.yml` `include:` list. */ export function generateComponentText( @@ -69,6 +73,7 @@ export function generateComponentText( includeInputs: boolean, selectedInputs: string[] = [], existingComponent: ExistingComponent | null = null, + serverFqdn?: string, ): string { const gitlabInstance = component.gitlabInstance || 'gitlab.com'; @@ -81,7 +86,13 @@ export function generateComponentText( componentUrl = component.originalUrl.replace(/@[^@]*$/, `@${component.version}`); } } else { - componentUrl = `https://${gitlabInstance}/${component.sourcePath}/${component.name}@${component.version}`; + componentUrl = buildComponentReference( + gitlabInstance, + component.sourcePath ?? '', + component.name, + component.version, + serverFqdn, + ); } let insertion = ` - component: ${componentUrl}`; diff --git a/src/providers/componentBrowserProvider.ts b/src/providers/componentBrowserProvider.ts index 4d93a058..6a63baa9 100644 --- a/src/providers/componentBrowserProvider.ts +++ b/src/providers/componentBrowserProvider.ts @@ -3,18 +3,22 @@ import { getComponentService } from '../services/component'; import { ComponentCacheManager } from '../services/cache/componentCacheManager'; import { GitLabCatalogComponent, GitLabCatalogVariable } from '../types/gitlab-catalog'; import type { ComponentParameter, Component } from './componentDetector'; -import type { CachedComponent } from '../types/cache'; +import { resolveServerFqdn } from './componentDetector'; +import { isVersionLookupShape } from '../services/component/versionLookupShape'; import type { SourceGroup, ComponentGroup, ComponentVersion } from './componentBrowserTypes'; import type { HoverContext } from './hoverContentBuilder'; -import { containsGitLabVariables } from '../utils/gitlabVariables'; import { Logger } from '../utils/logger'; import { templateFileUrlForResolved } from '../utils/templateFileUrl'; import { escapeHtml, renderInlineMarkdown } from '../webview/inlineMarkdown'; import { serializeForScript } from '../webview/scriptData'; import { generateComponentText } from './componentBrowserGenerate'; import { findComponentLineRange, parseExistingComponentText } from './componentBrowserEdit'; -import { transformCachedComponentsToGroups } from './componentBrowserTransform'; -import { compileTagTemplate, stripTagPrefix } from '../services/component/tagScoping'; +import { chooseComponentVersion, transformCachedComponentsToGroups } from './componentBrowserTransform'; +import { LATEST_VERSION_PREFERENCE, versionPreferenceKey } from './versionPreferences'; +import { readVersionPreferences, saveVersionPreference } from './versionPreferenceSettings'; +import { buildVersionLabels, compileTagTemplate, stripTagPrefix } from '../services/component/tagScoping'; +import { assetRoots, assetUri, createNonce, cspMetaTag } from '../webview/webviewHtml'; +import { safeHttpUrl } from '../webview/safeUrl'; /** * Component shape carried through the detach-hover webview's "Open in Detailed View" round trip. @@ -24,18 +28,21 @@ import { compileTagTemplate, stripTagPrefix } from '../services/component/tagSco */ type DetachableComponent = Component & { _hoverContext?: HoverContext }; -/** - * Type-guard narrowing a `Component`-shaped value to one that also satisfies `CachedComponent`. - * `Component` carries `source`/`sourcePath`/`gitlabInstance`/`version`/`url` as optional; cache - * methods like `fetchComponentVersions` require them. The guard checks all five before the call so - * we don't pass a half-populated `Component` into a function expecting the full cache shape. - */ -function isCachedComponentShape(component: Component): component is Component & CachedComponent { - return typeof component.source === 'string' - && typeof component.sourcePath === 'string' - && typeof component.gitlabInstance === 'string' - && typeof component.version === 'string' - && typeof component.url === 'string'; +/** Per-entry-point behaviour for the shared details-panel message handler. */ +interface DetailsPanelOptions { + /** + * Set by the detached (hover) entry point to the editor the panel was opened from. Two effects, both of which + * exist because that entry point constructs its own provider rather than going through `show()`: + * + * 1. The editor is adopted as this provider's insertion target at registration, since nothing else has populated + * it and `insertComponent` refuses to insert without one. + * 2. The panel is disposed once an insert completes โ€” it is a one-shot view, where the Component Browser's own + * details panel stays open. + * + * Refocusing the target editor is not one of them: `insertComponent` and `editExistingComponentFromDetached` each + * focus and verify their own document, on both entry points. + */ + detachedFrom?: vscode.TextEditor; } /** @@ -87,14 +94,12 @@ export class ComponentBrowserProvider { { enableScripts: true, retainContextWhenHidden: true, - localResourceRoots: [ - vscode.Uri.joinPath(this.context.extensionUri, 'media') - ] + localResourceRoots: assetRoots(this.context.extensionUri) } ); // Set initial HTML content with loading message - this.panel.webview.html = this.getLoadingHtml(); + this.panel.webview.html = this.getLoadingHtml(this.panel.webview); // Handle panel disposal this.panel.onDidDispose(() => { @@ -140,10 +145,10 @@ export class ComponentBrowserProvider { await this.fetchAndCacheVersion(message.componentName, message.sourcePath, message.gitlabInstance, message.version); return; case 'setDefaultVersion': - await this.setDefaultVersion(message.componentName, message.version); + await this.setDefaultVersion(message); return; case 'setAlwaysUseLatest': - await this.setAlwaysUseLatest(message.componentName); + await this.setAlwaysUseLatest(message); return; case 'expandComponent': await this.handleComponentExpand(message.componentName, message.projectId); @@ -165,7 +170,7 @@ export class ComponentBrowserProvider { try { // Show loading state - this.panel.webview.html = this.getLoadingHtml(); + this.panel.webview.html = this.getLoadingHtml(this.panel.webview); this.logger.debug(`[ComponentBrowser] Loading components, forceRefresh: ${forceRefresh}`, 'ComponentBrowser'); @@ -188,8 +193,11 @@ export class ComponentBrowserProvider { this.logger.debug('[ComponentBrowser] Components loaded, versions will be fetched on demand', 'ComponentBrowser'); // Transform cached components to component groups format - const allComponents = transformCachedComponentsToGroups(cachedComponents, (comp, reason) => - this.logger.warn(`[ComponentBrowser] Skipping component (${reason}): ${JSON.stringify(comp)}`, 'ComponentBrowser'), + const allComponents = transformCachedComponentsToGroups( + cachedComponents, + (comp, reason) => + this.logger.warn(`[ComponentBrowser] Skipping component (${reason}): ${JSON.stringify(comp)}`, 'ComponentBrowser'), + readVersionPreferences(), ); const cacheErrors = Object.fromEntries(sourceErrors); @@ -320,13 +328,13 @@ export class ComponentBrowserProvider { // If no sources configured and no components in cache, show guidance if (sources.length === 0 && allComponents.length === 0) { - this.panel.webview.html = this.getNoSourcesHtml(); + this.panel.webview.html = this.getNoSourcesHtml(this.panel.webview); return; } // If no components found but we have cache errors, show errors if (allComponents.length === 0 && Object.keys(cacheErrors).length > 0) { - this.panel.webview.html = this.getErrorsHtml(cacheErrors); + this.panel.webview.html = this.getErrorsHtml(this.panel.webview, cacheErrors); return; } @@ -348,11 +356,11 @@ export class ComponentBrowserProvider { this.logger.debug(`[ComponentBrowser] Filtered errors: ${Object.keys(filteredErrors).length} of ${Object.keys(cacheErrors).length}`, 'ComponentBrowser'); - this.panel.webview.html = this.getComponentBrowserHtml(allComponents, filteredErrors); + this.panel.webview.html = this.getComponentBrowserHtml(this.panel.webview, allComponents, filteredErrors); } catch (error) { this.logger.error(`[ComponentBrowser] Error in loadComponents: ${error}`, 'ComponentBrowser'); if (this.panel) { - this.panel.webview.html = this.getErrorHtml(error); + this.panel.webview.html = this.getErrorHtml(this.panel.webview, error); } } } @@ -377,90 +385,10 @@ export class ComponentBrowserProvider { return; } - // Use the GitLab instance from the component or default to gitlab.com - const gitlabInstance = component.gitlabInstance || 'gitlab.com'; - - // Create the component reference - // Check if we should preserve GitLab variables in the URL - let componentUrl: string; - - // If the component has a preserved URL with variables, use that - if (component.originalUrl && containsGitLabVariables(component.originalUrl)) { - componentUrl = component.originalUrl; - // Update version if different - if (component.version && !component.originalUrl.includes('@')) { - componentUrl += `@${component.version}`; - } else if (component.version && component.originalUrl.includes('@')) { - componentUrl = component.originalUrl.replace(/@[^@]*$/, `@${component.version}`); - } - } else { - // Create standard URL - componentUrl = `https://${gitlabInstance}/${component.sourcePath}/${component.name}@${component.version}`; - } - - let insertion = ` - component: ${componentUrl}`; - - // Add inputs if requested and component has parameters - if (includeInputs && component.parameters && component.parameters.length > 0) { - insertion += '\n inputs:'; - - // Determine which parameters to include - let parametersToInclude = component.parameters; - if (selectedInputs && selectedInputs.length > 0) { - // Only include specifically selected inputs - parametersToInclude = component.parameters.filter(param => selectedInputs.includes(param.name)); - } - - for (const param of parametersToInclude) { - let defaultValue = param.default; - - // Format default value based on type - if (defaultValue !== undefined) { - if (typeof defaultValue === 'string') { - // Check if it contains GitLab variables and preserve them - if (containsGitLabVariables(defaultValue)) { - defaultValue = `"${defaultValue}"`; // Keep variables as-is in quotes - } else { - defaultValue = `"${defaultValue}"`; - } - } else if (typeof defaultValue === 'boolean') { - defaultValue = defaultValue.toString(); - } else if (typeof defaultValue === 'number') { - defaultValue = defaultValue.toString(); - } else { - defaultValue = JSON.stringify(defaultValue); - } - } else { - // Provide placeholder based on type and required status - if (param.required) { - switch (param.type) { - case 'boolean': - defaultValue = 'true'; - break; - case 'number': - defaultValue = '0'; - break; - default: - defaultValue = '"TODO: set value"'; - } - } else { - switch (param.type) { - case 'boolean': - defaultValue = 'false'; - break; - case 'number': - defaultValue = '0'; - break; - default: - defaultValue = '""'; - } - } - } - - const comment = param.required ? ' # required' : ' # optional'; - insertion += `\n ${param.name}: ${defaultValue}${comment}`; - } - } + // Gate on declared parameters so a parameterless component doesn't get a bare `inputs:` line. + const withInputs = includeInputs && (component.parameters?.length ?? 0) > 0; + const serverFqdn = await resolveServerFqdn(editor.document.uri); + const insertion = generateComponentText(component, withInputs, withInputs ? selectedInputs : [], null, serverFqdn); // Insert at cursor position editor.edit(editBuilder => { @@ -480,11 +408,6 @@ export class ComponentBrowserProvider { vscode.window.showInformationMessage(message); } - // Public method to insert component from detached view (called from extension.ts) - public async insertComponentFromDetached(component: Component, includeInputs: boolean = false, selectedInputs?: string[]) { - return this.insertComponent(component, includeInputs, selectedInputs); - } - public async showComponentDetails(component: DetachableComponent) { // Create a new webview panel for component details const detailsPanel = vscode.window.createWebviewPanel( @@ -492,7 +415,8 @@ export class ComponentBrowserProvider { `Component: ${component.name}`, vscode.ViewColumn.Beside, { - enableScripts: true + enableScripts: true, + localResourceRoots: assetRoots(this.context.extensionUri) } ); @@ -501,150 +425,201 @@ export class ComponentBrowserProvider { const enriched = await this.lookupComponentDetails(component); // Show component details - detailsPanel.webview.html = this.getComponentDetailsHtml({ ...component, ...enriched }); + detailsPanel.webview.html = this.getComponentDetailsHtml(detailsPanel.webview, { ...component, ...enriched }); - // Handle messages from the details panel - detailsPanel.webview.onDidReceiveMessage( - async message => { - if (message.command === 'insertComponent') { - // Handle different insertion options - const { version, includeInputs, selectedInputs } = message; + this.registerDetailsPanelMessageHandler(detailsPanel, { ...component, ...enriched }); + } - // Update component version if specified - if (version && version !== component.version) { - if (!component.sourcePath || !component.gitlabInstance) { - vscode.window.showErrorMessage('Cannot fetch version: component is missing source path or GitLab instance.'); - return; - } - const updatedComponent = await this.cacheManager.fetchSpecificVersion( - component.name, - component.sourcePath, - component.gitlabInstance, - version - ); - if (updatedComponent) { - if (component._hoverContext) { - await this.editExistingComponentFromDetached( - updatedComponent, - component._hoverContext.documentUri, - component._hoverContext.position, - includeInputs || false, - selectedInputs || [] - ); - } else { - await this.insertComponent(updatedComponent, includeInputs, selectedInputs); + /** + * Wires the details panel's message handling. Both entry points โ€” the Component Browser's Details button and the + * hover's "Open in Detailed View" โ€” render the same HTML and speak the same protocol, so they share this handler; + * `options.detachedFrom` carries the only behavioural difference between them. + * + * @param panel The details webview panel to attach to. + * @param component The component being shown. Held mutably: a `versionChanged` round trip replaces it so later + * `fetchVersions`/`insertComponent` messages act on the version the user is actually looking at. + * @param options Per-entry-point behaviour; see {@link DetailsPanelOptions}. + */ + public registerDetailsPanelMessageHandler( + panel: vscode.WebviewPanel, + component: DetachableComponent, + options: DetailsPanelOptions = {} + ): void { + let active = component; + + if (options.detachedFrom) { + this.adoptOriginalEditor(options.detachedFrom); + } + + panel.webview.onDidReceiveMessage(async message => { + switch (message.command) { + case 'insertComponent': { + const { version, includeInputs, selectedInputs } = message; + try { + let target = active; + if (version && version !== active.version) { + if (!active.sourcePath || !active.gitlabInstance) { + vscode.window.showErrorMessage('Cannot fetch version: component is missing source path or GitLab instance.'); + return; } - } else { - vscode.window.showErrorMessage(`Failed to fetch version ${version} of component ${component.name}`); + const updatedComponent = await this.cacheManager.fetchSpecificVersion( + active.name, + active.sourcePath, + active.gitlabInstance, + version + ); + if (!updatedComponent) { + vscode.window.showErrorMessage(`Failed to fetch version ${version} of component ${active.name}`); + return; + } + // Keep the reference as written, so a variable form like `${CI_SERVER_FQDN}/โ€ฆ` survives the version swap. + target = { ...updatedComponent, originalUrl: active.originalUrl }; } - } else { - if (component._hoverContext) { + + if (active._hoverContext) { await this.editExistingComponentFromDetached( - component, - component._hoverContext.documentUri, - component._hoverContext.position, + target, + active._hoverContext.documentUri, + active._hoverContext.position, includeInputs || false, selectedInputs || [] ); } else { - await this.insertComponent(component, includeInputs, selectedInputs); + await this.insertComponent(target, includeInputs || false, selectedInputs || []); + } + + // The detached panel is a one-shot view opened from a hover, so it closes once it has done its job. + if (options.detachedFrom) { + panel.dispose(); } + } catch (error) { + this.logger.error(`[ComponentBrowser] Error inserting component from details panel: ${error}`, 'ComponentBrowser'); + vscode.window.showErrorMessage(`Error inserting component: ${error}`); } - } else if (message.command === 'fetchVersions') { - // Fetch available versions for the component + break; + } + + case 'fetchVersions': { try { - if (!isCachedComponentShape(component)) { - throw new Error('Component is missing required fields (source, sourcePath, gitlabInstance, version) for version lookup.'); + if (!isVersionLookupShape(active)) { + throw new Error(`Cannot look up versions for ${active.name}: missing source path or GitLab instance.`); } - const versions = await this.cacheManager.fetchComponentVersions(component); - detailsPanel.webview.postMessage({ + // Bind the narrowed value: `active` is reassignable, so TS widens it back across the await below. + const lookupTarget = active; + const versions = await this.cacheManager.fetchComponentVersions(lookupTarget); + // Same monorepo labelling as the detached panel: the webview can't reach the template matcher, so the + // full tag โ†’ stripped {version} map is built here. Without it a refresh reverts the dropdown to full tags. + panel.webview.postMessage({ command: 'versionsLoaded', - versions: versions, - currentVersion: component.version + versions, + versionLabels: buildVersionLabels(versions, lookupTarget.name, lookupTarget.tagPattern), + currentVersion: lookupTarget.version }); } catch (error) { - detailsPanel.webview.postMessage({ + const reason = error instanceof Error ? error.message : String(error); + this.logger.error(`[ComponentBrowser] Error fetching versions: ${reason}`, 'ComponentBrowser'); + panel.webview.postMessage({ command: 'versionsError', - error: error instanceof Error ? error.message : String(error) + error: reason }); } - } else if (message.command === 'versionChanged') { - // Fetch details for the selected version and update the display + break; + } + + case 'openLink': { + // The webview names a link; it never supplies the URL. The host resolves it from the component it holds and + // validates it again here, so a message from a compromised document cannot open anything the component + // metadata did not already name. `openExternal` then applies VS Code's trusted-domain confirmation, which + // shows the user the destination before an untrusted host is opened. + const target = message.link === 'documentation' + ? active.documentationUrl + : message.link === 'templateFile' + ? this.buildTemplateFileUrl(active) + : undefined; + const url = safeHttpUrl(target); + if (!url) { + this.logger.warn(`[ComponentBrowser] Refused to open ${String(message.link)} link: not an http(s) URL`, 'ComponentBrowser'); + break; + } + await vscode.env.openExternal(vscode.Uri.parse(url, true)); + break; + } + + case 'versionChanged': { const { selectedVersion } = message; try { this.logger.debug(`[ComponentBrowser] Version changed to ${selectedVersion}, fetching details...`, 'ComponentBrowser'); - if (!component.sourcePath || !component.gitlabInstance) { + if (!active.sourcePath || !active.gitlabInstance) { vscode.window.showErrorMessage('Cannot change version: component is missing source path or GitLab instance.'); return; } const updatedComponent = await this.cacheManager.fetchSpecificVersion( - component.name, - component.sourcePath, - component.gitlabInstance, + active.name, + active.sourcePath, + active.gitlabInstance, selectedVersion ); if (updatedComponent) { + // Carry the hover context forward so a later insert still edits in place rather than inserting anew. + // Carry the documentation URL forward too: a cached version carries none, and it names the project rather + // than a version, so dropping it would silently break the Project URL link after a version switch. And the + // reference as written, so an edit keeps a variable form like `${CI_SERVER_FQDN}/โ€ฆ`. + active = { + ...updatedComponent, + documentationUrl: active.documentationUrl, + originalUrl: active.originalUrl, + _hoverContext: active._hoverContext, + }; // Send the updated component details to the webview, with the template-file URL precomputed // server-side so the webview never has to do its own URL routing. - detailsPanel.webview.postMessage({ + panel.webview.postMessage({ command: 'componentDetailsUpdated', component: { ...updatedComponent, - templateFileUrl: this.buildTemplateFileUrl(updatedComponent), + documentationUrl: safeHttpUrl(active.documentationUrl), + templateFileUrl: safeHttpUrl(this.buildTemplateFileUrl(updatedComponent)), } }); } else { - detailsPanel.webview.postMessage({ + panel.webview.postMessage({ command: 'versionChangeError', error: `Failed to fetch details for version ${selectedVersion}` }); } } catch (error) { this.logger.error(`[ComponentBrowser] Error fetching version details: ${error}`, 'ComponentBrowser'); - detailsPanel.webview.postMessage({ + panel.webview.postMessage({ command: 'versionChangeError', error: error instanceof Error ? error.message : String(error) }); } + break; } } - ); + }); } - private getLoadingHtml(): string { + /** + * Adopts `editor` as the insertion target for a panel opened outside `show()`. The detached (hover) panel builds its + * own provider, so nothing has populated `originalEditor` and `insertComponent` would otherwise refuse to insert. + */ + private adoptOriginalEditor(editor: vscode.TextEditor): void { + this.originalEditor = editor; + } + + private getLoadingHtml(webview: vscode.Webview): string { + const nonce = createNonce(); + const styleUri = assetUri(webview, this.context.extensionUri, 'styles/loading.css'); return ` + ${cspMetaTag(webview.cspSource, nonce)} + GitLab CI/CD Components -
@@ -682,17 +657,36 @@ export class ComponentBrowserProvider { .join(''); } - private getComponentBrowserHtml(componentGroups: SourceGroup[], cacheErrors: Record = {}): string { + /** + * Render the Component Browser: every configured source, its projects and their components, as a collapsible tree. + * + * @param webview The panel this document is for, used to resolve its asset URIs. + * @param componentGroups Sources with their projects and components, already grouped for display. + * @param cacheErrors Per-source failure messages, keyed by source name. Sources that failed are listed in a + * banner above the tree; an empty record omits it. + * @returns The panel's complete HTML document. + */ + private getComponentBrowserHtml( + webview: vscode.Webview, + componentGroups: SourceGroup[], + cacheErrors: Record = {} + ): string { + const nonce = createNonce(); + const styleUri = assetUri(webview, this.context.extensionUri, 'styles/componentBrowser.css'); + const scriptUri = assetUri(webview, this.context.extensionUri, 'client/componentBrowser.js'); const hasErrors = Object.keys(cacheErrors).length > 0; // Prepare version data as a safe JSON string + // Null-prototype maps: component names and versions are publisher-controlled, and `__proto__` is a legal template + // file name and git tag. On a plain object, `acc['__proto__'][v] = โ€ฆ` would write to Object.prototype in the + // extension host. const versionData = componentGroups.reduce>>((acc, source) => { if (source.projects && Array.isArray(source.projects)) { source.projects.forEach(project => { if (project.components && Array.isArray(project.components)) { project.components.forEach(component => { - if (!acc[component.name]) { - acc[component.name] = {}; + if (!Object.prototype.hasOwnProperty.call(acc, component.name)) { + acc[component.name] = Object.create(null) as Record; } if (component.versions && Array.isArray(component.versions)) { component.versions.forEach(version => { @@ -704,7 +698,7 @@ export class ComponentBrowserProvider { }); } return acc; - }, {}); + }, Object.create(null) as Record>); const versionDataJson = serializeForScript(versionData); @@ -719,12 +713,12 @@ export class ComponentBrowserProvider {
${this.escapeHtml(source)}
${this.escapeHtml(summary)}
- - + +
`; }).join('')} - ${hasAuthError ? '' : ''} + ${hasAuthError ? '' : ''}
` : ''; @@ -740,34 +734,35 @@ export class ComponentBrowserProvider { '

No components found in this project

' : components.map(component => { const componentKey = `${component.name}-${component.sourcePath}`; + const initialVersion = component.defaultVersion || component.availableVersions[0]; const hasVersions = component.availableVersions && component.availableVersions.length > 0; return ` -
+
- ${component.name} + ${this.escapeHtml(component.name)} ${hasVersions && component.availableVersions.length > 1 ? `${component.availableVersions.length} versions` : ''} -
+
${hasVersions ? ` ${component.availableVersions.length > 1 ? ` - ${this.renderVersionOptions(component)} - ` : `${component.availableVersions[0] || 'latest'}`} - - + ` : `${this.escapeHtml(initialVersion || 'latest')}`} + + ` : ` - - + + `}
-
${this.renderInlineMarkdown(component.description || '')}
+
${this.renderInlineMarkdown(component.description || '')}
${hasVersions && component.availableVersions.length > 1 ? ` -
- Default version: ${component.defaultVersion} +
+ Default version: ${this.escapeHtml(component.defaultVersion)}
` : ''}
@@ -776,12 +771,12 @@ export class ComponentBrowserProvider { return `
-
+
${project.isExpanded ? 'โ–ผ' : 'โ–ถ'} - ${project.name} (${components.length}) - ${project.gitlabInstance}/${project.path} + ${this.escapeHtml(project.name)} (${components.length}) + ${this.escapeHtml(project.gitlabInstance)}/${this.escapeHtml(project.path)}
-
+
${componentsHtml}
@@ -790,11 +785,11 @@ export class ComponentBrowserProvider { return `
-
+
${source.isExpanded ? 'โ–ผ' : 'โ–ถ'} - ${source.source} (${source.projects?.length || 0} projects, ${source.totalComponents || 0} components) + ${this.escapeHtml(source.source)} (${source.projects?.length || 0} projects, ${source.totalComponents || 0} components)
-
+
${projectsHtml}
@@ -807,317 +802,19 @@ export class ComponentBrowserProvider { + ${cspMetaTag(webview.cspSource, nonce)} GitLab CI/CD Components - +
- +
- - - + + +
@@ -1129,392 +826,12 @@ export class ComponentBrowserProvider {
-
Set as Default Version
-
Always Use Latest
+
Set as Default Version
+
Always Use Latest
- + + `; @@ -1570,11 +887,16 @@ export class ComponentBrowserProvider { } public getComponentDetailsHtml( + webview: vscode.Webview, component: Component & { availableVersions?: string[]; tagPattern?: string; }, ): string { + const nonce = createNonce(); + const styleUri = assetUri(webview, this.context.extensionUri, 'styles/componentDetails.css'); + const scriptUri = assetUri(webview, this.context.extensionUri, 'client/componentDetails.js'); + const parameters = component.parameters || []; const availableVersions = component.availableVersions || [component.version || 'main']; const headerSummary = component.summary; @@ -1584,6 +906,10 @@ export class ComponentBrowserProvider { const rawYaml = component.rawYaml || ''; const hasRawYaml = Boolean(rawYaml); const templateFileUrl = this.buildTemplateFileUrl(component); + // `documentationUrl` is whatever the component's publisher put in its catalog entry. Validate before display; the + // anchors carry no URL, and clicking one has the extension host open it (see `openLink`). + const safeDocUrl = safeHttpUrl(component.documentationUrl); + const safeTemplateUrl = safeHttpUrl(templateFileUrl); return ` @@ -1591,188 +917,47 @@ export class ComponentBrowserProvider { - Component: ${component.name} - + Component: ${this.escapeHtml(component.name)} + ${cspMetaTag(webview.cspSource, nonce)} + -

${component.name}

+

${this.escapeHtml(component.name)}

${this.renderInlineMarkdown(component.description || '')}
-