diff --git a/.forgejo/workflows/deploy.yml b/.forgejo/workflows/deploy.yml index faf379e..e2c0649 100644 --- a/.forgejo/workflows/deploy.yml +++ b/.forgejo/workflows/deploy.yml @@ -3,10 +3,8 @@ name: Deploy to Pages on: push: branches: ['main'] - pull_request: branches: ['main'] - workflow_dispatch: concurrency: @@ -31,26 +29,21 @@ jobs: - name: Lint run: | - set -eo pipefail npm run lint - npm run typecheck - npm run qa:no-em-dashes - npm run qa:spelling - npm run qa:no-github-links + git diff + if [[ `git status --porcelain` ]]; then + exit 1 + fi - - name: Build - run: npm run build + - name: Typecheck + run: npm run typecheck - - name: QA build + - name: Build, Astro Audit & QA run: | - set -eo pipefail - npm run qa:astro-audit - npm run qa:links - npm run qa:no-js - npm run qa:overflow - npm run qa:preview-cropping + npx playwright install chromium + npm run qa - - name: On main, Copy build to host pages mount + - name: Copy build to host pages mount if: github.event_name == 'push' && github.ref == 'refs/heads/main' uses: http://forgejo:3000/andras/ci-actions/deploy-pages@main with: diff --git a/.vscode/settings.json b/.vscode/settings.json index 5528ea3..80a5ba5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,9 +1,42 @@ { + "cSpell.words": [ + "andras", + "Andras", + "astra", + "colour", + "colours", + "datetime", + "decla", + "EEPROM", + "favicons", + "favourite", + "forex", + "froms", + "Glsl", + "leds", + "linkedin", + "mesmerising", + "microcontrollers", + "mixins", + "noopener", + "optimisations", + "optimised", + "organiser", + "playsinline", + "realised", + "schmelczer", + "serialisation", + "synchronised", + "tabindex", + "utilised", + "utilising", + "webm", + "webp", + "youtube" + ], "files.exclude": { "node_modules": true }, - "editor.rulers": [ - 90 - ], + "editor.rulers": [90], "editor.wordWrap": "on" -} \ No newline at end of file +} diff --git a/README.md b/README.md index 71ab187..64893ae 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Engineering writeups by Andras Schmelczer: finished projects with the design constraints left in. Built with Astro, no required client JavaScript. -All content lives in the single `src/content/work` collection: each entry can carry an `article` facet (a page under `/articles/`), a `project` facet (a card on `/projects/`), or both. Normal pages are rendered as static HTML. +Articles live in `src/content/posts`, project index entries in `src/content/projects`, and normal pages are rendered as static HTML. ## Setup @@ -11,8 +11,6 @@ npm ci npx playwright install --with-deps chromium # required before Playwright QA checks ``` -The `overrides.yaml` entry in `package.json` forces every transitive `yaml` dependency to 2.9+, ahead of what some Astro tooling requests on its own. Drop it once `npm ls yaml` shows nothing older without it. - ## Commands ```sh @@ -25,11 +23,11 @@ npm run qa ## Structure -- `src/content/work`: Markdown entries (article and/or project facets) +- `src/content/posts`: Markdown articles +- `src/content/projects`: project index entries - `src/pages`: static routes - `src/layouts`: page and post layouts - `src/components`: reusable UI pieces - `src/styles/global.css`: the visual system -- `scripts`: QA checks run by `npm run qa` (shared helpers in `scripts/lib`) - `public/media/downloads`: CV and thesis PDFs - `public/media/video`: project videos diff --git a/astro.config.mjs b/astro.config.mjs index c4c4999..93a9357 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -7,15 +7,14 @@ import rehypeAutolinkHeadings from 'rehype-autolink-headings'; import rehypeSlug from 'rehype-slug'; import { visit } from 'unist-util-visit'; -// Build a lookup of article slugs to their last modification dates so the -// sitemap can advertise accurate values to crawlers. astro:content -// isn't available inside the config, so we read entry frontmatter directly. -// Each entry uses a single-line top-level scalar `date:` key, so a small regex -// extraction is sufficient and intentional. (`updated:` now lives nested under -// `article:`; no entry sets it, so falling back to `date` is correct.) +// Build a lookup of post slugs to their last modification dates so the sitemap +// can advertise accurate values to crawlers. astro:content isn't +// available inside the config, so we read post frontmatter directly. Our posts +// always use single-line scalar `date:` / `updated:` keys, so a small regex +// extraction is sufficient and intentional. const postsDir = path.resolve( path.dirname(fileURLToPath(import.meta.url)), - 'src/content/work' + 'src/content/posts' ); function extractScalar(frontmatter, key) { diff --git a/cspell.json b/cspell.json deleted file mode 100644 index e606e31..0000000 --- a/cspell.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json", - "version": "0.2", - "language": "en,en-GB", - "ignorePaths": [ - "node_modules/**", - "dist/**", - ".astro/**", - "package-lock.json", - "*.svg", - "public/**", - "todo.md" - ], - "words": [ - "acked", - "acks", - "adblocker", - "apos", - "backpressure", - "backtest", - "bgsave", - "binaryen", - "bindgen", - "bitpacking", - "blockedbyclient", - "borgmann", - "btrfs", - "cheatable", - "collab", - "conveyal", - "crewmates", - "datasheet", - "datasheets", - "decla", - "dequant", - "desync", - "domcontentloaded", - "emelt", - "érettségi", - "extensionless", - "extrapolators", - "fizika", - "forex", - "fouc", - "funimation", - "gameboy", - "glsl", - "greatai", - "hanning", - "healthcheck", - "immich", - "immich's", - "importmap", - "incrementality", - "janky", - "jemalloc", - "keepalives", - "laion", - "loggable", - "malloc", - "metas", - "mispredictions", - "mixolydian", - "mlockall", - "mosfets", - "nixplay's", - "ntfy", - "numba", - "numpy", - "nums", - "permacomputing", - "physarum", - "piskel", - "pocketbase", - "powerups", - "proptest", - "refetches", - "reflashing", - "reimplementable", - "requantised", - "rgba", - "scalex", - "scaley", - "schmelczer", - "scrollables", - "serde", - "setpoints", - "shiki", - "slugifies", - "speculationrules", - "sqlx", - "stdlib", - "stft", - "strobing", - "stucki", - "subvolume", - "syncer", - "szintű", - "tamagotchi", - "tamagotchis", - "tarjan's", - "tidepool", - "tmpfs", - "tweakpane", - "unsets", - "vaultlink", - "vtable", - "waveshare", - "waveshare's", - "webform", - "webgpu", - "wgsl", - "writeups", - "zstd" - ] -} diff --git a/package-lock.json b/package-lock.json index 96c325f..1d3867b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,21 +7,19 @@ "name": "schmelczer-dev", "license": "GPL-3.0-or-later", "dependencies": { - "@plausible-analytics/tracker": "^0.4.5", - "sharp": "^0.34.5" + "@plausible-analytics/tracker": "^0.4.5" }, "devDependencies": { "@astrojs/check": "^0.9.9", "@astrojs/rss": "^4.0.18", "@astrojs/sitemap": "^3.7.2", - "@types/node": "^22.13.0", "astro": "^6.3.1", - "cspell": "^10.0.1", "playwright": "^1.59.1", "prettier": "^3.8.3", "prettier-plugin-astro": "^0.14.1", "rehype-autolink-headings": "^7.1.0", "rehype-slug": "^6.0.0", + "sharp": "^0.34.5", "typescript": "^5.9.3", "unist-util-visit": "^5.1.0" }, @@ -95,6 +93,19 @@ "picomatch": "^4.0.4" } }, + "node_modules/@astrojs/internal-helpers/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@astrojs/language-server": { "version": "2.16.8", "resolved": "https://registry.npmjs.org/@astrojs/language-server/-/language-server-2.16.8.tgz", @@ -402,640 +413,6 @@ "node": ">= 20.12.0" } }, - "node_modules/@cspell/cspell-bundled-dicts": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-10.0.1.tgz", - "integrity": "sha512-WvkSDNX4Uyyj/ZgbPO6L38iFNMfK1EqsH1FteRiI2qLz6QZMXRFrIt12OqiWIplzZDDaVpBH9FCJOPJll0fjCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/dict-ada": "^4.1.1", - "@cspell/dict-al": "^1.1.1", - "@cspell/dict-aws": "^4.0.17", - "@cspell/dict-bash": "^4.2.2", - "@cspell/dict-companies": "^3.2.11", - "@cspell/dict-cpp": "^7.0.2", - "@cspell/dict-cryptocurrencies": "^5.0.5", - "@cspell/dict-csharp": "^4.0.8", - "@cspell/dict-css": "^4.1.1", - "@cspell/dict-dart": "^2.3.2", - "@cspell/dict-data-science": "^2.0.13", - "@cspell/dict-django": "^4.1.6", - "@cspell/dict-docker": "^1.1.17", - "@cspell/dict-dotnet": "^5.0.13", - "@cspell/dict-elixir": "^4.0.8", - "@cspell/dict-en_us": "^4.4.33", - "@cspell/dict-en-common-misspellings": "^2.1.12", - "@cspell/dict-en-gb-mit": "^3.1.22", - "@cspell/dict-filetypes": "^3.0.18", - "@cspell/dict-flutter": "^1.1.1", - "@cspell/dict-fonts": "^4.0.6", - "@cspell/dict-fsharp": "^1.1.1", - "@cspell/dict-fullstack": "^3.2.9", - "@cspell/dict-gaming-terms": "^1.1.2", - "@cspell/dict-git": "^3.1.0", - "@cspell/dict-golang": "^6.0.26", - "@cspell/dict-google": "^1.0.9", - "@cspell/dict-haskell": "^4.0.6", - "@cspell/dict-html": "^4.0.15", - "@cspell/dict-html-symbol-entities": "^4.0.5", - "@cspell/dict-java": "^5.0.12", - "@cspell/dict-julia": "^1.1.1", - "@cspell/dict-k8s": "^1.0.12", - "@cspell/dict-kotlin": "^1.1.1", - "@cspell/dict-latex": "^5.1.0", - "@cspell/dict-lorem-ipsum": "^4.0.5", - "@cspell/dict-lua": "^4.0.8", - "@cspell/dict-makefile": "^1.0.5", - "@cspell/dict-markdown": "^2.0.16", - "@cspell/dict-monkeyc": "^1.0.12", - "@cspell/dict-node": "^5.0.9", - "@cspell/dict-npm": "^5.2.38", - "@cspell/dict-php": "^4.1.1", - "@cspell/dict-powershell": "^5.0.15", - "@cspell/dict-public-licenses": "^2.0.16", - "@cspell/dict-python": "^4.2.26", - "@cspell/dict-r": "^2.1.1", - "@cspell/dict-ruby": "^5.1.1", - "@cspell/dict-rust": "^4.1.2", - "@cspell/dict-scala": "^5.0.9", - "@cspell/dict-shell": "^1.1.2", - "@cspell/dict-software-terms": "^5.2.2", - "@cspell/dict-sql": "^2.2.1", - "@cspell/dict-svelte": "^1.0.7", - "@cspell/dict-swift": "^2.0.6", - "@cspell/dict-terraform": "^1.1.3", - "@cspell/dict-typescript": "^3.2.3", - "@cspell/dict-vue": "^3.0.5", - "@cspell/dict-zig": "^1.0.0" - }, - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/@cspell/cspell-json-reporter": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-json-reporter/-/cspell-json-reporter-10.0.1.tgz", - "integrity": "sha512-/nes1RGILec3WCBcoMOd0byNTBtnJuPaVz/+ZzqYkLtY7x58VMcBG5kyP6hPyN8cIwjRADE/SR43gwdXuqk/FA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/cspell-types": "10.0.1" - }, - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/@cspell/cspell-performance-monitor": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-performance-monitor/-/cspell-performance-monitor-10.0.1.tgz", - "integrity": "sha512-9tVcHXwRnbazUv4WSG0h3MqV4+LgmLNgSALAQUflPPW0EMxTf7C4Dmv9cgxJyCEQrdnVKCr58nPPaahhz9LJUg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/@cspell/cspell-pipe": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-10.0.1.tgz", - "integrity": "sha512-HPeXMD9AZ3V/qPkvQaPcak+C7cJ2z7JTHN8smd6J8L2aThLRky2cHc2OyeaHPSHB7WA47b4z2n5u5nawZhv5VQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/@cspell/cspell-resolver": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-resolver/-/cspell-resolver-10.0.1.tgz", - "integrity": "sha512-PIzkZHD1fGUQx1XteK2d1iQ0Mzq/maYcoB4jkvAiiR6WqP3MWYNKFdI9z+R5pOq5KgMfW+5Ig1q0oSR6h8irlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "global-directory": "^5.0.0" - }, - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/@cspell/cspell-service-bus": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-10.0.1.tgz", - "integrity": "sha512-y6NcIGP2IdXaBL4PVH8vxsr7K27wzz3Ech87UtUtrDSXAiVEOvXgAIknEOUVp59rTlUE8Rn4IRURC6f/hgMyfw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/@cspell/cspell-types": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-10.0.1.tgz", - "integrity": "sha512-kLgLShnWADDVreKC63pBrWkcvxgZzFIfO34Jhx/SWfuOIA3cD8AXT+HjyuLfoGJ7mUb58hv2kUziKzEy4INb1w==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/@cspell/cspell-worker": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-worker/-/cspell-worker-10.0.1.tgz", - "integrity": "sha512-L2bJerfuYOls2wEknm8FmynLtj/G7O4UqX9I/HznRggEW6i2yZIxagDetpVDNowpyavNHJ3SJtUFiyMiZc16Sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "cspell-lib": "10.0.1" - }, - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/@cspell/dict-ada": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-4.1.1.tgz", - "integrity": "sha512-E+0YW9RhZod/9Qy2gxfNZiHJjCYFlCdI69br1eviQQWB8yOTJX0JHXLs79kOYhSW0kINPVUdvddEBe6Lu6CjGQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-al": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-al/-/dict-al-1.1.1.tgz", - "integrity": "sha512-sD8GCaZetgQL4+MaJLXqbzWcRjfKVp8x+px3HuCaaiATAAtvjwUQ5/Iubiqwfd1boIh2Y1/3EgM3TLQ7Q8e0wQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-aws": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-4.0.17.tgz", - "integrity": "sha512-ORcblTWcdlGjIbWrgKF+8CNEBQiLVKdUOFoTn0KPNkAYnFcdPP0muT4892h7H4Xafh3j72wqB4/loQ6Nti9E/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-bash": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-4.2.3.tgz", - "integrity": "sha512-ljUZoKHbDqw5Sx0qpL2qTUlmkmr+vhZH/sCNrNaBZKTbdgiswErSnIF1jRbGmEitJNxHRHWsuZyVgnTGfVO1Yw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/dict-shell": "1.2.0" - } - }, - "node_modules/@cspell/dict-companies": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-3.2.11.tgz", - "integrity": "sha512-0cmafbcz2pTHXLd59eLR1gvDvN6aWAOM0+cIL4LLF9GX9yB2iKDNrKsvs4tJRqutoaTdwNFBbV0FYv+6iCtebQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-cpp": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-7.0.2.tgz", - "integrity": "sha512-dfbeERiVNeqmo/npivdR6rDiBCqZi3QtjH2Z0HFcXwpdj6i97dX1xaKyK2GUsO/p4u1TOv63Dmj5Vm48haDpuA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-cryptocurrencies": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-5.0.5.tgz", - "integrity": "sha512-R68hYYF/rtlE6T/dsObStzN5QZw+0aQBinAXuWCVqwdS7YZo0X33vGMfChkHaiCo3Z2+bkegqHlqxZF4TD3rUA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-csharp": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-4.0.8.tgz", - "integrity": "sha512-qmk45pKFHSxckl5mSlbHxmDitSsGMlk/XzFgt7emeTJWLNSTUK//MbYAkBNRtfzB4uD7pAFiKgpKgtJrTMRnrQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-css": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-4.1.2.tgz", - "integrity": "sha512-+ylGoKdwZ2sVOCOnU2Eq5wDZx+RaVX3HoKyNHGGsFvhSw6IidQ6tH/mAPKBDofViHJoWCPNlklE0lTr6MDG3QA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@cspell/dict-dart": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-2.3.2.tgz", - "integrity": "sha512-sUiLW56t9gfZcu8iR/5EUg+KYyRD83Cjl3yjDEA2ApVuJvK1HhX+vn4e4k4YfjpUQMag8XO2AaRhARE09+/rqw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-data-science": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/@cspell/dict-data-science/-/dict-data-science-2.0.14.tgz", - "integrity": "sha512-jl6Ds4u5u5JT+yY30pWQpAbdCHfy3lCcNkLbpL/AZKoUaLEoXbaYsps9xQtvD7DyaiXxiLZkdH2yHHXtoFtZyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-django": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-4.1.6.tgz", - "integrity": "sha512-SdbSFDGy9ulETqNz15oWv2+kpWLlk8DJYd573xhIkeRdcXOjskRuxjSZPKfW7O3NxN/KEf3gm3IevVOiNuFS+w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-docker": { - "version": "1.1.17", - "resolved": "https://registry.npmjs.org/@cspell/dict-docker/-/dict-docker-1.1.17.tgz", - "integrity": "sha512-OcnVTIpHIYYKhztNTyK8ShAnXTfnqs43hVH6p0py0wlcwRIXe5uj4f12n7zPf2CeBI7JAlPjEsV0Rlf4hbz/xQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-dotnet": { - "version": "5.0.13", - "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-5.0.13.tgz", - "integrity": "sha512-xPp7jMnFpOri7tzmqmm/dXMolXz1t2bhNqxYkOyMqXhvs08oc7BFs+EsbDY0X7hqiISgeFZGNqn0dOCr+ncPYw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-elixir": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-4.0.8.tgz", - "integrity": "sha512-CyfphrbMyl4Ms55Vzuj+mNmd693HjBFr9hvU+B2YbFEZprE5AG+EXLYTMRWrXbpds4AuZcvN3deM2XVB80BN/Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-en_us": { - "version": "4.4.35", - "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-4.4.35.tgz", - "integrity": "sha512-xWpxBCc/FzzMMo/A+0qwARVaIIhR0Ql8yhhv4rvsvg+GfQF+LG9yzg2GwTM5N2rjvzmM3nKuR9zxFZq2I6fJSg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-en-common-misspellings": { - "version": "2.1.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-en-common-misspellings/-/dict-en-common-misspellings-2.1.12.tgz", - "integrity": "sha512-14Eu6QGqyksqOd4fYPuRb58lK1Va7FQK9XxFsRKnZU8LhL3N+kj7YKDW+7aIaAN/0WGEqslGP6lGbQzNti8Akw==", - "dev": true, - "license": "CC BY-SA 4.0" - }, - "node_modules/@cspell/dict-en-gb-mit": { - "version": "3.1.24", - "resolved": "https://registry.npmjs.org/@cspell/dict-en-gb-mit/-/dict-en-gb-mit-3.1.24.tgz", - "integrity": "sha512-Oowb/Uzkh7OmDRdCcETzMc9imEb4IpLlHJXoYjX8A8DS2X/54gqSjI915JFB8hKtFjBko5OM0BLQ+6cZhFEMmQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-filetypes": { - "version": "3.0.18", - "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-3.0.18.tgz", - "integrity": "sha512-yU7RKD/x1IWmDLzWeiItMwgV+6bUcU/af23uS0+uGiFUbsY1qWV/D4rxlAAO6Z7no3J2z8aZOkYIOvUrJq0Rcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-flutter": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-flutter/-/dict-flutter-1.1.1.tgz", - "integrity": "sha512-UlOzRcH2tNbFhZmHJN48Za/2/MEdRHl2BMkCWZBYs+30b91mWvBfzaN4IJQU7dUZtowKayVIF9FzvLZtZokc5A==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-fonts": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-4.0.6.tgz", - "integrity": "sha512-aR/0csY01dNb0A1tw/UmN9rKgHruUxsYsvXu6YlSBJFu60s26SKr/k1o4LavpHTQ+lznlYMqAvuxGkE4Flliqw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-fsharp": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-fsharp/-/dict-fsharp-1.1.1.tgz", - "integrity": "sha512-imhs0u87wEA4/cYjgzS0tAyaJpwG7vwtC8UyMFbwpmtw+/bgss+osNfyqhYRyS/ehVCWL17Ewx2UPkexjKyaBA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-fullstack": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-3.2.9.tgz", - "integrity": "sha512-diZX+usW5aZ4/b2T0QM/H/Wl9aNMbdODa1Jq0ReBr/jazmNeWjd+PyqeVgzd1joEaHY+SAnjrf/i9CwKd2ZtWQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-gaming-terms": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-gaming-terms/-/dict-gaming-terms-1.1.2.tgz", - "integrity": "sha512-9XnOvaoTBscq0xuD6KTEIkk9hhdfBkkvJAIsvw3JMcnp1214OCGW8+kako5RqQ2vTZR3Tnf3pc57o7VgkM0q1Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-git": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-git/-/dict-git-3.1.0.tgz", - "integrity": "sha512-KEt9zGkxqGy2q1nwH4CbyqTSv5nadpn8BAlDnzlRcnL0Xb3LX9xTgSGShKvzb0bw35lHoYyLWN2ZKAqbC4pgGQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-golang": { - "version": "6.0.26", - "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-6.0.26.tgz", - "integrity": "sha512-YKA7Xm5KeOd14v5SQ4ll6afe9VSy3a2DWM7L9uBq4u3lXToRBQ1W5PRa+/Q9udd+DTURyVVnQ+7b9cnOlNxaRg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-google": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@cspell/dict-google/-/dict-google-1.0.9.tgz", - "integrity": "sha512-biL65POqialY0i4g6crj7pR6JnBkbsPovB2WDYkj3H4TuC/QXv7Pu5pdPxeUJA6TSCHI7T5twsO4VSVyRxD9CA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-haskell": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-4.0.6.tgz", - "integrity": "sha512-ib8SA5qgftExpYNjWhpYIgvDsZ/0wvKKxSP+kuSkkak520iPvTJumEpIE+qPcmJQo4NzdKMN8nEfaeci4OcFAQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-html": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-4.0.15.tgz", - "integrity": "sha512-GJYnYKoD9fmo2OI0aySEGZOjThnx3upSUvV7mmqUu8oG+mGgzqm82P/f7OqsuvTaInZZwZbo+PwJQd/yHcyFIw==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@cspell/dict-html-symbol-entities": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-4.0.5.tgz", - "integrity": "sha512-429alTD4cE0FIwpMucvSN35Ld87HCyuM8mF731KU5Rm4Je2SG6hmVx7nkBsLyrmH3sQukTcr1GaiZsiEg8svPA==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@cspell/dict-java": { - "version": "5.0.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-5.0.12.tgz", - "integrity": "sha512-qPSNhTcl7LGJ5Qp6VN71H8zqvRQK04S08T67knMq9hTA8U7G1sTKzLmBaDOFhq17vNX/+rT+rbRYp+B5Nwza1A==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-julia": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-julia/-/dict-julia-1.1.1.tgz", - "integrity": "sha512-WylJR9TQ2cgwd5BWEOfdO3zvDB+L7kYFm0I9u0s9jKHWQ6yKmfKeMjU9oXxTBxIufhCXm92SKwwVNAC7gjv+yA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-k8s": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-k8s/-/dict-k8s-1.0.12.tgz", - "integrity": "sha512-2LcllTWgaTfYC7DmkMPOn9GsBWsA4DZdlun4po8s2ysTP7CPEnZc1ZfK6pZ2eI4TsZemlUQQ+NZxMe9/QutQxg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-kotlin": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-kotlin/-/dict-kotlin-1.1.1.tgz", - "integrity": "sha512-J3NzzfgmxRvEeOe3qUXnSJQCd38i/dpF9/t3quuWh6gXM+krsAXP75dY1CzDmS8mrJAlBdVBeAW5eAZTD8g86Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-latex": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-5.1.0.tgz", - "integrity": "sha512-qxT4guhysyBt0gzoliXYEBYinkAdEtR2M7goRaUH0a7ltCsoqqAeEV8aXYRIdZGcV77gYSobvu3jJL038tlPAw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-lorem-ipsum": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-4.0.5.tgz", - "integrity": "sha512-9a4TJYRcPWPBKkQAJ/whCu4uCAEgv/O2xAaZEI0n4y1/l18Yyx8pBKoIX5QuVXjjmKEkK7hi5SxyIsH7pFEK9Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-lua": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-4.0.8.tgz", - "integrity": "sha512-N4PkgNDMu9JVsRu7JBS/3E/dvfItRgk9w5ga2dKq+JupP2Y3lojNaAVFhXISh4Y0a6qXDn2clA6nvnavQ/jjLA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-makefile": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-makefile/-/dict-makefile-1.0.5.tgz", - "integrity": "sha512-4vrVt7bGiK8Rx98tfRbYo42Xo2IstJkAF4tLLDMNQLkQ86msDlYSKG1ZCk8Abg+EdNcFAjNhXIiNO+w4KflGAQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-markdown": { - "version": "2.0.17", - "resolved": "https://registry.npmjs.org/@cspell/dict-markdown/-/dict-markdown-2.0.17.tgz", - "integrity": "sha512-H8bAxih6U8NOnSPL7R8My+tqjaB4tmnJTjERuz4zYqmf+cH+5xshX3UVgKlwWFcyjsYfv/zEDuRdMctQv1q6HQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@cspell/dict-css": "^4.1.2", - "@cspell/dict-html": "^4.0.15", - "@cspell/dict-html-symbol-entities": "^4.0.5", - "@cspell/dict-typescript": "^3.2.3" - } - }, - "node_modules/@cspell/dict-monkeyc": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-monkeyc/-/dict-monkeyc-1.0.12.tgz", - "integrity": "sha512-MN7Vs11TdP5mbdNFQP5x2Ac8zOBm97ARg6zM5Sb53YQt/eMvXOMvrep7+/+8NJXs0jkp70bBzjqU4APcqBFNAw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-node": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-5.0.9.tgz", - "integrity": "sha512-hO+ga+uYZ/WA4OtiMEyKt5rDUlUyu3nXMf8KVEeqq2msYvAPdldKBGH7lGONg6R/rPhv53Rb+0Y1SLdoK1+7wQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-npm": { - "version": "5.2.41", - "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-5.2.41.tgz", - "integrity": "sha512-To3xsfRmMBYVXtWVEdUgV35M9a/JZ54dSuoY6m6D3uHKKL3I326Wmy4xifZ3PU8MQaWhyEH7zbIcUEtKwTQMcA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-php": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-4.1.1.tgz", - "integrity": "sha512-EXelI+4AftmdIGtA8HL8kr4WlUE11OqCSVlnIgZekmTkEGSZdYnkFdiJ5IANSALtlQ1mghKjz+OFqVs6yowgWA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-powershell": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-5.0.15.tgz", - "integrity": "sha512-l4S5PAcvCFcVDMJShrYD0X6Huv9dcsQPlsVsBGbH38wvuN7gS7+GxZFAjTNxDmTY1wrNi1cCatSg6Pu2BW4rgg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-public-licenses": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-2.0.16.tgz", - "integrity": "sha512-EQRrPvEOmwhwWezV+W7LjXbIBjiy6y/shrET6Qcpnk3XANTzfvWflf9PnJ5kId/oKWvihFy0za0AV1JHd03pSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-python": { - "version": "4.2.27", - "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-4.2.27.tgz", - "integrity": "sha512-Rj6xQgYS4X6ienjgAZF+njA0GRY4oSPouJWv0vfikCTn6EWlfk0V6Dy1HP3Migj1O+IC2NmespgVq+BZNSp8OA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/dict-data-science": "^2.0.14" - } - }, - "node_modules/@cspell/dict-r": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-r/-/dict-r-2.1.1.tgz", - "integrity": "sha512-71Ka+yKfG4ZHEMEmDxc6+blFkeTTvgKbKAbwiwQAuKl3zpqs1Y0vUtwW2N4b3LgmSPhV3ODVY0y4m5ofqDuKMw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-ruby": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-5.1.1.tgz", - "integrity": "sha512-LHrp84oEV6q1ZxPPyj4z+FdKyq1XAKYPtmGptrd+uwHbrF/Ns5+fy6gtSi7pS+uc0zk3JdO9w/tPK+8N1/7WUA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-rust": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-4.1.2.tgz", - "integrity": "sha512-O1FHrumYcO+HZti3dHfBPUdnDFkI+nbYK3pxYmiM1sr+G0ebOd6qchmswS0Wsc6ZdEVNiPYJY/gZQR6jfW3uOg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-scala": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-5.0.9.tgz", - "integrity": "sha512-AjVcVAELgllybr1zk93CJ5wSUNu/Zb5kIubymR/GAYkMyBdYFCZ3Zbwn4Zz8GJlFFAbazABGOu0JPVbeY59vGg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-shell": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-shell/-/dict-shell-1.2.0.tgz", - "integrity": "sha512-PVctvT22lJ49niMiakO8xieY7ELCAzjSqhejWR7bAMb5AZ9F4WDEs+XdGMnoVHWeXq7K5rcepLPmEJb+37zzIw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-software-terms": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-5.2.2.tgz", - "integrity": "sha512-0CaYd6TAsKtEoA7tNswm1iptEblTzEe3UG8beG2cpSTHk7afWIVMtJLgXDv0f/Li67Lf3Z1Jf3JeXR7GsJ2TRw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-sql": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-sql/-/dict-sql-2.2.1.tgz", - "integrity": "sha512-qDHF8MpAYCf4pWU8NKbnVGzkoxMNrFqBHyG/dgrlic5EQiKANCLELYtGlX5auIMDLmTf1inA0eNtv74tyRJ/vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-svelte": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@cspell/dict-svelte/-/dict-svelte-1.0.7.tgz", - "integrity": "sha512-hGZsGqP0WdzKkdpeVLBivRuSNzOTvN036EBmpOwxH+FTY2DuUH7ecW+cSaMwOgmq5JFSdTcbTNFlNC8HN8lhaQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-swift": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@cspell/dict-swift/-/dict-swift-2.0.6.tgz", - "integrity": "sha512-PnpNbrIbex2aqU1kMgwEKvCzgbkHtj3dlFLPMqW1vSniop7YxaDTtvTUO4zA++ugYAEL+UK8vYrBwDPTjjvSnA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-terraform": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-terraform/-/dict-terraform-1.1.3.tgz", - "integrity": "sha512-gr6wxCydwSFyyBKhBA2xkENXtVFToheqYYGFvlMZXWjviynXmh+NK/JTvTCk/VHk3+lzbO9EEQKee6VjrAUSbA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-typescript": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-3.2.3.tgz", - "integrity": "sha512-zXh1wYsNljQZfWWdSPYwQhpwiuW0KPW1dSd8idjMRvSD0aSvWWHoWlrMsmZeRl4qM4QCEAjua8+cjflm41cQBg==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@cspell/dict-vue": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-vue/-/dict-vue-3.0.5.tgz", - "integrity": "sha512-Mqutb8jbM+kIcywuPQCCaK5qQHTdaByoEO2J9LKFy3sqAdiBogNkrplqUK0HyyRFgCfbJUgjz3N85iCMcWH0JA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-zig": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-zig/-/dict-zig-1.0.0.tgz", - "integrity": "sha512-XibBIxBlVosU06+M6uHWkFeT0/pW5WajDRYdXG2CgHnq85b0TI/Ks0FuBJykmsgi2CAD3Qtx8UHFEtl/DSFnAQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dynamic-import": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dynamic-import/-/dynamic-import-10.0.1.tgz", - "integrity": "sha512-mP1gdq00aIcH8HxNMqnH11X6BKxLcneDtFgl/ecjIKnaGKwi44m8AndP5Kr4ODaYdl8UUw9O3dJh7KaQXnLHZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/url": "10.0.1", - "import-meta-resolve": "^4.2.0" - }, - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/@cspell/filetypes": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/filetypes/-/filetypes-10.0.1.tgz", - "integrity": "sha512-Z5S35giU5IW49fBBq6BksUbE8PC4IYPfaKuwl5Nl9jkf/OkAKiBmCowKX45NzRUQInwK/GSqqIUifrNeI6LdLw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/@cspell/rpc": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/rpc/-/rpc-10.0.1.tgz", - "integrity": "sha512-axSRKv3zEAmBm66iD/FV/MPmE4/Yf7c3PZiwTW894Yd3iEhtn3KPKeTrqQ2/tDrhB1Z2qTsap/Hue0MK4o5WXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/@cspell/strong-weak-map": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/strong-weak-map/-/strong-weak-map-10.0.1.tgz", - "integrity": "sha512-lenN1DVyPi8nJLSMSJJ670ddTjyiruLueuSZO1qLcxBqUhgxDt/mALu9N/1m6WdOVcg6m/5cLiZVg2KOo2UzRw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/@cspell/url": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/url/-/url-10.0.1.tgz", - "integrity": "sha512-abYYgI29wJhWIfWTYrYuzRYDcHQUQ1N5ylnhxYn1NJnIQMqUWGLbDmt12JABtZ+R6h6UNatQrS7rhP86etvJyQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.18.0" - } - }, "node_modules/@emmetio/abbreviation": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/@emmetio/abbreviation/-/abbreviation-2.3.3.tgz", @@ -1102,6 +479,7 @@ "version": "1.10.0", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -1554,6 +932,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -1566,6 +945,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1588,6 +968,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1610,6 +991,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1626,6 +1008,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1642,6 +1025,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1658,6 +1042,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1674,6 +1059,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1690,6 +1076,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1706,6 +1093,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1722,6 +1110,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1738,6 +1127,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1754,6 +1144,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1770,6 +1161,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1792,6 +1184,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1814,6 +1207,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1836,6 +1230,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1858,6 +1253,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1880,6 +1276,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1902,6 +1299,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1924,6 +1322,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -1946,6 +1345,7 @@ "cpu": [ "wasm32" ], + "dev": true, "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "optional": true, "dependencies": { @@ -1965,6 +1365,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ @@ -1984,6 +1385,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ @@ -2003,6 +1405,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ @@ -2071,6 +1474,19 @@ } } }, + "node_modules/@rollup/pluginutils/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.60.3", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.3.tgz", @@ -2584,19 +2000,19 @@ } }, "node_modules/@types/node": { - "version": "22.19.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.21.tgz", - "integrity": "sha512-VMeFBSCKQKmm2swI2kW51SFusDqekC6q9trBCvJ/JliDchFSuoYYKN7yVNjPthP1HKZcx3U1gI/wTcEBjEFKTA==", + "version": "25.6.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.2.tgz", + "integrity": "sha512-sokuT28dxf9JT5Kady1fsXOvI4HVpjZa95NKT5y9PNTIrs2AsobR4GFAA90ZG8M+nxVRLysCXsVj6eGC7Vbrlw==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.21.0" + "undici-types": "~7.19.0" } }, "node_modules/@types/node/node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", "dev": true, "license": "MIT" }, @@ -2797,13 +2213,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/array-timsort": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", - "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", - "dev": true, - "license": "MIT" - }, "node_modules/astro": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/astro/-/astro-6.3.1.tgz", @@ -3083,6 +2492,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/astro/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/astro/node_modules/svgo": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.1.tgz", @@ -3115,7 +2537,6 @@ "integrity": "sha512-/4XH147Ui7OGTjg3HbdWe5arnZQSbfuRzdr9Ec7TQi5I7R+ir0Rlc9GIvD4v0XZurELqA035KVXJXpR61xhiTA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -3256,35 +2677,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk-template": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-1.1.2.tgz", - "integrity": "sha512-2bxTP2yUH7AJj/VAXfcA+4IcWGdQ87HwBANLt5XxGTeomo8yG0y95N1um9i5StvhT/Bl0/2cARA5v1PpPXUxUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^5.2.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/chalk/chalk-template?sponsor=1" - } - }, "node_modules/character-entities": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", @@ -3408,30 +2800,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/commander": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", - "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - } - }, - "node_modules/comment-json": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-5.0.0.tgz", - "integrity": "sha512-uiqLcOiVDJtBP8WGkZHEP+FZIhTzP1dxvn59EfoYUi9gqupjrBWVQkO2atDrbnKPwLeotFYDsuNb26uBMqB+hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-timsort": "^1.0.3", - "esprima": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/common-ancestor-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-2.0.0.tgz", @@ -3459,203 +2827,6 @@ "uncrypto": "^0.1.3" } }, - "node_modules/cspell": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell/-/cspell-10.0.1.tgz", - "integrity": "sha512-Gg6w/flT3fKfl3la62hfTnhtNnDQ+9mU7kUhVqw/axl/Ms4oENw0oJMkWFIoj4f6nL/SDPz7KcPXd2XbkKFNmQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/cspell-json-reporter": "10.0.1", - "@cspell/cspell-performance-monitor": "10.0.1", - "@cspell/cspell-pipe": "10.0.1", - "@cspell/cspell-types": "10.0.1", - "@cspell/cspell-worker": "10.0.1", - "@cspell/dynamic-import": "10.0.1", - "@cspell/url": "10.0.1", - "ansi-regex": "^6.2.2", - "chalk": "^5.6.2", - "chalk-template": "^1.1.2", - "commander": "^14.0.3", - "cspell-config-lib": "10.0.1", - "cspell-dictionary": "10.0.1", - "cspell-gitignore": "10.0.1", - "cspell-glob": "10.0.1", - "cspell-io": "10.0.1", - "cspell-lib": "10.0.1", - "fast-json-stable-stringify": "^2.1.0", - "flatted": "^3.4.2", - "semver": "^7.8.1", - "tinyglobby": "^0.2.16" - }, - "bin": { - "cspell": "bin.mjs", - "cspell-esm": "bin.mjs" - }, - "engines": { - "node": ">=22.18.0" - }, - "funding": { - "url": "https://github.com/streetsidesoftware/cspell?sponsor=1" - } - }, - "node_modules/cspell-config-lib": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell-config-lib/-/cspell-config-lib-10.0.1.tgz", - "integrity": "sha512-hMpo/0j6k7pbiqrLDOLJKD2IGP9XwhjKf2miiM6p84Xeo4nyuFZaxxDCQ68R851HSYFrrdltgpoipMbj1h2Tnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/cspell-types": "10.0.1", - "comment-json": "^5.0.0", - "smol-toml": "^1.6.1", - "yaml": "^2.9.0" - }, - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/cspell-dictionary": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-10.0.1.tgz", - "integrity": "sha512-3cZ659vgsZWkzGQJR/sNqGDVt/OnvTSieLKI76V++4t1bHJfochb9ZrrwsuMsb1VPGiyqClUP1/O6WrefF/FVg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/cspell-performance-monitor": "10.0.1", - "@cspell/cspell-pipe": "10.0.1", - "@cspell/cspell-types": "10.0.1", - "cspell-trie-lib": "10.0.1", - "fast-equals": "^6.0.0" - }, - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/cspell-gitignore": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-10.0.1.tgz", - "integrity": "sha512-wN23U61Mx6qPJN3CesOmBU9vnbJ0jQm/ylK0iaVui3CcnO7Zzl5qLu5mPHUzGQGm8yso6qjyxqo16Ho7LpZGOQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/url": "10.0.1", - "cspell-glob": "10.0.1", - "cspell-io": "10.0.1" - }, - "bin": { - "cspell-gitignore": "bin.mjs" - }, - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/cspell-glob": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-10.0.1.tgz", - "integrity": "sha512-7bII9J3aSSpZDwhx7w+zfQXbMxHZQ3be0ilUp5bHrsjz6o07v/NqOHMGcwKdPn1sw2dxDz9sv057xE5pqXnSdw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/url": "10.0.1", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/cspell-grammar": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-10.0.1.tgz", - "integrity": "sha512-xC9AFYmaI9wsO//a7S5tdDGKGJVD5UEEsTg+Up2fi7lPfXIryisYmV6tePNL1SEg0idYss4ja8LUZ3Mib09BjQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/cspell-pipe": "10.0.1", - "@cspell/cspell-types": "10.0.1" - }, - "bin": { - "cspell-grammar": "bin.mjs" - }, - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/cspell-io": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-10.0.1.tgz", - "integrity": "sha512-8C2ka07faxflnaqEBO3pektS21XViE/SEHT7F5ZD1ou7FyMR5u3xawTBJSczClfsxLt/WYeztBYrpmGAjmjksw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/cspell-service-bus": "10.0.1", - "@cspell/url": "10.0.1" - }, - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/cspell-lib": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-10.0.1.tgz", - "integrity": "sha512-RpsIPiLzc4/YMW8BMRKpyJ81x439qjYWcqgdKeXnMkbKM88J9PexzutfFf/4v97v96KzfNitEzMpbI0uj8OeUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/cspell-bundled-dicts": "10.0.1", - "@cspell/cspell-performance-monitor": "10.0.1", - "@cspell/cspell-pipe": "10.0.1", - "@cspell/cspell-resolver": "10.0.1", - "@cspell/cspell-types": "10.0.1", - "@cspell/dynamic-import": "10.0.1", - "@cspell/filetypes": "10.0.1", - "@cspell/rpc": "10.0.1", - "@cspell/strong-weak-map": "10.0.1", - "@cspell/url": "10.0.1", - "cspell-config-lib": "10.0.1", - "cspell-dictionary": "10.0.1", - "cspell-glob": "10.0.1", - "cspell-grammar": "10.0.1", - "cspell-io": "10.0.1", - "cspell-trie-lib": "10.0.1", - "env-paths": "^4.0.0", - "gensequence": "^8.0.8", - "import-fresh": "^4.0.0", - "resolve-from": "^5.0.0", - "vscode-languageserver-textdocument": "^1.0.12", - "vscode-uri": "^3.1.0", - "xdg-basedir": "^5.1.0" - }, - "engines": { - "node": ">=22.18.0" - } - }, - "node_modules/cspell-trie-lib": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-10.0.1.tgz", - "integrity": "sha512-BFvhalSkRQFjKrZ//FKK7fRGrZFpifnxB5AwCkzsIsBZqicsfafcQ1xP21qpb0QqyV/IomjNgviG+tRJs+0rMw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.18.0" - }, - "peerDependencies": { - "@cspell/cspell-types": "10.0.1" - } - }, - "node_modules/cspell/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "node_modules/css-tree": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", @@ -3754,6 +2925,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=8" @@ -3835,22 +3007,6 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "node_modules/env-paths": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-4.0.0.tgz", - "integrity": "sha512-pxP8eL2SwwaTRi/KHYwLYXinDs7gL3jxFcBYmEdYfZmZXbaVDvdppd0XBU8qVz03rDfKZMXg1omHCbsJjZrMsw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-safe-filename": "^0.1.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/esbuild": { "version": "0.27.7", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", @@ -3902,20 +3058,6 @@ "node": ">=6" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", @@ -3936,23 +3078,6 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "node_modules/fast-equals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-6.0.0.tgz", - "integrity": "sha512-PFhhIGgdM79r5Uztdj9Zb6Tt1zKafqVfdMGwVca1z5z6fbX7DmsySSuJd8HiP6I1j505DCS83cLxo5rmSNeVEA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, "node_modules/fast-string-truncated-width": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", @@ -4036,13 +3161,6 @@ "fxparser": "src/cli/cli.js" } }, - "node_modules/flatted": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", - "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", - "dev": true, - "license": "ISC" - }, "node_modules/flattie": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/flattie/-/flattie-1.1.1.tgz", @@ -4090,16 +3208,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/gensequence": { - "version": "8.0.8", - "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-8.0.8.tgz", - "integrity": "sha512-omMVniXEXpdx/vKxGnPRoO2394Otlze28TyxECbFVyoSpZ9H3EO7lemjcB12OpQJzRW4e5tt/dL1rOxry6aMHg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - } - }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -4133,22 +3241,6 @@ "dev": true, "license": "ISC" }, - "node_modules/global-directory": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-5.0.0.tgz", - "integrity": "sha512-1pgFdhK3J2LeM+dVf2Pd424yHx2ou338lC0ErNP2hPx4j8eW1Sp0XqSjNxtk6Tc4Kr5wlWtSvz8cn2yb7/SG/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ini": "6.0.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/h3": { "version": "1.15.11", "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.11.tgz", @@ -4407,40 +3499,6 @@ "dev": true, "license": "BSD-2-Clause" }, - "node_modules/import-fresh": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-4.0.0.tgz", - "integrity": "sha512-Fpi660c7VPDM3fPKYovStd9IP1CPOikf6v/dGxJJMmHPcwYQIMJ4W7kO1avBYEpMqkCh+Dx3Ln6H7VYqgztLjw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.15" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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/ini": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", - "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/iron-webcrypto": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz", @@ -4493,19 +3551,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-safe-filename": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-safe-filename/-/is-safe-filename-0.1.1.tgz", - "integrity": "sha512-4SrR7AdnY11LHfDKTZY1u6Ga3RuxZdl3YKWWShO5iyuG5h8QS4GD2tOb04peBJ5I7pXbR+CGBNEhTcwK+FzN3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/js-yaml": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", @@ -5717,19 +4762,6 @@ "dev": true, "license": "ISC" }, - "node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/playwright": { "version": "1.59.1", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.1.tgz", @@ -5797,7 +4829,6 @@ "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -5814,7 +4845,6 @@ "integrity": "sha512-RiBETaaP9veVstE4vUwSIcdATj6dKmXljouXc/DDNwBSPTp8FRkLGDSGFClKsAFeeg+13SB0Z1JZvbD76bigJw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@astrojs/compiler": "^2.9.1", "prettier": "^3.0.0", @@ -6093,16 +5123,6 @@ "node": ">=0.10.0" } }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", @@ -6184,7 +5204,6 @@ "integrity": "sha512-pAQK9HalE84QSm4Po3EmWIZPd3FnjkShVkiMlz1iligWYkWQ7wHYd1PF/T7QZ5TVSD6uSTon5gBVMSM4JfBV+A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -6252,9 +5271,10 @@ } }, "node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -6267,6 +5287,7 @@ "version": "0.34.5", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "dev": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -6500,6 +5521,19 @@ } } }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -6526,6 +5560,7 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true, "optional": true }, "node_modules/typesafe-path": { @@ -6541,7 +5576,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -7237,19 +6271,6 @@ "node": ">=4" } }, - "node_modules/xdg-basedir": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", - "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/xml-naming": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz", @@ -7328,7 +6349,6 @@ "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -7473,6 +6493,14 @@ "dev": true, "requires": { "picomatch": "^4.0.4" + }, + "dependencies": { + "picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true + } } }, "@astrojs/language-server": { @@ -7693,524 +6721,6 @@ "sisteransi": "^1.0.5" } }, - "@cspell/cspell-bundled-dicts": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-10.0.1.tgz", - "integrity": "sha512-WvkSDNX4Uyyj/ZgbPO6L38iFNMfK1EqsH1FteRiI2qLz6QZMXRFrIt12OqiWIplzZDDaVpBH9FCJOPJll0fjCQ==", - "dev": true, - "requires": { - "@cspell/dict-ada": "^4.1.1", - "@cspell/dict-al": "^1.1.1", - "@cspell/dict-aws": "^4.0.17", - "@cspell/dict-bash": "^4.2.2", - "@cspell/dict-companies": "^3.2.11", - "@cspell/dict-cpp": "^7.0.2", - "@cspell/dict-cryptocurrencies": "^5.0.5", - "@cspell/dict-csharp": "^4.0.8", - "@cspell/dict-css": "^4.1.1", - "@cspell/dict-dart": "^2.3.2", - "@cspell/dict-data-science": "^2.0.13", - "@cspell/dict-django": "^4.1.6", - "@cspell/dict-docker": "^1.1.17", - "@cspell/dict-dotnet": "^5.0.13", - "@cspell/dict-elixir": "^4.0.8", - "@cspell/dict-en_us": "^4.4.33", - "@cspell/dict-en-common-misspellings": "^2.1.12", - "@cspell/dict-en-gb-mit": "^3.1.22", - "@cspell/dict-filetypes": "^3.0.18", - "@cspell/dict-flutter": "^1.1.1", - "@cspell/dict-fonts": "^4.0.6", - "@cspell/dict-fsharp": "^1.1.1", - "@cspell/dict-fullstack": "^3.2.9", - "@cspell/dict-gaming-terms": "^1.1.2", - "@cspell/dict-git": "^3.1.0", - "@cspell/dict-golang": "^6.0.26", - "@cspell/dict-google": "^1.0.9", - "@cspell/dict-haskell": "^4.0.6", - "@cspell/dict-html": "^4.0.15", - "@cspell/dict-html-symbol-entities": "^4.0.5", - "@cspell/dict-java": "^5.0.12", - "@cspell/dict-julia": "^1.1.1", - "@cspell/dict-k8s": "^1.0.12", - "@cspell/dict-kotlin": "^1.1.1", - "@cspell/dict-latex": "^5.1.0", - "@cspell/dict-lorem-ipsum": "^4.0.5", - "@cspell/dict-lua": "^4.0.8", - "@cspell/dict-makefile": "^1.0.5", - "@cspell/dict-markdown": "^2.0.16", - "@cspell/dict-monkeyc": "^1.0.12", - "@cspell/dict-node": "^5.0.9", - "@cspell/dict-npm": "^5.2.38", - "@cspell/dict-php": "^4.1.1", - "@cspell/dict-powershell": "^5.0.15", - "@cspell/dict-public-licenses": "^2.0.16", - "@cspell/dict-python": "^4.2.26", - "@cspell/dict-r": "^2.1.1", - "@cspell/dict-ruby": "^5.1.1", - "@cspell/dict-rust": "^4.1.2", - "@cspell/dict-scala": "^5.0.9", - "@cspell/dict-shell": "^1.1.2", - "@cspell/dict-software-terms": "^5.2.2", - "@cspell/dict-sql": "^2.2.1", - "@cspell/dict-svelte": "^1.0.7", - "@cspell/dict-swift": "^2.0.6", - "@cspell/dict-terraform": "^1.1.3", - "@cspell/dict-typescript": "^3.2.3", - "@cspell/dict-vue": "^3.0.5", - "@cspell/dict-zig": "^1.0.0" - } - }, - "@cspell/cspell-json-reporter": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-json-reporter/-/cspell-json-reporter-10.0.1.tgz", - "integrity": "sha512-/nes1RGILec3WCBcoMOd0byNTBtnJuPaVz/+ZzqYkLtY7x58VMcBG5kyP6hPyN8cIwjRADE/SR43gwdXuqk/FA==", - "dev": true, - "requires": { - "@cspell/cspell-types": "10.0.1" - } - }, - "@cspell/cspell-performance-monitor": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-performance-monitor/-/cspell-performance-monitor-10.0.1.tgz", - "integrity": "sha512-9tVcHXwRnbazUv4WSG0h3MqV4+LgmLNgSALAQUflPPW0EMxTf7C4Dmv9cgxJyCEQrdnVKCr58nPPaahhz9LJUg==", - "dev": true - }, - "@cspell/cspell-pipe": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-10.0.1.tgz", - "integrity": "sha512-HPeXMD9AZ3V/qPkvQaPcak+C7cJ2z7JTHN8smd6J8L2aThLRky2cHc2OyeaHPSHB7WA47b4z2n5u5nawZhv5VQ==", - "dev": true - }, - "@cspell/cspell-resolver": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-resolver/-/cspell-resolver-10.0.1.tgz", - "integrity": "sha512-PIzkZHD1fGUQx1XteK2d1iQ0Mzq/maYcoB4jkvAiiR6WqP3MWYNKFdI9z+R5pOq5KgMfW+5Ig1q0oSR6h8irlA==", - "dev": true, - "requires": { - "global-directory": "^5.0.0" - } - }, - "@cspell/cspell-service-bus": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-10.0.1.tgz", - "integrity": "sha512-y6NcIGP2IdXaBL4PVH8vxsr7K27wzz3Ech87UtUtrDSXAiVEOvXgAIknEOUVp59rTlUE8Rn4IRURC6f/hgMyfw==", - "dev": true - }, - "@cspell/cspell-types": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-10.0.1.tgz", - "integrity": "sha512-kLgLShnWADDVreKC63pBrWkcvxgZzFIfO34Jhx/SWfuOIA3cD8AXT+HjyuLfoGJ7mUb58hv2kUziKzEy4INb1w==", - "dev": true, - "peer": true - }, - "@cspell/cspell-worker": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/cspell-worker/-/cspell-worker-10.0.1.tgz", - "integrity": "sha512-L2bJerfuYOls2wEknm8FmynLtj/G7O4UqX9I/HznRggEW6i2yZIxagDetpVDNowpyavNHJ3SJtUFiyMiZc16Sw==", - "dev": true, - "requires": { - "cspell-lib": "10.0.1" - } - }, - "@cspell/dict-ada": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-4.1.1.tgz", - "integrity": "sha512-E+0YW9RhZod/9Qy2gxfNZiHJjCYFlCdI69br1eviQQWB8yOTJX0JHXLs79kOYhSW0kINPVUdvddEBe6Lu6CjGQ==", - "dev": true - }, - "@cspell/dict-al": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-al/-/dict-al-1.1.1.tgz", - "integrity": "sha512-sD8GCaZetgQL4+MaJLXqbzWcRjfKVp8x+px3HuCaaiATAAtvjwUQ5/Iubiqwfd1boIh2Y1/3EgM3TLQ7Q8e0wQ==", - "dev": true - }, - "@cspell/dict-aws": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-4.0.17.tgz", - "integrity": "sha512-ORcblTWcdlGjIbWrgKF+8CNEBQiLVKdUOFoTn0KPNkAYnFcdPP0muT4892h7H4Xafh3j72wqB4/loQ6Nti9E/w==", - "dev": true - }, - "@cspell/dict-bash": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-4.2.3.tgz", - "integrity": "sha512-ljUZoKHbDqw5Sx0qpL2qTUlmkmr+vhZH/sCNrNaBZKTbdgiswErSnIF1jRbGmEitJNxHRHWsuZyVgnTGfVO1Yw==", - "dev": true, - "requires": { - "@cspell/dict-shell": "1.2.0" - } - }, - "@cspell/dict-companies": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-3.2.11.tgz", - "integrity": "sha512-0cmafbcz2pTHXLd59eLR1gvDvN6aWAOM0+cIL4LLF9GX9yB2iKDNrKsvs4tJRqutoaTdwNFBbV0FYv+6iCtebQ==", - "dev": true - }, - "@cspell/dict-cpp": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-7.0.2.tgz", - "integrity": "sha512-dfbeERiVNeqmo/npivdR6rDiBCqZi3QtjH2Z0HFcXwpdj6i97dX1xaKyK2GUsO/p4u1TOv63Dmj5Vm48haDpuA==", - "dev": true - }, - "@cspell/dict-cryptocurrencies": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-5.0.5.tgz", - "integrity": "sha512-R68hYYF/rtlE6T/dsObStzN5QZw+0aQBinAXuWCVqwdS7YZo0X33vGMfChkHaiCo3Z2+bkegqHlqxZF4TD3rUA==", - "dev": true - }, - "@cspell/dict-csharp": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-4.0.8.tgz", - "integrity": "sha512-qmk45pKFHSxckl5mSlbHxmDitSsGMlk/XzFgt7emeTJWLNSTUK//MbYAkBNRtfzB4uD7pAFiKgpKgtJrTMRnrQ==", - "dev": true - }, - "@cspell/dict-css": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-4.1.2.tgz", - "integrity": "sha512-+ylGoKdwZ2sVOCOnU2Eq5wDZx+RaVX3HoKyNHGGsFvhSw6IidQ6tH/mAPKBDofViHJoWCPNlklE0lTr6MDG3QA==", - "dev": true, - "peer": true - }, - "@cspell/dict-dart": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-2.3.2.tgz", - "integrity": "sha512-sUiLW56t9gfZcu8iR/5EUg+KYyRD83Cjl3yjDEA2ApVuJvK1HhX+vn4e4k4YfjpUQMag8XO2AaRhARE09+/rqw==", - "dev": true - }, - "@cspell/dict-data-science": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/@cspell/dict-data-science/-/dict-data-science-2.0.14.tgz", - "integrity": "sha512-jl6Ds4u5u5JT+yY30pWQpAbdCHfy3lCcNkLbpL/AZKoUaLEoXbaYsps9xQtvD7DyaiXxiLZkdH2yHHXtoFtZyg==", - "dev": true - }, - "@cspell/dict-django": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-4.1.6.tgz", - "integrity": "sha512-SdbSFDGy9ulETqNz15oWv2+kpWLlk8DJYd573xhIkeRdcXOjskRuxjSZPKfW7O3NxN/KEf3gm3IevVOiNuFS+w==", - "dev": true - }, - "@cspell/dict-docker": { - "version": "1.1.17", - "resolved": "https://registry.npmjs.org/@cspell/dict-docker/-/dict-docker-1.1.17.tgz", - "integrity": "sha512-OcnVTIpHIYYKhztNTyK8ShAnXTfnqs43hVH6p0py0wlcwRIXe5uj4f12n7zPf2CeBI7JAlPjEsV0Rlf4hbz/xQ==", - "dev": true - }, - "@cspell/dict-dotnet": { - "version": "5.0.13", - "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-5.0.13.tgz", - "integrity": "sha512-xPp7jMnFpOri7tzmqmm/dXMolXz1t2bhNqxYkOyMqXhvs08oc7BFs+EsbDY0X7hqiISgeFZGNqn0dOCr+ncPYw==", - "dev": true - }, - "@cspell/dict-elixir": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-4.0.8.tgz", - "integrity": "sha512-CyfphrbMyl4Ms55Vzuj+mNmd693HjBFr9hvU+B2YbFEZprE5AG+EXLYTMRWrXbpds4AuZcvN3deM2XVB80BN/Q==", - "dev": true - }, - "@cspell/dict-en_us": { - "version": "4.4.35", - "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-4.4.35.tgz", - "integrity": "sha512-xWpxBCc/FzzMMo/A+0qwARVaIIhR0Ql8yhhv4rvsvg+GfQF+LG9yzg2GwTM5N2rjvzmM3nKuR9zxFZq2I6fJSg==", - "dev": true - }, - "@cspell/dict-en-common-misspellings": { - "version": "2.1.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-en-common-misspellings/-/dict-en-common-misspellings-2.1.12.tgz", - "integrity": "sha512-14Eu6QGqyksqOd4fYPuRb58lK1Va7FQK9XxFsRKnZU8LhL3N+kj7YKDW+7aIaAN/0WGEqslGP6lGbQzNti8Akw==", - "dev": true - }, - "@cspell/dict-en-gb-mit": { - "version": "3.1.24", - "resolved": "https://registry.npmjs.org/@cspell/dict-en-gb-mit/-/dict-en-gb-mit-3.1.24.tgz", - "integrity": "sha512-Oowb/Uzkh7OmDRdCcETzMc9imEb4IpLlHJXoYjX8A8DS2X/54gqSjI915JFB8hKtFjBko5OM0BLQ+6cZhFEMmQ==", - "dev": true - }, - "@cspell/dict-filetypes": { - "version": "3.0.18", - "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-3.0.18.tgz", - "integrity": "sha512-yU7RKD/x1IWmDLzWeiItMwgV+6bUcU/af23uS0+uGiFUbsY1qWV/D4rxlAAO6Z7no3J2z8aZOkYIOvUrJq0Rcw==", - "dev": true - }, - "@cspell/dict-flutter": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-flutter/-/dict-flutter-1.1.1.tgz", - "integrity": "sha512-UlOzRcH2tNbFhZmHJN48Za/2/MEdRHl2BMkCWZBYs+30b91mWvBfzaN4IJQU7dUZtowKayVIF9FzvLZtZokc5A==", - "dev": true - }, - "@cspell/dict-fonts": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-4.0.6.tgz", - "integrity": "sha512-aR/0csY01dNb0A1tw/UmN9rKgHruUxsYsvXu6YlSBJFu60s26SKr/k1o4LavpHTQ+lznlYMqAvuxGkE4Flliqw==", - "dev": true - }, - "@cspell/dict-fsharp": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-fsharp/-/dict-fsharp-1.1.1.tgz", - "integrity": "sha512-imhs0u87wEA4/cYjgzS0tAyaJpwG7vwtC8UyMFbwpmtw+/bgss+osNfyqhYRyS/ehVCWL17Ewx2UPkexjKyaBA==", - "dev": true - }, - "@cspell/dict-fullstack": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-3.2.9.tgz", - "integrity": "sha512-diZX+usW5aZ4/b2T0QM/H/Wl9aNMbdODa1Jq0ReBr/jazmNeWjd+PyqeVgzd1joEaHY+SAnjrf/i9CwKd2ZtWQ==", - "dev": true - }, - "@cspell/dict-gaming-terms": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-gaming-terms/-/dict-gaming-terms-1.1.2.tgz", - "integrity": "sha512-9XnOvaoTBscq0xuD6KTEIkk9hhdfBkkvJAIsvw3JMcnp1214OCGW8+kako5RqQ2vTZR3Tnf3pc57o7VgkM0q1Q==", - "dev": true - }, - "@cspell/dict-git": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-git/-/dict-git-3.1.0.tgz", - "integrity": "sha512-KEt9zGkxqGy2q1nwH4CbyqTSv5nadpn8BAlDnzlRcnL0Xb3LX9xTgSGShKvzb0bw35lHoYyLWN2ZKAqbC4pgGQ==", - "dev": true - }, - "@cspell/dict-golang": { - "version": "6.0.26", - "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-6.0.26.tgz", - "integrity": "sha512-YKA7Xm5KeOd14v5SQ4ll6afe9VSy3a2DWM7L9uBq4u3lXToRBQ1W5PRa+/Q9udd+DTURyVVnQ+7b9cnOlNxaRg==", - "dev": true - }, - "@cspell/dict-google": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@cspell/dict-google/-/dict-google-1.0.9.tgz", - "integrity": "sha512-biL65POqialY0i4g6crj7pR6JnBkbsPovB2WDYkj3H4TuC/QXv7Pu5pdPxeUJA6TSCHI7T5twsO4VSVyRxD9CA==", - "dev": true - }, - "@cspell/dict-haskell": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-4.0.6.tgz", - "integrity": "sha512-ib8SA5qgftExpYNjWhpYIgvDsZ/0wvKKxSP+kuSkkak520iPvTJumEpIE+qPcmJQo4NzdKMN8nEfaeci4OcFAQ==", - "dev": true - }, - "@cspell/dict-html": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-4.0.15.tgz", - "integrity": "sha512-GJYnYKoD9fmo2OI0aySEGZOjThnx3upSUvV7mmqUu8oG+mGgzqm82P/f7OqsuvTaInZZwZbo+PwJQd/yHcyFIw==", - "dev": true, - "peer": true - }, - "@cspell/dict-html-symbol-entities": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-4.0.5.tgz", - "integrity": "sha512-429alTD4cE0FIwpMucvSN35Ld87HCyuM8mF731KU5Rm4Je2SG6hmVx7nkBsLyrmH3sQukTcr1GaiZsiEg8svPA==", - "dev": true, - "peer": true - }, - "@cspell/dict-java": { - "version": "5.0.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-5.0.12.tgz", - "integrity": "sha512-qPSNhTcl7LGJ5Qp6VN71H8zqvRQK04S08T67knMq9hTA8U7G1sTKzLmBaDOFhq17vNX/+rT+rbRYp+B5Nwza1A==", - "dev": true - }, - "@cspell/dict-julia": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-julia/-/dict-julia-1.1.1.tgz", - "integrity": "sha512-WylJR9TQ2cgwd5BWEOfdO3zvDB+L7kYFm0I9u0s9jKHWQ6yKmfKeMjU9oXxTBxIufhCXm92SKwwVNAC7gjv+yA==", - "dev": true - }, - "@cspell/dict-k8s": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-k8s/-/dict-k8s-1.0.12.tgz", - "integrity": "sha512-2LcllTWgaTfYC7DmkMPOn9GsBWsA4DZdlun4po8s2ysTP7CPEnZc1ZfK6pZ2eI4TsZemlUQQ+NZxMe9/QutQxg==", - "dev": true - }, - "@cspell/dict-kotlin": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-kotlin/-/dict-kotlin-1.1.1.tgz", - "integrity": "sha512-J3NzzfgmxRvEeOe3qUXnSJQCd38i/dpF9/t3quuWh6gXM+krsAXP75dY1CzDmS8mrJAlBdVBeAW5eAZTD8g86Q==", - "dev": true - }, - "@cspell/dict-latex": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-5.1.0.tgz", - "integrity": "sha512-qxT4guhysyBt0gzoliXYEBYinkAdEtR2M7goRaUH0a7ltCsoqqAeEV8aXYRIdZGcV77gYSobvu3jJL038tlPAw==", - "dev": true - }, - "@cspell/dict-lorem-ipsum": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-4.0.5.tgz", - "integrity": "sha512-9a4TJYRcPWPBKkQAJ/whCu4uCAEgv/O2xAaZEI0n4y1/l18Yyx8pBKoIX5QuVXjjmKEkK7hi5SxyIsH7pFEK9Q==", - "dev": true - }, - "@cspell/dict-lua": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-4.0.8.tgz", - "integrity": "sha512-N4PkgNDMu9JVsRu7JBS/3E/dvfItRgk9w5ga2dKq+JupP2Y3lojNaAVFhXISh4Y0a6qXDn2clA6nvnavQ/jjLA==", - "dev": true - }, - "@cspell/dict-makefile": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-makefile/-/dict-makefile-1.0.5.tgz", - "integrity": "sha512-4vrVt7bGiK8Rx98tfRbYo42Xo2IstJkAF4tLLDMNQLkQ86msDlYSKG1ZCk8Abg+EdNcFAjNhXIiNO+w4KflGAQ==", - "dev": true - }, - "@cspell/dict-markdown": { - "version": "2.0.17", - "resolved": "https://registry.npmjs.org/@cspell/dict-markdown/-/dict-markdown-2.0.17.tgz", - "integrity": "sha512-H8bAxih6U8NOnSPL7R8My+tqjaB4tmnJTjERuz4zYqmf+cH+5xshX3UVgKlwWFcyjsYfv/zEDuRdMctQv1q6HQ==", - "dev": true, - "requires": {} - }, - "@cspell/dict-monkeyc": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-monkeyc/-/dict-monkeyc-1.0.12.tgz", - "integrity": "sha512-MN7Vs11TdP5mbdNFQP5x2Ac8zOBm97ARg6zM5Sb53YQt/eMvXOMvrep7+/+8NJXs0jkp70bBzjqU4APcqBFNAw==", - "dev": true - }, - "@cspell/dict-node": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-5.0.9.tgz", - "integrity": "sha512-hO+ga+uYZ/WA4OtiMEyKt5rDUlUyu3nXMf8KVEeqq2msYvAPdldKBGH7lGONg6R/rPhv53Rb+0Y1SLdoK1+7wQ==", - "dev": true - }, - "@cspell/dict-npm": { - "version": "5.2.41", - "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-5.2.41.tgz", - "integrity": "sha512-To3xsfRmMBYVXtWVEdUgV35M9a/JZ54dSuoY6m6D3uHKKL3I326Wmy4xifZ3PU8MQaWhyEH7zbIcUEtKwTQMcA==", - "dev": true - }, - "@cspell/dict-php": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-4.1.1.tgz", - "integrity": "sha512-EXelI+4AftmdIGtA8HL8kr4WlUE11OqCSVlnIgZekmTkEGSZdYnkFdiJ5IANSALtlQ1mghKjz+OFqVs6yowgWA==", - "dev": true - }, - "@cspell/dict-powershell": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-5.0.15.tgz", - "integrity": "sha512-l4S5PAcvCFcVDMJShrYD0X6Huv9dcsQPlsVsBGbH38wvuN7gS7+GxZFAjTNxDmTY1wrNi1cCatSg6Pu2BW4rgg==", - "dev": true - }, - "@cspell/dict-public-licenses": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-2.0.16.tgz", - "integrity": "sha512-EQRrPvEOmwhwWezV+W7LjXbIBjiy6y/shrET6Qcpnk3XANTzfvWflf9PnJ5kId/oKWvihFy0za0AV1JHd03pSQ==", - "dev": true - }, - "@cspell/dict-python": { - "version": "4.2.27", - "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-4.2.27.tgz", - "integrity": "sha512-Rj6xQgYS4X6ienjgAZF+njA0GRY4oSPouJWv0vfikCTn6EWlfk0V6Dy1HP3Migj1O+IC2NmespgVq+BZNSp8OA==", - "dev": true, - "requires": { - "@cspell/dict-data-science": "^2.0.14" - } - }, - "@cspell/dict-r": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-r/-/dict-r-2.1.1.tgz", - "integrity": "sha512-71Ka+yKfG4ZHEMEmDxc6+blFkeTTvgKbKAbwiwQAuKl3zpqs1Y0vUtwW2N4b3LgmSPhV3ODVY0y4m5ofqDuKMw==", - "dev": true - }, - "@cspell/dict-ruby": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-5.1.1.tgz", - "integrity": "sha512-LHrp84oEV6q1ZxPPyj4z+FdKyq1XAKYPtmGptrd+uwHbrF/Ns5+fy6gtSi7pS+uc0zk3JdO9w/tPK+8N1/7WUA==", - "dev": true - }, - "@cspell/dict-rust": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-4.1.2.tgz", - "integrity": "sha512-O1FHrumYcO+HZti3dHfBPUdnDFkI+nbYK3pxYmiM1sr+G0ebOd6qchmswS0Wsc6ZdEVNiPYJY/gZQR6jfW3uOg==", - "dev": true - }, - "@cspell/dict-scala": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-5.0.9.tgz", - "integrity": "sha512-AjVcVAELgllybr1zk93CJ5wSUNu/Zb5kIubymR/GAYkMyBdYFCZ3Zbwn4Zz8GJlFFAbazABGOu0JPVbeY59vGg==", - "dev": true - }, - "@cspell/dict-shell": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-shell/-/dict-shell-1.2.0.tgz", - "integrity": "sha512-PVctvT22lJ49niMiakO8xieY7ELCAzjSqhejWR7bAMb5AZ9F4WDEs+XdGMnoVHWeXq7K5rcepLPmEJb+37zzIw==", - "dev": true - }, - "@cspell/dict-software-terms": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-5.2.2.tgz", - "integrity": "sha512-0CaYd6TAsKtEoA7tNswm1iptEblTzEe3UG8beG2cpSTHk7afWIVMtJLgXDv0f/Li67Lf3Z1Jf3JeXR7GsJ2TRw==", - "dev": true - }, - "@cspell/dict-sql": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-sql/-/dict-sql-2.2.1.tgz", - "integrity": "sha512-qDHF8MpAYCf4pWU8NKbnVGzkoxMNrFqBHyG/dgrlic5EQiKANCLELYtGlX5auIMDLmTf1inA0eNtv74tyRJ/vg==", - "dev": true - }, - "@cspell/dict-svelte": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@cspell/dict-svelte/-/dict-svelte-1.0.7.tgz", - "integrity": "sha512-hGZsGqP0WdzKkdpeVLBivRuSNzOTvN036EBmpOwxH+FTY2DuUH7ecW+cSaMwOgmq5JFSdTcbTNFlNC8HN8lhaQ==", - "dev": true - }, - "@cspell/dict-swift": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@cspell/dict-swift/-/dict-swift-2.0.6.tgz", - "integrity": "sha512-PnpNbrIbex2aqU1kMgwEKvCzgbkHtj3dlFLPMqW1vSniop7YxaDTtvTUO4zA++ugYAEL+UK8vYrBwDPTjjvSnA==", - "dev": true - }, - "@cspell/dict-terraform": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-terraform/-/dict-terraform-1.1.3.tgz", - "integrity": "sha512-gr6wxCydwSFyyBKhBA2xkENXtVFToheqYYGFvlMZXWjviynXmh+NK/JTvTCk/VHk3+lzbO9EEQKee6VjrAUSbA==", - "dev": true - }, - "@cspell/dict-typescript": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-3.2.3.tgz", - "integrity": "sha512-zXh1wYsNljQZfWWdSPYwQhpwiuW0KPW1dSd8idjMRvSD0aSvWWHoWlrMsmZeRl4qM4QCEAjua8+cjflm41cQBg==", - "dev": true, - "peer": true - }, - "@cspell/dict-vue": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-vue/-/dict-vue-3.0.5.tgz", - "integrity": "sha512-Mqutb8jbM+kIcywuPQCCaK5qQHTdaByoEO2J9LKFy3sqAdiBogNkrplqUK0HyyRFgCfbJUgjz3N85iCMcWH0JA==", - "dev": true - }, - "@cspell/dict-zig": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-zig/-/dict-zig-1.0.0.tgz", - "integrity": "sha512-XibBIxBlVosU06+M6uHWkFeT0/pW5WajDRYdXG2CgHnq85b0TI/Ks0FuBJykmsgi2CAD3Qtx8UHFEtl/DSFnAQ==", - "dev": true - }, - "@cspell/dynamic-import": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/dynamic-import/-/dynamic-import-10.0.1.tgz", - "integrity": "sha512-mP1gdq00aIcH8HxNMqnH11X6BKxLcneDtFgl/ecjIKnaGKwi44m8AndP5Kr4ODaYdl8UUw9O3dJh7KaQXnLHZQ==", - "dev": true, - "requires": { - "@cspell/url": "10.0.1", - "import-meta-resolve": "^4.2.0" - } - }, - "@cspell/filetypes": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/filetypes/-/filetypes-10.0.1.tgz", - "integrity": "sha512-Z5S35giU5IW49fBBq6BksUbE8PC4IYPfaKuwl5Nl9jkf/OkAKiBmCowKX45NzRUQInwK/GSqqIUifrNeI6LdLw==", - "dev": true - }, - "@cspell/rpc": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/rpc/-/rpc-10.0.1.tgz", - "integrity": "sha512-axSRKv3zEAmBm66iD/FV/MPmE4/Yf7c3PZiwTW894Yd3iEhtn3KPKeTrqQ2/tDrhB1Z2qTsap/Hue0MK4o5WXg==", - "dev": true - }, - "@cspell/strong-weak-map": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/strong-weak-map/-/strong-weak-map-10.0.1.tgz", - "integrity": "sha512-lenN1DVyPi8nJLSMSJJ670ddTjyiruLueuSZO1qLcxBqUhgxDt/mALu9N/1m6WdOVcg6m/5cLiZVg2KOo2UzRw==", - "dev": true - }, - "@cspell/url": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@cspell/url/-/url-10.0.1.tgz", - "integrity": "sha512-abYYgI29wJhWIfWTYrYuzRYDcHQUQ1N5ylnhxYn1NJnIQMqUWGLbDmt12JABtZ+R6h6UNatQrS7rhP86etvJyQ==", - "dev": true - }, "@emmetio/abbreviation": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/@emmetio/abbreviation/-/abbreviation-2.3.3.tgz", @@ -8270,6 +6780,7 @@ "version": "1.10.0", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, "optional": true, "requires": { "tslib": "^2.4.0" @@ -8460,12 +6971,14 @@ "@img/colour": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", - "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==" + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "dev": true }, "@img/sharp-darwin-arm64": { "version": "0.34.5", "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "dev": true, "optional": true, "requires": { "@img/sharp-libvips-darwin-arm64": "1.2.4" @@ -8475,6 +6988,7 @@ "version": "0.34.5", "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "dev": true, "optional": true, "requires": { "@img/sharp-libvips-darwin-x64": "1.2.4" @@ -8484,66 +6998,77 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "dev": true, "optional": true }, "@img/sharp-libvips-darwin-x64": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "dev": true, "optional": true }, "@img/sharp-libvips-linux-arm": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "dev": true, "optional": true }, "@img/sharp-libvips-linux-arm64": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "dev": true, "optional": true }, "@img/sharp-libvips-linux-ppc64": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "dev": true, "optional": true }, "@img/sharp-libvips-linux-riscv64": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "dev": true, "optional": true }, "@img/sharp-libvips-linux-s390x": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "dev": true, "optional": true }, "@img/sharp-libvips-linux-x64": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "dev": true, "optional": true }, "@img/sharp-libvips-linuxmusl-arm64": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "dev": true, "optional": true }, "@img/sharp-libvips-linuxmusl-x64": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "dev": true, "optional": true }, "@img/sharp-linux-arm": { "version": "0.34.5", "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "dev": true, "optional": true, "requires": { "@img/sharp-libvips-linux-arm": "1.2.4" @@ -8553,6 +7078,7 @@ "version": "0.34.5", "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "dev": true, "optional": true, "requires": { "@img/sharp-libvips-linux-arm64": "1.2.4" @@ -8562,6 +7088,7 @@ "version": "0.34.5", "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "dev": true, "optional": true, "requires": { "@img/sharp-libvips-linux-ppc64": "1.2.4" @@ -8571,6 +7098,7 @@ "version": "0.34.5", "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "dev": true, "optional": true, "requires": { "@img/sharp-libvips-linux-riscv64": "1.2.4" @@ -8580,6 +7108,7 @@ "version": "0.34.5", "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "dev": true, "optional": true, "requires": { "@img/sharp-libvips-linux-s390x": "1.2.4" @@ -8589,6 +7118,7 @@ "version": "0.34.5", "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "dev": true, "optional": true, "requires": { "@img/sharp-libvips-linux-x64": "1.2.4" @@ -8598,6 +7128,7 @@ "version": "0.34.5", "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "dev": true, "optional": true, "requires": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" @@ -8607,6 +7138,7 @@ "version": "0.34.5", "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "dev": true, "optional": true, "requires": { "@img/sharp-libvips-linuxmusl-x64": "1.2.4" @@ -8616,6 +7148,7 @@ "version": "0.34.5", "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "dev": true, "optional": true, "requires": { "@emnapi/runtime": "^1.7.0" @@ -8625,18 +7158,21 @@ "version": "0.34.5", "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "dev": true, "optional": true }, "@img/sharp-win32-ia32": { "version": "0.34.5", "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "dev": true, "optional": true }, "@img/sharp-win32-x64": { "version": "0.34.5", "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "dev": true, "optional": true }, "@jridgewell/sourcemap-codec": { @@ -8671,6 +7207,14 @@ "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" + }, + "dependencies": { + "picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true + } } }, "@rollup/rollup-android-arm-eabi": { @@ -8976,18 +7520,18 @@ } }, "@types/node": { - "version": "22.19.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.21.tgz", - "integrity": "sha512-VMeFBSCKQKmm2swI2kW51SFusDqekC6q9trBCvJ/JliDchFSuoYYKN7yVNjPthP1HKZcx3U1gI/wTcEBjEFKTA==", + "version": "25.6.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.2.tgz", + "integrity": "sha512-sokuT28dxf9JT5Kady1fsXOvI4HVpjZa95NKT5y9PNTIrs2AsobR4GFAA90ZG8M+nxVRLysCXsVj6eGC7Vbrlw==", "dev": true, "requires": { - "undici-types": "~6.21.0" + "undici-types": "~7.19.0" }, "dependencies": { "undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", "dev": true } } @@ -9156,12 +7700,6 @@ "integrity": "sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==", "dev": true }, - "array-timsort": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", - "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", - "dev": true - }, "astro": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/astro/-/astro-6.3.1.tgz", @@ -9345,6 +7883,12 @@ "yocto-queue": "^1.2.1" } }, + "picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true + }, "svgo": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.1.tgz", @@ -9365,7 +7909,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.3.tgz", "integrity": "sha512-/4XH147Ui7OGTjg3HbdWe5arnZQSbfuRzdr9Ec7TQi5I7R+ir0Rlc9GIvD4v0XZurELqA035KVXJXpR61xhiTA==", "dev": true, - "peer": true, "requires": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -9415,21 +7958,6 @@ "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", "dev": true }, - "chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "dev": true - }, - "chalk-template": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-1.1.2.tgz", - "integrity": "sha512-2bxTP2yUH7AJj/VAXfcA+4IcWGdQ87HwBANLt5XxGTeomo8yG0y95N1um9i5StvhT/Bl0/2cARA5v1PpPXUxUA==", - "dev": true, - "requires": { - "chalk": "^5.2.0" - } - }, "character-entities": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", @@ -9508,22 +8036,6 @@ "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", "dev": true }, - "commander": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", - "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", - "dev": true - }, - "comment-json": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-5.0.0.tgz", - "integrity": "sha512-uiqLcOiVDJtBP8WGkZHEP+FZIhTzP1dxvn59EfoYUi9gqupjrBWVQkO2atDrbnKPwLeotFYDsuNb26uBMqB+hw==", - "dev": true, - "requires": { - "array-timsort": "^1.0.3", - "esprima": "^4.0.1" - } - }, "common-ancestor-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-2.0.0.tgz", @@ -9545,147 +8057,6 @@ "uncrypto": "^0.1.3" } }, - "cspell": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell/-/cspell-10.0.1.tgz", - "integrity": "sha512-Gg6w/flT3fKfl3la62hfTnhtNnDQ+9mU7kUhVqw/axl/Ms4oENw0oJMkWFIoj4f6nL/SDPz7KcPXd2XbkKFNmQ==", - "dev": true, - "requires": { - "@cspell/cspell-json-reporter": "10.0.1", - "@cspell/cspell-performance-monitor": "10.0.1", - "@cspell/cspell-pipe": "10.0.1", - "@cspell/cspell-types": "10.0.1", - "@cspell/cspell-worker": "10.0.1", - "@cspell/dynamic-import": "10.0.1", - "@cspell/url": "10.0.1", - "ansi-regex": "^6.2.2", - "chalk": "^5.6.2", - "chalk-template": "^1.1.2", - "commander": "^14.0.3", - "cspell-config-lib": "10.0.1", - "cspell-dictionary": "10.0.1", - "cspell-gitignore": "10.0.1", - "cspell-glob": "10.0.1", - "cspell-io": "10.0.1", - "cspell-lib": "10.0.1", - "fast-json-stable-stringify": "^2.1.0", - "flatted": "^3.4.2", - "semver": "^7.8.1", - "tinyglobby": "^0.2.16" - }, - "dependencies": { - "ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true - } - } - }, - "cspell-config-lib": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell-config-lib/-/cspell-config-lib-10.0.1.tgz", - "integrity": "sha512-hMpo/0j6k7pbiqrLDOLJKD2IGP9XwhjKf2miiM6p84Xeo4nyuFZaxxDCQ68R851HSYFrrdltgpoipMbj1h2Tnw==", - "dev": true, - "requires": { - "@cspell/cspell-types": "10.0.1", - "comment-json": "^5.0.0", - "smol-toml": "^1.6.1", - "yaml": "^2.9.0" - } - }, - "cspell-dictionary": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-10.0.1.tgz", - "integrity": "sha512-3cZ659vgsZWkzGQJR/sNqGDVt/OnvTSieLKI76V++4t1bHJfochb9ZrrwsuMsb1VPGiyqClUP1/O6WrefF/FVg==", - "dev": true, - "requires": { - "@cspell/cspell-performance-monitor": "10.0.1", - "@cspell/cspell-pipe": "10.0.1", - "@cspell/cspell-types": "10.0.1", - "cspell-trie-lib": "10.0.1", - "fast-equals": "^6.0.0" - } - }, - "cspell-gitignore": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-10.0.1.tgz", - "integrity": "sha512-wN23U61Mx6qPJN3CesOmBU9vnbJ0jQm/ylK0iaVui3CcnO7Zzl5qLu5mPHUzGQGm8yso6qjyxqo16Ho7LpZGOQ==", - "dev": true, - "requires": { - "@cspell/url": "10.0.1", - "cspell-glob": "10.0.1", - "cspell-io": "10.0.1" - } - }, - "cspell-glob": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-10.0.1.tgz", - "integrity": "sha512-7bII9J3aSSpZDwhx7w+zfQXbMxHZQ3be0ilUp5bHrsjz6o07v/NqOHMGcwKdPn1sw2dxDz9sv057xE5pqXnSdw==", - "dev": true, - "requires": { - "@cspell/url": "10.0.1", - "picomatch": "^4.0.4" - } - }, - "cspell-grammar": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-10.0.1.tgz", - "integrity": "sha512-xC9AFYmaI9wsO//a7S5tdDGKGJVD5UEEsTg+Up2fi7lPfXIryisYmV6tePNL1SEg0idYss4ja8LUZ3Mib09BjQ==", - "dev": true, - "requires": { - "@cspell/cspell-pipe": "10.0.1", - "@cspell/cspell-types": "10.0.1" - } - }, - "cspell-io": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-10.0.1.tgz", - "integrity": "sha512-8C2ka07faxflnaqEBO3pektS21XViE/SEHT7F5ZD1ou7FyMR5u3xawTBJSczClfsxLt/WYeztBYrpmGAjmjksw==", - "dev": true, - "requires": { - "@cspell/cspell-service-bus": "10.0.1", - "@cspell/url": "10.0.1" - } - }, - "cspell-lib": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-10.0.1.tgz", - "integrity": "sha512-RpsIPiLzc4/YMW8BMRKpyJ81x439qjYWcqgdKeXnMkbKM88J9PexzutfFf/4v97v96KzfNitEzMpbI0uj8OeUg==", - "dev": true, - "requires": { - "@cspell/cspell-bundled-dicts": "10.0.1", - "@cspell/cspell-performance-monitor": "10.0.1", - "@cspell/cspell-pipe": "10.0.1", - "@cspell/cspell-resolver": "10.0.1", - "@cspell/cspell-types": "10.0.1", - "@cspell/dynamic-import": "10.0.1", - "@cspell/filetypes": "10.0.1", - "@cspell/rpc": "10.0.1", - "@cspell/strong-weak-map": "10.0.1", - "@cspell/url": "10.0.1", - "cspell-config-lib": "10.0.1", - "cspell-dictionary": "10.0.1", - "cspell-glob": "10.0.1", - "cspell-grammar": "10.0.1", - "cspell-io": "10.0.1", - "cspell-trie-lib": "10.0.1", - "env-paths": "^4.0.0", - "gensequence": "^8.0.8", - "import-fresh": "^4.0.0", - "resolve-from": "^5.0.0", - "vscode-languageserver-textdocument": "^1.0.12", - "vscode-uri": "^3.1.0", - "xdg-basedir": "^5.1.0" - } - }, - "cspell-trie-lib": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-10.0.1.tgz", - "integrity": "sha512-BFvhalSkRQFjKrZ//FKK7fRGrZFpifnxB5AwCkzsIsBZqicsfafcQ1xP21qpb0QqyV/IomjNgviG+tRJs+0rMw==", - "dev": true, - "requires": {} - }, "css-tree": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", @@ -9750,7 +8121,8 @@ "detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==" + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true }, "devalue": { "version": "5.8.1", @@ -9801,15 +8173,6 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "env-paths": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-4.0.0.tgz", - "integrity": "sha512-pxP8eL2SwwaTRi/KHYwLYXinDs7gL3jxFcBYmEdYfZmZXbaVDvdppd0XBU8qVz03rDfKZMXg1omHCbsJjZrMsw==", - "dev": true, - "requires": { - "is-safe-filename": "^0.1.0" - } - }, "esbuild": { "version": "0.27.7", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", @@ -9850,12 +8213,6 @@ "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", "dev": true }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, "estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", @@ -9874,18 +8231,6 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "fast-equals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-6.0.0.tgz", - "integrity": "sha512-PFhhIGgdM79r5Uztdj9Zb6Tt1zKafqVfdMGwVca1z5z6fbX7DmsySSuJd8HiP6I1j505DCS83cLxo5rmSNeVEA==", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, "fast-string-truncated-width": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", @@ -9938,12 +8283,6 @@ "strnum": "^2.2.3" } }, - "flatted": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", - "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", - "dev": true - }, "flattie": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/flattie/-/flattie-1.1.1.tgz", @@ -9975,12 +8314,6 @@ "dev": true, "optional": true }, - "gensequence": { - "version": "8.0.8", - "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-8.0.8.tgz", - "integrity": "sha512-omMVniXEXpdx/vKxGnPRoO2394Otlze28TyxECbFVyoSpZ9H3EO7lemjcB12OpQJzRW4e5tt/dL1rOxry6aMHg==", - "dev": true - }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -10002,15 +8335,6 @@ "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", "dev": true }, - "global-directory": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-5.0.0.tgz", - "integrity": "sha512-1pgFdhK3J2LeM+dVf2Pd424yHx2ou338lC0ErNP2hPx4j8eW1Sp0XqSjNxtk6Tc4Kr5wlWtSvz8cn2yb7/SG/w==", - "dev": true, - "requires": { - "ini": "6.0.0" - } - }, "h3": { "version": "1.15.11", "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.11.tgz", @@ -10201,24 +8525,6 @@ "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", "dev": true }, - "import-fresh": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-4.0.0.tgz", - "integrity": "sha512-Fpi660c7VPDM3fPKYovStd9IP1CPOikf6v/dGxJJMmHPcwYQIMJ4W7kO1avBYEpMqkCh+Dx3Ln6H7VYqgztLjw==", - "dev": true - }, - "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 - }, - "ini": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", - "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==", - "dev": true - }, "iron-webcrypto": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz", @@ -10248,12 +8554,6 @@ } } }, - "is-safe-filename": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-safe-filename/-/is-safe-filename-0.1.1.tgz", - "integrity": "sha512-4SrR7AdnY11LHfDKTZY1u6Ga3RuxZdl3YKWWShO5iyuG5h8QS4GD2tOb04peBJ5I7pXbR+CGBNEhTcwK+FzN3g==", - "dev": true - }, "js-yaml": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", @@ -11022,12 +9322,6 @@ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true }, - "picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true - }, "playwright": { "version": "1.59.1", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.1.tgz", @@ -11059,15 +9353,13 @@ "version": "3.8.3", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", - "dev": true, - "peer": true + "dev": true }, "prettier-plugin-astro": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/prettier-plugin-astro/-/prettier-plugin-astro-0.14.1.tgz", "integrity": "sha512-RiBETaaP9veVstE4vUwSIcdATj6dKmXljouXc/DDNwBSPTp8FRkLGDSGFClKsAFeeg+13SB0Z1JZvbD76bigJw==", "dev": true, - "peer": true, "requires": { "@astrojs/compiler": "^2.9.1", "prettier": "^3.0.0", @@ -11268,12 +9560,6 @@ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, "resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", @@ -11330,7 +9616,6 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.3.tgz", "integrity": "sha512-pAQK9HalE84QSm4Po3EmWIZPd3FnjkShVkiMlz1iligWYkWQ7wHYd1PF/T7QZ5TVSD6uSTon5gBVMSM4JfBV+A==", "dev": true, - "peer": true, "requires": { "@rollup/rollup-android-arm-eabi": "4.60.3", "@rollup/rollup-android-arm64": "4.60.3", @@ -11383,14 +9668,16 @@ "dev": true }, "semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==" + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "dev": true }, "sharp": { "version": "0.34.5", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "dev": true, "requires": { "@img/colour": "^1.0.0", "@img/sharp-darwin-arm64": "0.34.5", @@ -11546,6 +9833,12 @@ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, "requires": {} + }, + "picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true } } }, @@ -11565,6 +9858,7 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true, "optional": true }, "typesafe-path": { @@ -11577,8 +9871,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "peer": true + "dev": true }, "typescript-auto-import-cache": { "version": "0.3.6", @@ -11995,12 +10288,6 @@ "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==", "dev": true }, - "xdg-basedir": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", - "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", - "dev": true - }, "xml-naming": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz", @@ -12049,7 +10336,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, - "peer": true, "requires": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", diff --git a/package.json b/package.json index 1236e45..c282e3d 100644 --- a/package.json +++ b/package.json @@ -10,24 +10,22 @@ "scripts": { "dev": "astro dev --host 0.0.0.0 --port 5173", "typecheck": "astro check", - "lint": "prettier --check \"astro.config.mjs\" \"src/**/*.{astro,ts,md,css}\" \"scripts/**/*.mjs\" \"*.md\" \"*.json\"", - "format": "prettier --write \"astro.config.mjs\" \"src/**/*.{astro,ts,md,css}\" \"scripts/**/*.mjs\" \"*.md\" \"*.json\"", + "lint": "prettier --check \"astro.config.mjs\" \"src/**/*.{astro,ts,md,css}\" \"scripts/*.mjs\" \"*.md\" \"*.json\"", + "format": "prettier --write \"astro.config.mjs\" \"src/**/*.{astro,ts,md,css}\" \"scripts/*.mjs\" \"*.md\" \"*.json\"", "build": "astro build", "preview": "astro preview", "audit:astro": "npm run build && node scripts/install-playwright-deps.mjs && node scripts/export-astro-audit.mjs", "qa:astro-audit": "node scripts/install-playwright-deps.mjs && node scripts/export-astro-audit.mjs --fail-on-issues", "qa:no-em-dashes": "node scripts/check-no-em-dashes.mjs", - "qa:spelling": "cspell --no-progress \"astro.config.mjs\" \"src/**/*.{astro,ts,md,css}\" \"scripts/**/*.mjs\" \"*.md\"", - "qa:no-github-links": "node scripts/check-no-github-links.mjs", "qa:links": "node scripts/check-links.mjs", "qa:no-js": "node scripts/check-no-js.mjs", "qa:overflow": "node scripts/install-playwright-deps.mjs && node scripts/check-overflow.mjs", "qa:preview-cropping": "node scripts/install-playwright-deps.mjs && node scripts/check-preview-cropping.mjs", - "qa": "npm run typecheck && npm run lint && npm run qa:no-em-dashes && npm run qa:spelling && npm run qa:no-github-links && npm run build && npm run qa:astro-audit && npm run qa:links && npm run qa:no-js && npm run qa:overflow && npm run qa:preview-cropping" + "qa": "npm run typecheck && npm run lint && npm run qa:no-em-dashes && npm run build && npm run qa:astro-audit && npm run qa:links && npm run qa:no-js && npm run qa:overflow && npm run qa:preview-cropping" }, "repository": { "type": "git", - "url": "git+https://git.schmelczer.dev/andras/schmelczer.dev.git" + "url": "git+https://github.com/schmelczer/schmelczer.github.io.git" }, "keywords": [ "blog", @@ -38,29 +36,27 @@ "author": "Andras Schmelczer", "license": "GPL-3.0-or-later", "bugs": { - "url": "https://git.schmelczer.dev/andras/schmelczer.dev/issues" + "url": "https://github.com/schmelczer/schmelczer.github.io/issues" }, - "homepage": "https://git.schmelczer.dev/andras/schmelczer.dev#readme", + "homepage": "https://github.com/schmelczer/schmelczer.github.io#readme", "devDependencies": { "@astrojs/check": "^0.9.9", "@astrojs/rss": "^4.0.18", "@astrojs/sitemap": "^3.7.2", - "@types/node": "^22.13.0", "astro": "^6.3.1", - "cspell": "^10.0.1", "playwright": "^1.59.1", "prettier": "^3.8.3", "prettier-plugin-astro": "^0.14.1", "rehype-autolink-headings": "^7.1.0", "rehype-slug": "^6.0.0", "typescript": "^5.9.3", - "unist-util-visit": "^5.1.0" + "unist-util-visit": "^5.1.0", + "sharp": "^0.34.5" }, "overrides": { "yaml": "^2.9.0" }, "dependencies": { - "@plausible-analytics/tracker": "^0.4.5", - "sharp": "^0.34.5" + "@plausible-analytics/tracker": "^0.4.5" } } diff --git a/public/media/video/ad_astra.vtt b/public/media/video/ad_astra.vtt new file mode 100644 index 0000000..578c7b6 --- /dev/null +++ b/public/media/video/ad_astra.vtt @@ -0,0 +1,13 @@ +WEBVTT + +00:00.000 --> 00:04.000 +No spoken dialogue. Game audio only. + +00:04.000 --> 00:35.000 +The Ad Astra handheld board runs the game on a small OLED display. + +00:35.000 --> 01:05.000 +The player controls the game through the IR input while the engine updates the display in real time. + +01:05.000 --> 01:34.600 +The clip continues showing gameplay on the custom ATtiny85-based board. diff --git a/scripts/check-links.mjs b/scripts/check-links.mjs index 13cf634..b6f4301 100644 --- a/scripts/check-links.mjs +++ b/scripts/check-links.mjs @@ -1,17 +1,59 @@ -import { readFile } from 'node:fs/promises'; +import { readdir, readFile, stat } from 'node:fs/promises'; import path from 'node:path'; -import { dist, requireDist, resolveFile } from './lib/dist.mjs'; -import { walk } from './lib/walk.mjs'; +const dist = path.resolve('dist'); const allowedPreservedRoutes = new Set(['/fleeting/', '/reconcile/']); const failures = []; -async function targetExists(pathname) { - if (allowedPreservedRoutes.has(pathname)) return true; - return (await resolveFile(pathname)) !== null; +async function walk(dir) { + const entries = await readdir(dir, { withFileTypes: true }); + const files = []; + + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + files.push(...(await walk(fullPath))); + } else { + files.push(fullPath); + } + } + + return files; } -await requireDist(); +async function exists(file) { + try { + return (await stat(file)).isFile(); + } catch { + return false; + } +} + +async function targetExists(pathname) { + if (allowedPreservedRoutes.has(pathname)) return true; + + const safePath = path + .normalize(decodeURIComponent(pathname)) + .replace(/^\/+/, '') + .replace(/^(\.\.(\/|\\|$))+/, ''); + const candidate = path.join(dist, safePath); + const candidates = [ + candidate, + path.join(candidate, 'index.html'), + path.join(dist, `${safePath}.html`), + ]; + + for (const file of candidates) { + if (await exists(file)) return true; + } + return false; +} + +try { + await stat(dist); +} catch { + throw new Error('dist/ does not exist. Run npm run build first.'); +} const files = await walk(dist); const checkedFiles = files.filter((file) => /\.(html|xml|css|webmanifest)$/.test(file)); diff --git a/scripts/check-no-em-dashes.mjs b/scripts/check-no-em-dashes.mjs index 78ec0d0..edb1606 100644 --- a/scripts/check-no-em-dashes.mjs +++ b/scripts/check-no-em-dashes.mjs @@ -1,6 +1,5 @@ -import { readFile, stat } from 'node:fs/promises'; +import { readdir, readFile, stat } from 'node:fs/promises'; import path from 'node:path'; -import { walk } from './lib/walk.mjs'; const forbidden = String.fromCodePoint(0x2014); const root = process.cwd(); @@ -15,6 +14,7 @@ const textExtensions = new Set([ '.mjs', '.ts', '.txt', + '.vtt', '.webmanifest', '.xml', ]); @@ -37,6 +37,25 @@ async function exists(filePath) { } } +async function walk(entryPath) { + const entryStat = await stat(entryPath); + if (entryStat.isFile()) return [entryPath]; + + const entries = await readdir(entryPath, { withFileTypes: true }); + const files = []; + + for (const entry of entries) { + const fullPath = path.join(entryPath, entry.name); + if (entry.isDirectory()) { + files.push(...(await walk(fullPath))); + } else if (entry.isFile()) { + files.push(fullPath); + } + } + + return files; +} + function lineAndColumn(text, index) { const before = text.slice(0, index); const lines = before.split('\n'); diff --git a/scripts/check-no-github-links.mjs b/scripts/check-no-github-links.mjs deleted file mode 100644 index 587de6c..0000000 --- a/scripts/check-no-github-links.mjs +++ /dev/null @@ -1,99 +0,0 @@ -// cspell:ignore githubusercontent streetsidesoftware forgejo -import { readFile, stat } from 'node:fs/promises'; -import path from 'node:path'; -import { walk } from './lib/walk.mjs'; - -const root = process.cwd(); - -// GitHub is no longer linked from anywhere on the site: project source links, -// the social links, and the repo metadata all point at the self-hosted git -// host instead. Matching the host substrings (rather than the bare word -// "github") keeps the Shiki `github-light`/`github-dark` themes and the -// Forgejo Actions `github.*` context variables from tripping the check. -const bannedHosts = [/github\.com/i, /github\.io/i, /githubusercontent\.com/i]; - -// Upstream tooling URLs that genuinely live on GitHub and have no self-hosted -// equivalent (e.g. the cspell config JSON Schema). A flagged URL is permitted -// only when it exactly equals one of these. -const permitted = new Set([ - 'https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json', -]); - -const textExtensions = new Set([ - '.astro', - '.css', - '.html', - '.js', - '.json', - '.md', - '.mjs', - '.ts', - '.txt', - '.webmanifest', - '.xml', -]); - -const roots = [ - 'src', - 'public', - 'scripts', - 'README.md', - 'package.json', - 'astro.config.mjs', - 'cspell.json', -].map((entry) => path.resolve(root, entry)); - -async function exists(filePath) { - try { - await stat(filePath); - return true; - } catch { - return false; - } -} - -// Grows a match outward to the whole whitespace/quote-delimited URL token so it -// can be compared against the permitted set. -function urlToken(line, index, length) { - const boundary = /[\s"'`<>()[\]{}]/; - let start = index; - while (start > 0 && !boundary.test(line[start - 1])) start -= 1; - let end = index + length; - while (end < line.length && !boundary.test(line[end])) end += 1; - return line.slice(start, end); -} - -const files = []; - -for (const entry of roots) { - if (!(await exists(entry))) continue; - files.push(...(await walk(entry))); -} - -const textFiles = files.filter((file) => textExtensions.has(path.extname(file))); - -const failures = []; - -for (const file of textFiles) { - const lines = (await readFile(file, 'utf8')).split('\n'); - - lines.forEach((line, lineIndex) => { - for (const pattern of bannedHosts) { - for (const match of line.matchAll(new RegExp(pattern, 'gi'))) { - const token = urlToken(line, match.index, match[0].length); - if (permitted.has(token)) continue; - const location = `${path.relative(root, file)}:${lineIndex + 1}:${match.index + 1}`; - failures.push(location); - } - } - }); -} - -if (failures.length > 0) { - console.error( - `GitHub links are not allowed; link the self-hosted git host instead:\n${failures.join('\n')}` - ); - process.exit(1); -} - -console.log('No GitHub links found.'); diff --git a/scripts/check-no-js.mjs b/scripts/check-no-js.mjs index 4fd82ac..051a252 100644 --- a/scripts/check-no-js.mjs +++ b/scripts/check-no-js.mjs @@ -1,10 +1,30 @@ -import { readFile } from 'node:fs/promises'; -import { dist, requireDist } from './lib/dist.mjs'; -import { walk } from './lib/walk.mjs'; +import { readdir, readFile, stat } from 'node:fs/promises'; +import path from 'node:path'; +const dist = path.resolve('dist'); const failures = []; -await requireDist(); +async function walk(dir) { + const entries = await readdir(dir, { withFileTypes: true }); + const files = []; + + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + files.push(...(await walk(fullPath))); + } else { + files.push(fullPath); + } + } + + return files; +} + +try { + await stat(dist); +} catch { + throw new Error('dist/ does not exist. Run npm run build first.'); +} const files = await walk(dist); const ALLOWED_JS_ASSET_PATTERNS = [ diff --git a/scripts/check-overflow.mjs b/scripts/check-overflow.mjs index 88c4531..8b2e75a 100644 --- a/scripts/check-overflow.mjs +++ b/scripts/check-overflow.mjs @@ -1,32 +1,200 @@ +import { createServer } from 'node:http'; +import { mkdir, readdir, readFile, rm, stat } from 'node:fs/promises'; import path from 'node:path'; -import { - CONTEXT_TIMEOUT_MS, - PAGE_TIMEOUT_MS, - cleanupBrowserTmp, - openBrowser, - safeCloseBrowser, - safeCloseContext, - safeClosePage, - setupBrowserTmp, - shouldRetryNavigation, - withTimeout, -} from './lib/browser.mjs'; -import { discoverRoutes, requireDist, startDistServer } from './lib/dist.mjs'; +import { chromium } from 'playwright'; +const dist = path.resolve('dist'); const browserTmp = path.resolve('.astro', 'playwright-overflow-tmp'); +const INDEX_FILE = 'index.html'; const MAX_NAV_RETRIES = 4; // Common device widths: iPhone SE / Galaxy S / iPhone 14 / iPad portrait / // iPad landscape / common laptop / full HD desktop. const VIEWPORT_WIDTHS = [320, 390, 430, 768, 1024, 1440, 1920]; +const CLOSE_TIMEOUT_MS = 3000; +const LAUNCH_TIMEOUT_MS = 10000; +const CONTEXT_TIMEOUT_MS = 8000; +const PAGE_TIMEOUT_MS = 15000; const MEASURE_TIMEOUT_MS = 25000; -await requireDist(); -await setupBrowserTmp(browserTmp); +const MIME = { + '.html': 'text/html; charset=utf-8', + '.css': 'text/css; charset=utf-8', + '.js': 'text/javascript; charset=utf-8', + '.svg': 'image/svg+xml', + '.png': 'image/png', + '.jpg': 'image/jpeg', + '.jpeg': 'image/jpeg', + '.webp': 'image/webp', + '.avif': 'image/avif', + '.ico': 'image/x-icon', + '.woff': 'font/woff', + '.woff2': 'font/woff2', + '.mp4': 'video/mp4', + '.webm': 'video/webm', + '.vtt': 'text/vtt; charset=utf-8', + '.pdf': 'application/pdf', +}; + +function contentType(file) { + const ext = path.extname(file).toLowerCase(); + return MIME[ext] ?? 'application/octet-stream'; +} + +async function walk(dir) { + const entries = await readdir(dir, { withFileTypes: true }); + const files = []; + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + files.push(...(await walk(fullPath))); + } else { + files.push(fullPath); + } + } + return files; +} + +async function discoverRoutes() { + const files = await walk(dist); + const routes = new Set(); + for (const file of files) { + if (!file.endsWith('.html')) continue; + const rel = path.relative(dist, file).replaceAll(path.sep, '/'); + if (rel === '404.html') continue; + if (rel === INDEX_FILE) { + routes.add('/'); + } else if (rel.endsWith(`/${INDEX_FILE}`)) { + routes.add('/' + rel.slice(0, -INDEX_FILE.length)); + } else { + routes.add('/' + rel.replace(/\.html$/, '/')); + } + } + return [...routes].sort(); +} + +async function resolveFile(url) { + const parsed = new URL(url, 'http://localhost'); + const safePath = path + .normalize(decodeURIComponent(parsed.pathname)) + .replace(/^\/+/, '') + .replace(/^(\.\.(\/|\\|$))+/, ''); + const candidate = path.join(dist, safePath); + const candidates = [ + candidate, + path.join(candidate, 'index.html'), + path.join(dist, `${safePath}.html`), + ]; + + for (const file of candidates) { + try { + const fileStat = await stat(file); + if (fileStat.isFile()) return file; + } catch { + // Try the next candidate. + } + } + + return path.join(dist, '404.html'); +} + +try { + await stat(dist); +} catch { + throw new Error('dist/ does not exist. Run npm run build first.'); +} + +// Some CI/dev containers mount /tmp as a very small tmpfs. Chromium uses the +// process temp directory for profiles and internal files; putting it under the +// already-ignored .astro/ directory keeps the overflow check reproducible even +// when the system temp mount is full. +await rm(browserTmp, { recursive: true, force: true }); +await mkdir(browserTmp, { recursive: true }); +process.env.TMPDIR = browserTmp; +process.env.TMP = browserTmp; +process.env.TEMP = browserTmp; const routes = await discoverRoutes(); -const { server, port } = await startDistServer(); + +const server = createServer(async (req, res) => { + try { + const file = await resolveFile(req.url ?? '/'); + const body = await readFile(file); + res.writeHead(200, { 'content-type': contentType(file) }); + res.end(body); + } catch (error) { + res.writeHead(500, { 'content-type': 'text/plain; charset=utf-8' }); + res.end(String(error)); + } +}); + +await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve)); +const { port } = server.address(); const failures = []; +function launchBrowser() { + return chromium.launch({ + headless: true, + env: { + ...process.env, + TMPDIR: browserTmp, + TMP: browserTmp, + TEMP: browserTmp, + }, + args: ['--disable-dev-shm-usage', '--disable-gpu', '--no-sandbox'], + }); +} + +async function withTimeout(promise, timeoutMs, label) { + let timeout; + try { + return await Promise.race([ + promise, + new Promise((_, reject) => { + timeout = setTimeout(() => reject(new Error(label)), timeoutMs); + }), + ]); + } finally { + clearTimeout(timeout); + } +} + +async function safeClosePage(page) { + await withTimeout( + page.close(), + CLOSE_TIMEOUT_MS, + 'Timed out while closing Playwright page' + ).catch(() => {}); +} + +async function safeCloseContext(context) { + await withTimeout( + context.close(), + CLOSE_TIMEOUT_MS, + 'Timed out while closing Playwright context' + ).catch(() => {}); +} + +async function safeCloseBrowser(browser) { + const childProcess = browser.process?.(); + try { + await withTimeout( + browser.close(), + CLOSE_TIMEOUT_MS, + 'Timed out while closing Chromium' + ); + } catch { + childProcess?.kill('SIGKILL'); + } +} + +async function openBrowser() { + return withTimeout( + launchBrowser(), + LAUNCH_TIMEOUT_MS, + 'Timed out while launching Chromium' + ); +} + async function newMeasurementContext(browser, width) { const context = await browser.newContext({ viewport: { width, height: 900 }, @@ -59,6 +227,13 @@ async function measureViewport(page) { })); } +function shouldRetryNavigation(error) { + const message = error instanceof Error ? error.message : String(error); + return /ERR_INSUFFICIENT_RESOURCES|Execution context was destroyed|Target.*closed|has been closed|Timed out while|navigation/i.test( + message + ); +} + async function measureRoute(context, route) { let page; try { @@ -88,7 +263,7 @@ try { let browser; let context; try { - browser = await openBrowser(browserTmp); + browser = await openBrowser(); context = await openMeasurementContext(browser, width); for (const route of routes) { let result; @@ -103,7 +278,7 @@ try { } await safeCloseContext(context); await safeCloseBrowser(browser); - browser = await openBrowser(browserTmp); + browser = await openBrowser(); context = await openMeasurementContext(browser, width); } } @@ -121,7 +296,7 @@ try { } } finally { server.close(); - await cleanupBrowserTmp(browserTmp); + await rm(browserTmp, { recursive: true, force: true }).catch(() => {}); } if (failures.length > 0) { diff --git a/scripts/check-preview-cropping.mjs b/scripts/check-preview-cropping.mjs index b1bc7bd..7804e41 100644 --- a/scripts/check-preview-cropping.mjs +++ b/scripts/check-preview-cropping.mjs @@ -1,31 +1,115 @@ -import { readFile } from 'node:fs/promises'; +import { createServer } from 'node:http'; +import { mkdir, readdir, readFile, rm, stat } from 'node:fs/promises'; import path from 'node:path'; -import { - CONTEXT_TIMEOUT_MS, - PAGE_TIMEOUT_MS, - cleanupBrowserTmp, - openBrowser, - safeCloseBrowser, - safeCloseContext, - safeClosePage, - setupBrowserTmp, - shouldRetryNavigation, - withTimeout, -} from './lib/browser.mjs'; -import { discoverRoutes, requireDist, startDistServer } from './lib/dist.mjs'; +import { chromium } from 'playwright'; +const dist = path.resolve('dist'); const previewCss = path.resolve('src/styles/global.css'); const browserTmp = path.resolve('.astro', 'playwright-preview-cropping-tmp'); +const INDEX_FILE = 'index.html'; const PREVIEW_SELECTOR = '[data-uncropped-preview]'; // Common device widths: iPhone SE / Galaxy S / iPhone 14 / iPad portrait / // iPad landscape / common laptop / full HD desktop. const VIEWPORT_WIDTHS = [320, 390, 430, 768, 1024, 1440, 1920]; const MAX_NAV_RETRIES = 4; +const CLOSE_TIMEOUT_MS = 3000; +const LAUNCH_TIMEOUT_MS = 10000; +const CONTEXT_TIMEOUT_MS = 8000; +const PAGE_TIMEOUT_MS = 15000; const MEASURE_TIMEOUT_MS = 30000; const CLIP_TOLERANCE_PX = 0.75; const RATIO_TOLERANCE = 0.01; -await requireDist(); +const MIME = { + '.html': 'text/html; charset=utf-8', + '.css': 'text/css; charset=utf-8', + '.js': 'text/javascript; charset=utf-8', + '.svg': 'image/svg+xml', + '.png': 'image/png', + '.jpg': 'image/jpeg', + '.jpeg': 'image/jpeg', + '.webp': 'image/webp', + '.avif': 'image/avif', + '.ico': 'image/x-icon', + '.woff': 'font/woff', + '.woff2': 'font/woff2', + '.mp4': 'video/mp4', + '.webm': 'video/webm', + '.vtt': 'text/vtt; charset=utf-8', + '.pdf': 'application/pdf', +}; + +function contentType(file) { + const ext = path.extname(file).toLowerCase(); + return MIME[ext] ?? 'application/octet-stream'; +} + +async function walk(dir) { + const entries = await readdir(dir, { withFileTypes: true }); + const files = []; + + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + files.push(...(await walk(fullPath))); + } else { + files.push(fullPath); + } + } + + return files; +} + +async function discoverRoutes() { + const files = await walk(dist); + const routes = new Set(); + + for (const file of files) { + if (!file.endsWith('.html')) continue; + const rel = path.relative(dist, file).replaceAll(path.sep, '/'); + if (rel === '404.html') continue; + if (rel === INDEX_FILE) { + routes.add('/'); + } else if (rel.endsWith(`/${INDEX_FILE}`)) { + routes.add('/' + rel.slice(0, -INDEX_FILE.length)); + } else { + routes.add('/' + rel.replace(/\.html$/, '/')); + } + } + + return [...routes].sort(); +} + +async function resolveFile(url) { + const parsed = new URL(url, 'http://localhost'); + const safePath = path + .normalize(decodeURIComponent(parsed.pathname)) + .replace(/^\/+/, '') + .replace(/^(\.\.(\/|\\|$))+/, ''); + const candidate = path.join(dist, safePath); + const candidates = [ + candidate, + path.join(candidate, 'index.html'), + path.join(dist, `${safePath}.html`), + ]; + + for (const file of candidates) { + try { + const fileStat = await stat(file); + if (fileStat.isFile()) return file; + } catch { + // Try the next candidate. + } + } + + return path.join(dist, '404.html'); +} + +try { + await stat(dist); +} catch { + throw new Error('dist/ does not exist. Run npm run build first.'); +} function lineAndColumn(text, index) { const before = text.slice(0, index); @@ -113,11 +197,95 @@ async function checkPreviewCroppingStyles() { return styleFailures; } -await setupBrowserTmp(browserTmp); +// Keep Chromium temp files inside the repo so the check is reproducible in CI +// containers with very small /tmp mounts. +await rm(browserTmp, { recursive: true, force: true }); +await mkdir(browserTmp, { recursive: true }); +process.env.TMPDIR = browserTmp; +process.env.TMP = browserTmp; +process.env.TEMP = browserTmp; const routes = await discoverRoutes(); const failures = await checkPreviewCroppingStyles(); -const { server, port } = await startDistServer(); + +const server = createServer(async (req, res) => { + try { + const file = await resolveFile(req.url ?? '/'); + const body = await readFile(file); + res.writeHead(200, { 'content-type': contentType(file) }); + res.end(body); + } catch (error) { + res.writeHead(500, { 'content-type': 'text/plain; charset=utf-8' }); + res.end(String(error)); + } +}); + +await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve)); +const { port } = server.address(); + +function launchBrowser() { + return chromium.launch({ + headless: true, + env: { + ...process.env, + TMPDIR: browserTmp, + TMP: browserTmp, + TEMP: browserTmp, + }, + args: ['--disable-dev-shm-usage', '--disable-gpu', '--no-sandbox'], + }); +} + +async function withTimeout(promise, timeoutMs, label) { + let timeout; + try { + return await Promise.race([ + promise, + new Promise((_, reject) => { + timeout = setTimeout(() => reject(new Error(label)), timeoutMs); + }), + ]); + } finally { + clearTimeout(timeout); + } +} + +async function safeClosePage(page) { + await withTimeout( + page.close(), + CLOSE_TIMEOUT_MS, + 'Timed out while closing Playwright page' + ).catch(() => {}); +} + +async function safeCloseContext(context) { + await withTimeout( + context.close(), + CLOSE_TIMEOUT_MS, + 'Timed out while closing Playwright context' + ).catch(() => {}); +} + +async function safeCloseBrowser(browser) { + const childProcess = browser.process?.(); + try { + await withTimeout( + browser.close(), + CLOSE_TIMEOUT_MS, + 'Timed out while closing Chromium' + ); + } catch { + childProcess?.kill('SIGKILL'); + } +} + +async function openBrowser() { + return withTimeout( + launchBrowser(), + LAUNCH_TIMEOUT_MS, + 'Timed out while launching Chromium' + ); +} async function newMeasurementContext(browser, width) { const context = await browser.newContext({ @@ -283,6 +451,13 @@ async function inspectPreviews(page, route, width, phase, index = null) { ); } +function shouldRetryNavigation(error) { + const message = error instanceof Error ? error.message : String(error); + return /ERR_INSUFFICIENT_RESOURCES|Execution context was destroyed|Target.*closed|has been closed|Timed out while|navigation/i.test( + message + ); +} + async function measureRoute(context, route, width) { let page; @@ -317,7 +492,7 @@ try { let context; try { - browser = await openBrowser(browserTmp); + browser = await openBrowser(); context = await openMeasurementContext(browser, width); for (const route of routes) { @@ -334,7 +509,7 @@ try { await safeCloseContext(context); await safeCloseBrowser(browser); - browser = await openBrowser(browserTmp); + browser = await openBrowser(); context = await openMeasurementContext(browser, width); } } @@ -348,7 +523,7 @@ try { } } finally { server.close(); - await cleanupBrowserTmp(browserTmp); + await rm(browserTmp, { recursive: true, force: true }).catch(() => {}); } if (failures.length > 0) { diff --git a/scripts/export-astro-audit.mjs b/scripts/export-astro-audit.mjs index 34e9e56..62c4113 100644 --- a/scripts/export-astro-audit.mjs +++ b/scripts/export-astro-audit.mjs @@ -1,16 +1,11 @@ import { spawn } from 'node:child_process'; import { once } from 'node:events'; -import { mkdir, writeFile } from 'node:fs/promises'; +import { mkdir, readdir, rm, stat, writeFile } from 'node:fs/promises'; import { createServer as createNetServer } from 'node:net'; import path from 'node:path'; -import { - cleanupBrowserTmp, - openBrowser, - safeCloseBrowser, - setupBrowserTmp, -} from './lib/browser.mjs'; -import { discoverRoutes, requireDist } from './lib/dist.mjs'; +import { chromium } from 'playwright'; +const dist = path.resolve('dist'); const browserTmp = path.resolve('.astro', 'playwright-astro-audit-tmp'); const outputJson = path.resolve( process.env.ASTRO_AUDIT_OUTPUT_JSON ?? '.astro/astro-audit-results.json' @@ -24,6 +19,7 @@ const astroBin = path.resolve( process.platform === 'win32' ? 'astro.cmd' : 'astro' ); const HOST = '127.0.0.1'; +const INDEX_FILE = 'index.html'; const SERVER_START_TIMEOUT_MS = 60000; const CLOSE_TIMEOUT_MS = 3000; const NAV_TIMEOUT_MS = 20000; @@ -55,7 +51,21 @@ function parseViewports(raw = process.env.ASTRO_AUDIT_VIEWPORTS ?? DEFAULT_VIEWP }); } -async function discoverAuditRoutes() { +async function walk(dir) { + const entries = await readdir(dir, { withFileTypes: true }); + const files = []; + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + files.push(...(await walk(fullPath))); + } else { + files.push(fullPath); + } + } + return files; +} + +async function discoverRoutes() { if (process.env.ASTRO_AUDIT_ROUTES) { return process.env.ASTRO_AUDIT_ROUTES.split(',') .map((route) => route.trim()) @@ -63,8 +73,29 @@ async function discoverAuditRoutes() { .map((route) => (route.startsWith('/') ? route : `/${route}`)); } - await requireDist(); - return discoverRoutes(); + try { + await stat(dist); + } catch { + throw new Error('dist/ does not exist. Run npm run build first.'); + } + + const files = await walk(dist); + const routes = new Set(); + for (const file of files) { + if (!file.endsWith('.html')) continue; + const rel = path.relative(dist, file).replaceAll(path.sep, '/'); + if (rel === '404.html') continue; + + if (rel === INDEX_FILE) { + routes.add('/'); + } else if (rel.endsWith(`/${INDEX_FILE}`)) { + routes.add('/' + rel.slice(0, -INDEX_FILE.length)); + } else { + routes.add('/' + rel.replace(/\.html$/, '/')); + } + } + + return [...routes].sort(); } async function getFreePort() { @@ -138,6 +169,20 @@ async function stopProcess(child) { } } +async function safeCloseBrowser(browser) { + const childProcess = browser?.process?.(); + try { + await Promise.race([ + browser.close(), + sleep(CLOSE_TIMEOUT_MS).then(() => { + throw new Error('Timed out while closing Chromium'); + }), + ]); + } catch { + childProcess?.kill('SIGKILL'); + } +} + function viewportLabel(viewport) { return `${viewport.width}x${viewport.height}`; } @@ -340,15 +385,19 @@ function renderMarkdown(report) { } const viewports = parseViewports(); -const routes = await discoverAuditRoutes(); +const routes = await discoverRoutes(); if (routes.length === 0) { throw new Error('No HTML routes found to audit.'); } -await setupBrowserTmp(browserTmp); +await rm(browserTmp, { recursive: true, force: true }); +await mkdir(browserTmp, { recursive: true }); await mkdir(path.dirname(outputJson), { recursive: true }); await mkdir(path.dirname(outputMarkdown), { recursive: true }); +process.env.TMPDIR = browserTmp; +process.env.TMP = browserTmp; +process.env.TEMP = browserTmp; const port = await getFreePort(); const baseUrl = `http://${HOST}:${port}/`; @@ -360,7 +409,16 @@ try { devServer = startAstroDev(port); await waitForDevServer(baseUrl, devServer); - browser = await openBrowser(browserTmp); + browser = await chromium.launch({ + headless: true, + env: { + ...process.env, + TMPDIR: browserTmp, + TMP: browserTmp, + TEMP: browserTmp, + }, + args: ['--disable-dev-shm-usage', '--disable-gpu', '--no-sandbox'], + }); for (const viewport of viewports) { const context = await browser.newContext({ @@ -422,5 +480,5 @@ try { } finally { if (browser) await safeCloseBrowser(browser); if (devServer) await stopProcess(devServer); - await cleanupBrowserTmp(browserTmp); + await rm(browserTmp, { recursive: true, force: true }).catch(() => {}); } diff --git a/scripts/lib/browser.mjs b/scripts/lib/browser.mjs deleted file mode 100644 index 71355c8..0000000 --- a/scripts/lib/browser.mjs +++ /dev/null @@ -1,89 +0,0 @@ -import { mkdir, rm } from 'node:fs/promises'; -import { chromium } from 'playwright'; - -export const CLOSE_TIMEOUT_MS = 3000; -export const LAUNCH_TIMEOUT_MS = 10000; -export const CONTEXT_TIMEOUT_MS = 8000; -export const PAGE_TIMEOUT_MS = 15000; - -// Chromium puts profiles and internal files in the process temp directory. -// Some CI/dev containers mount /tmp as a very small tmpfs, so the checks point -// it at an already-ignored directory under .astro/ instead. -export async function setupBrowserTmp(browserTmp) { - await rm(browserTmp, { recursive: true, force: true }); - await mkdir(browserTmp, { recursive: true }); - process.env.TMPDIR = browserTmp; - process.env.TMP = browserTmp; - process.env.TEMP = browserTmp; -} - -export async function cleanupBrowserTmp(browserTmp) { - await rm(browserTmp, { recursive: true, force: true }).catch(() => {}); -} - -export async function withTimeout(promise, timeoutMs, label) { - let timeout; - try { - return await Promise.race([ - promise, - new Promise((_, reject) => { - timeout = setTimeout(() => reject(new Error(label)), timeoutMs); - }), - ]); - } finally { - clearTimeout(timeout); - } -} - -export async function safeClosePage(page) { - await withTimeout( - page.close(), - CLOSE_TIMEOUT_MS, - 'Timed out while closing Playwright page' - ).catch(() => {}); -} - -export async function safeCloseContext(context) { - await withTimeout( - context.close(), - CLOSE_TIMEOUT_MS, - 'Timed out while closing Playwright context' - ).catch(() => {}); -} - -export async function safeCloseBrowser(browser) { - const childProcess = browser.process?.(); - try { - await withTimeout( - browser.close(), - CLOSE_TIMEOUT_MS, - 'Timed out while closing Chromium' - ); - } catch { - childProcess?.kill('SIGKILL'); - } -} - -export function openBrowser(browserTmp) { - return withTimeout( - chromium.launch({ - headless: true, - env: { - ...process.env, - TMPDIR: browserTmp, - TMP: browserTmp, - TEMP: browserTmp, - }, - args: ['--disable-dev-shm-usage', '--disable-gpu', '--no-sandbox'], - }), - LAUNCH_TIMEOUT_MS, - 'Timed out while launching Chromium' - ); -} - -export function shouldRetryNavigation(error) { - const message = error instanceof Error ? error.message : String(error); - return /ERR_INSUFFICIENT_RESOURCES|Execution context was destroyed|Target.*closed|has been closed|Timed out while|navigation/i.test( - message - ); -} diff --git a/scripts/lib/dist.mjs b/scripts/lib/dist.mjs deleted file mode 100644 index b4584c2..0000000 --- a/scripts/lib/dist.mjs +++ /dev/null @@ -1,107 +0,0 @@ -import { createServer } from 'node:http'; -import { readFile, stat } from 'node:fs/promises'; -import path from 'node:path'; -import { walk } from './walk.mjs'; - -export const dist = path.resolve('dist'); - -const INDEX_FILE = 'index.html'; - -export async function requireDist() { - try { - await stat(dist); - } catch { - throw new Error('dist/ does not exist. Run npm run build first.'); - } -} - -// Derives the site's route list from the HTML files in dist/. -export async function discoverRoutes() { - const files = await walk(dist); - const routes = new Set(); - - for (const file of files) { - if (!file.endsWith('.html')) continue; - const rel = path.relative(dist, file).replaceAll(path.sep, '/'); - if (rel === '404.html') continue; - if (rel === INDEX_FILE) { - routes.add('/'); - } else if (rel.endsWith(`/${INDEX_FILE}`)) { - routes.add('/' + rel.slice(0, -INDEX_FILE.length)); - } else { - routes.add('/' + rel.replace(/\.html$/, '/')); - } - } - - return [...routes].sort(); -} - -// Maps a request URL (or pathname) to a file in dist/, mirroring static-host -// semantics: the path itself, its directory index.html, or the extensionless -// .html variant. Returns null when nothing matches. -export async function resolveFile(url) { - const parsed = new URL(url, 'http://localhost'); - const safePath = path - .normalize(decodeURIComponent(parsed.pathname)) - .replace(/^\/+/, '') - .replace(/^(\.\.(\/|\\|$))+/, ''); - const candidate = path.join(dist, safePath); - const candidates = [ - candidate, - path.join(candidate, 'index.html'), - path.join(dist, `${safePath}.html`), - ]; - - for (const file of candidates) { - try { - const fileStat = await stat(file); - if (fileStat.isFile()) return file; - } catch { - // Try the next candidate. - } - } - - return null; -} - -const MIME = { - '.html': 'text/html; charset=utf-8', - '.css': 'text/css; charset=utf-8', - '.js': 'text/javascript; charset=utf-8', - '.svg': 'image/svg+xml', - '.png': 'image/png', - '.jpg': 'image/jpeg', - '.jpeg': 'image/jpeg', - '.webp': 'image/webp', - '.avif': 'image/avif', - '.ico': 'image/x-icon', - '.woff': 'font/woff', - '.woff2': 'font/woff2', - '.mp4': 'video/mp4', - '.webm': 'video/webm', - '.pdf': 'application/pdf', -}; - -export function contentType(file) { - const ext = path.extname(file).toLowerCase(); - return MIME[ext] ?? 'application/octet-stream'; -} - -// Serves dist/ on an ephemeral localhost port, falling back to 404.html. -// Returns the server (callers own closing it) and the assigned port. -export async function startDistServer() { - const server = createServer(async (req, res) => { - try { - const file = (await resolveFile(req.url ?? '/')) ?? path.join(dist, '404.html'); - const body = await readFile(file); - res.writeHead(200, { 'content-type': contentType(file) }); - res.end(body); - } catch (error) { - res.writeHead(500, { 'content-type': 'text/plain; charset=utf-8' }); - res.end(String(error)); - } - }); - - await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve)); - return { server, port: server.address().port }; -} diff --git a/scripts/lib/walk.mjs b/scripts/lib/walk.mjs deleted file mode 100644 index 8424373..0000000 --- a/scripts/lib/walk.mjs +++ /dev/null @@ -1,23 +0,0 @@ -import { readdir, stat } from 'node:fs/promises'; -import path from 'node:path'; - -// Recursively lists every file under entryPath. A path that is itself a file -// resolves to a single-element list, so callers can mix files and directories. -export async function walk(entryPath) { - const entryStat = await stat(entryPath); - if (entryStat.isFile()) return [entryPath]; - - const entries = await readdir(entryPath, { withFileTypes: true }); - const files = []; - - for (const entry of entries) { - const fullPath = path.join(entryPath, entry.name); - if (entry.isDirectory()) { - files.push(...(await walk(fullPath))); - } else { - files.push(fullPath); - } - } - - return files; -} diff --git a/src/components/ArticleList.astro b/src/components/ArticleList.astro index 309ccb0..d2d3f9e 100644 --- a/src/components/ArticleList.astro +++ b/src/components/ArticleList.astro @@ -5,7 +5,7 @@ import TagList from './TagList.astro'; import { ARTICLE_THUMBNAIL, articlePath, formatDate, formatDateShort } from '../lib/site'; interface Props { - posts: CollectionEntry<'work'>[]; + posts: CollectionEntry<'posts'>[]; showYear?: boolean; tagLimit?: number; timeline?: boolean; @@ -39,7 +39,7 @@ const {

{post.data.description}

- +