diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index bbc294c..4c63b45 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -23,7 +23,7 @@ - [ ] Linting and formatting pass (`pnpm lint && pnpm format`) - [ ] PR title follows semantic commit format (`feat:`, `fix:`, etc.) - [ ] Changes are documented (README, JSDoc, or comments if needed) -- [ ] Ready for review — not a draft +- [ ] Ready for review - not a draft --- diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml.disable similarity index 92% rename from .github/workflows/release.yml rename to .github/workflows/release.yml.disable index 92e9b47..2e17038 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml.disable @@ -60,8 +60,8 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} run: | echo "ℹ️ Packages flagged for publish:" - echo "• core → ${{ steps.release.outputs['packages/core--release_version'] }}" - echo "• cli → ${{ steps.release.outputs['packages/cli--release_version'] }}" + echo "• core ➡️ ${{ steps.release.outputs['packages/core--release_version'] }}" + echo "• cli ➡️ ${{ steps.release.outputs['packages/cli--release_version'] }}" if [[ '${{ steps.release.outputs['packages/core--release_created'] }}' == 'true' ]]; then echo "📦 Publishing @react-zero-ui/core…" diff --git a/.prettierrc.json b/.prettierrc.json index aa184a9..295e1be 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -12,4 +12,4 @@ "bracketSameLine": true, "embeddedLanguageFormatting": "auto", "singleAttributePerLine": true -} \ No newline at end of file +} diff --git a/.release-please-config.json b/.release-please-config.json deleted file mode 100644 index 288e79b..0000000 --- a/.release-please-config.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "release-type": "node", - "monorepo-tags": true, - "include-component-in-tag": true, - "packages": { - "packages/core": { "package-name": "@react-zero-ui/core", "release-type": "node" }, - "packages/cli": { "package-name": "create-zero-ui", "release-type": "node" } - } -} diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index a545470..0000000 --- a/AGENTS.md +++ /dev/null @@ -1,87 +0,0 @@ - - -# Guidelines for AI Agents in this Repo - -This repository contains **React Zero-UI**, a library for global UI state without React re-renders. -Use these tips when working with the codebase or generating examples. - -## How React Zero-UI works - -1. `useUI()` writes to `document.body.dataset` using keys you specify. - -```tsx -const [staleValue, setValue] = useUI<'open' | 'closed'>('sidebar', 'closed'); -``` - -- `key` → becomes `data-{key}` on `` (e.g., `sidebar` → `data-sidebar="closed"`). -- `defaultValue` → used for SSR to avoid FOUC. Added to the body as a data-attribute. at build time. -- The first value is **always stale** — do NOT rely on it for reactive updates. - -2. Consumption is done strictly with tailwind variant classNames: - -```html -
-``` - -3. Build-time tooling scans all `useUI()` keys and values, then generates matching Tailwind variants. - -4. At runtime, calling the setter updates the `data-*` attribute on `` immediately. No VDOM. No re-renders. - ---- - -## Best Practices for AI Agents - -- ✅ Use `useUI()` **only for UI state**: themes, layout flags, open/closed toggles, etc. -- ✅ Prefer **kebab-case keys**: e.g. `sidebar-open`, `theme-dark`. -- ✅ Always provide a `defaultValue`: prevents FOUC and enables SSR. -- ✅ Do **NOT** use the first value from `useUI()` for logic — it DOES NOT UPDATE. -- ✅ You can call setters **from anywhere** in the app — no prop drilling or context needed. -- ✅ Tailwind classes must use `key-value:` pattern: - - `theme-dark:bg-black` - - `accent-blue:text-blue-500` - - `sidebar-open:translate-x-0` - ---- - -## Example: Toggle Theme - -```tsx -// Set state -const [, setTheme] = useUI<'light' | 'dark'>('theme', 'light'); -; -``` - -```html - -
-``` - -## Example: Scoping Styles - -```tsx -const [, setTheme] = useUI<'light' | 'dark'>('theme', 'light'); -// Simply pass a ref to the element -
; -``` - -Now the data-\* will flip on that element, and the styles will be scoped to that element, or its children. - ---- - -## What NOT to do - -- ❌ Do not pass anything to the StateKey or InitialValue that is not a string or does not resolve to a string. -- ❌ Don't use `useUI()` for business logic or data fetching -- ❌ Don't rely on the first tuple value for reactivity -- ❌ Don't use camelCase keys (will break variant generation) - ---- - -## Summary - -**React Zero-UI is a ZERO re-render UI state engine with global state baked in.** It replaces traditional VDOM cycles with `data-*` attribute flips and compile-time CSS. No React context. No prop drilling. No runtime cost. - -Think of it as writing atomic Tailwind variants for every UI state — but flipping them dynamically at runtime without re-rendering anything. diff --git a/README.md b/README.md index ce5194c..fcc1eec 100644 --- a/README.md +++ b/README.md @@ -1,186 +1,217 @@ -# React Zero‑UI (Beta) + + +![Tagline](https://img.shields.io/badge/The_ZERO_re--render_UI_state_library-%235500AD?style=flat&label=) -**Instant UI state updates. ZERO React re‑renders. Near ZERO runtime. <500 bytes** + -Pre‑render your UI once, flip a `data-*` attribute to update — that's it. +

+ Frame 342 +

-npm version npm version License: MIT ![CI](https://github.com/react-zero-ui/core/actions/workflows/ci.yml/badge.svg?branch=main) +
+ The fastest possible UI updates in React. Period. ---- +Zero runtime, zero React re-renders, and the simplest developer experience ever. Say goodbye to context and prop-drilling. + +bundle size npm version License: MIT ![CI](https://github.com/react-zero-ui/core/actions/workflows/ci.yml/badge.svg?branch=main) -## 📚 Quick Links +[📖 See the proof](/docs/demo.md) [🚀 Quick Start](#-quick-start) [📚 API Reference](#-api-reference) [🤝 Contributing](#-contributing) -- [⚡️ Quick Start](#️-quick-start) -- [🏄 Usage](#-usage) -- [🧬 How it works](#-how-it-works) -- [✅ Features](#-features) -- [🏗 Best Practices](#-best-practices) +
--- -## 🚀 Live Demo +## 🔥 Core Concept: _"Pre-Rendering"_ -| Example | Link | What it shows | Link to Code | -| --- | --- | --- | --- | -| Interactive menu with render tracker | Main Demo↗ | Compare Zero‑UI vs. React side‑by‑side while toggling a menu. | Github | -| React benchmark (10 000 nested nodes) | React 10k↗ | How long the traditional React render path takes. | Github | -| Zero‑UI benchmark (10 000 nested nodes) | Zero‑UI 10k↗ | Identical DOM, but powered by Zero‑UI's `data-*` switch. | Github | +Why re-render UI if all states are known at build time? React Zero-UI **pre-renders** UI states once ( at no runtime cost ), and flips `data-*` attribute to update - that's it. ---- +**Example:** + +```tsx +const [, setTheme] = useUI('theme', 'dark'); + +// Flip theme to "light" +setTheme('light'); // data-theme="light" on body +``` -## 🧐 Why Zero‑UI? +**Tailwind usage:** Anywhere in your app -Every `setState` in React triggers the full VDOM → Diff → Reconciliation → Paint pipeline. For _pure UI state_ (themes, menus, toggles) that work is wasted. +```html +
Fast & Reactive
+``` -**Zero‑UI introduces "_PRE‑rendering_":** +--- -1. Tailwind variants for every state are **generated at build‑time**. -2. The app **pre‑renders once**. -3. Runtime state changes only **flip a `data-*` attribute on ``**. +## 🚀 How it Works (Build-Time Magic) -Result → **5-10× faster visual updates** with **ZERO additional bundle cost**. +React Zero-UI uses a hyper-optimized AST resolver in development that scans your codebase for: -### 📊 Micro‑benchmarks (Apple M1) +- `useUI` and `useScopedUI` hook usage. +- Any variables resolving to strings (e.g., `'theme'`, `'modal-open'`). +- Tailwind variant classes (e.g. `theme-dark:bg-black`). -| Nodes updated | React state | Zero‑UI | Speed‑up | -| ------------- | ----------- | ------- | -------- | -| 10,000 | \~50 ms | \~5 ms | **10×** | -| 25,000 | \~180 ms | \~15 ms | **12×** | -| 50,000 | \~300 ms | \~20 ms | **15×** | +**This generates:** -Re‑run these numbers yourself via the links above. +- Optimal CSS with global or scoped variant selectors. +- Initial data-attributes injected onto the body (zero FOUC). +- UI state with ease, no prop-drilling. +- **Zero runtime overhead in production**. --- -## ⚡️ Quick Start +## 🚀 Quick Start -> **Prerequisite:** Tailwind CSS v4 must already be initialized in your project. +Zero-UI CLI + +**Pre-requisites:** +* Vite or Next.js (App Router) +* Tailwind V4 Configured. See [Tailwind V4 Installation](https://tailwindcss.com/docs/installation/using-vite) ```bash -# Inside an existing *Next.js (App Router)* or *Vite* repo npx create-zero-ui ``` -That's it — the CLI patch‑installs the required Babel & PostCSS plugins and updates `configs` for you. +> For manual configuration, see [Next JS Installation](/docs/installation-next.md) | [Vite Installation](/docs/installation-vite.md) -### Manual Install +**That's it.** Start your app and see the magic. -```bash -npm install @react-zero-ui/core -``` +--- -Then follow **Setup →** for your bundler. +## 📚 API Reference ---- +**The Basics:** -## 🔧 Setup +```tsx +const [, ] = useUI(, ); +``` -### Vite +- `stateKey` ➡️ becomes `data-{stateKey}` on ``. +- `defaultValue` ➡️ SSR, prevents FOUC. +- `staleValue` ➡️ For scoped UI, set the data-\* to the `staleValue` to prevent FOUC. +- **Note:** the returned `staleValue` does **not** update (`useUI` is write‑only). -```js -// vite.config.* -import { zeroUIPlugin } from '@react-zero-ui/core/vite'; +### 🔨 `useUI` Hook (Global UI State) -export default { - // ❗️Remove the default `tailwindcss()` plugin — Zero‑UI extends it internally - plugins: [zeroUIPlugin()], -}; +Simple hook mirroring React's `useState`: + +```tsx +import { useUI } from '@react-zero-ui/core'; + +const [theme, setTheme] = useUI('theme', 'dark'); ``` -### Next.js (App Router) +**Features:** -1. **Spread `bodyAttributes` on ``** in your root layout. +- Flips global `data-theme` attribute on ``. +- Zero React re-renders. +- Global UI state available anywhere in your app through tailwind variants. - ```tsx - // app/layout.tsx - import { bodyAttributes } from '@zero-ui/attributes'; - // or: import { bodyAttributes } from '../.zero-ui/attributes'; +--- - export default function RootLayout({ children }) { - return ( - - {children} - - ); - } - ``` +### 🎯 `useScopedUI` Hook (Scoped UI State) -2. **Add the PostCSS plugin (must come _before_ Tailwind).** +Control UI states at the element-level: - ```js - // postcss.config.js - module.exports = { plugins: { '@react-zero-ui/core/postcss': {}, tailwindcss: {} } }; - ``` +```diff ++ import { useScopedUI } from '@react-zero-ui/core'; ---- +const [theme, setTheme] = useScopedUI("theme", "dark"); -## 🏄 Usage +// ❗️Flips data-* on the specific ref element ++
+ Scoped UI Here +
+``` + +**Features:** -![react zero ui usage explained](docs/assets/useui-explained.webp) +- Data-\* flips on specific target element. +- Generates scoped CSS selectors only applying within the target element. +- No FOUC, no re-renders. --- -## 🛠 API +### 🌈 CSS Variables Support -### `useUI(key, defaultValue)` +Sometimes CSS variables are more efficient. React Zero-UI makes it trivial by passing the `CssVar` option: -```ts -const [staleValue, setValue] = useUI<'open' | 'closed'>('sidebar', 'closed'); -``` +```diff ++ Pass `CssVar` to either hook to use CSS variables -- `key` → becomes `data-{key}` on ``. -- `defaultValue` → SSR, prevents FOUC. -- **Note:** the returned `staleValue` does **not** update (`useUI` is write‑only). +useUI(, , CssVar); -### Tailwind variants +``` +automatically adds `--` to the Css Variable -```jsx -
+**Global CSS Variable:** + +```diff ++ import { CssVar } from '@react-zero-ui/core'; ``` -Any `data-{key}="{value}"` pair becomes a variant: `{key}-{value}:`. +```tsx +const [blur, setBlur] = useUI('blur', '0px', CssVar); +setBlur('5px'); // body { --blur: 5px } +``` ---- +**Scoped CSS Variable:** -## 🧬 How it works +```tsx +const [blur, setBlur] = useScopedUI('blur', '0px', CssVar); -1. **`useUI`** → writes to `data-*` attributes on ``. -2. **Babel plugin** → scans code, finds every `key/value`, injects them into **PostCSS**. -3. **PostCSS plugin** → generates static Tailwind classes **at build‑time**. -4. **Runtime** → changing state only touches the attribute — no VDOM, no reconciliation, ZERO re‑renders. +
+ Scoped blur effect. +
; +``` --- -## ✅ Features +## 🧪 Experimental Features -- **Zero React re‑renders** for UI‑only state. -- **Global setters** — call from any component or util. -- **Tiny**: < 391 Byte gzipped runtime. -- **SSR‑friendly** (Next.js & Vite SSR). -- **Use from anywhere** — Consume with tailwind variants from anywhere. +### SSR-safe `zeroOnClick` + +Enable client-side interactivity **without leaving server components**. +Just 300 bytes of runtime overhead. + +See [experimental](./docs/assets/experimental.md) for more details. --- -## 🏗 Best Practices +## 📦 Summary of Benefits + +- **🚀 Zero React re-renders:** Pure CSS-driven UI state. +- **⚡️ Pre-rendered UI:** All states injected at build-time and only loaded when needed. +- **📦 Tiny footprint:** <350 bytes, zero runtime overhead for CSS states. +- **💫 Amazing DX:** Simple hooks, auto-generated Tailwind variants. +- **⚙️ Highly optimized AST resolver:** Fast, cached build process. -1. **Global UI state only** → themes, layout toggles, feature flags. -2. **Business logic stays in React** → fetching, data mutation, etc. -3. **Kebab‑case keys** → e.g. `sidebar-open`. -4. **Provide defaults** to avoid Flash‑Of‑Unstyled‑Content. -5. **Avoid** for per-component logic or data. +React Zero-UI delivers the fastest, simplest, most performant way to handle global and scoped UI state in modern React applications. Say goodbye to re-renders and prop-drilling. + +--- --- ## 🤝 Contributing -PRs & issues welcome! Please read the [Contributing Guide](CONTRIBUTING.md). +We welcome contributions from the community! Whether it's bug fixes, feature requests, documentation improvements, or performance optimizations - every contribution helps make React Zero-UI better. ---- +**Get involved:** -## 📜 License +- 🐛 Found a bug? [Open an issue](https://github.com/react-zero-ui/core/issues) +- 💡 Have an idea? [Start a discussion](https://github.com/react-zero-ui/core/discussions) +- 🔧 Want to contribute code? Check out our [**Contributing Guide**](/docs/CONTRIBUTING.md) -[MIT](LICENSE) © Austin Serb +> **First time contributor?** We have good first issues labeled `good-first-issue` to help you get started! ---- +-- + +
+ +Made with ❤️ for the React community by [@austin1serb](https://github.com/austin1serb) -Built with ❤️ for the React community. If Zero‑UI makes your app feel ZERO fast, please ⭐️ the repo! +
diff --git a/README2.md b/README2.md deleted file mode 100644 index 69d25b6..0000000 --- a/README2.md +++ /dev/null @@ -1,146 +0,0 @@ - -## ⚡️ React Zero-UI -*The ZERO re-render UI state library* - -**The fastest possible UI updates in React. Period.** -Zero runtime, zero React re-renders, and the simplest developer experience ever. - -See the proof in [here](/docs/demo) - -npm version npm version License: MIT ![CI](https://github.com/react-zero-ui/core/actions/workflows/ci.yml/badge.svg?branch=main) - ---- - - -## 🔥 Core Concept: *"Pre-Rendering"* - -Why re-render UI if all states are known at build time? React Zero-UI **pre-renders** UI states once, and flips `data-*` attribute to update - that's it. - -**Example:** - -```tsx -const [, setTheme] = useUI("theme", "dark"); - -// Flip theme to "light" -setTheme("light"); // data-theme="light" on body -``` - -Tailwind usage: - -```html -
Fast & Reactive
-``` - ---- - -## 🚀 How it Works (Build-Time Magic) - -React Zero-UI uses a hyper-optimized AST resolver in development/build-time that scans your codebase for: - -* `useUI` and `useScopedUI` hook usage. -* Any variables resolving to strings (e.g., `'theme'`, `'modal-open'`). -* Tailwind variant classes (e.g., `theme-dark:bg-black`). - -This generates: - -* Optimal CSS with scoped variant selectors. -* Initial data-attributes injected onto the body (zero FOUC). -* **Zero runtime overhead in production**. - ---- - -## ⚙️ Installation (Zero-UI CLI) - -pre-requisites: -- Tailwind CSS v4 must already be initialized in your project. -- Vite or Next.js (App Router) - - -```bash -npx create-zero-ui -``` -> for manual configuration, see [manual installation.](https://github.com/react-zero-ui/core) - ---- - -## 🔨 API: `useUI` Hook (Global UI state) - -Simple hook mirroring React's `useState`: - -```tsx -import { useUI } from '@react-zero-ui/core'; - -const [theme, setTheme] = useUI("theme", "dark"); -``` - -* Flips global `data-theme` attribute on ``. -* Zero React re-renders. -* Initial state pre-rendered at build time (no FOUC). - ---- - -## 🎯 API: `useScopedUI` Hook (Scoped UI state) - -Control UI states at the element-level: - -```tsx -import { useScopedUI } from '@react-zero-ui/core'; - -const [theme, setTheme] = useScopedUI("theme", "dark"); - -// Flips data-theme attribute on the specific ref element -
- Scoped UI Here -
-``` - -* Data attribute flips on specific target element. -* Generates scoped CSS selectors only applying within the target element. - ---- - -## 🌈 API: CSS Variables Support - -Sometimes CSS variables are more efficient. React Zero-UI makes it trivial using the `CssVar` option: - -```tsx -import { useUI, CssVar } from '@react-zero-ui/core'; - -const [blur, setBlur] = useUI("blur", "0px", CssVar); - -// Flips CSS variable --blur on body -setBlur("5px"); // body { --blur: 5px } -``` - -**Scoped CSS Variable Example:** - -```tsx -const [blur, setBlur] = useScopedUI("blur", "0px", CssVar); - -
- Scoped blur effect. -
-``` - ---- - -## 🧪 Experimental: SSR-safe `zeroOnClick` - -Enable client-side interactivity **without leaving server components**. -Just 300 bytes of runtime overhead. - -See [experimental](./docs/assets/experimental.md) for more details. - -## 📦 Summary of Benefits - -* **Zero React re-renders:** Pure CSS-driven UI state. -* **Pre-rendered UI:** All states injected at build-time. and only loaded when needed. -* **Tiny footprint:** <350 bytes runtime, zero overhead for CSS states. -* **SSR-safe interaction:** Static server components, fully interactive. -* **Amazing DX:** Simple hooks, auto-generated Tailwind variants. -* **Highly optimized AST resolver:** Fast, cached build process. - -React Zero-UI delivers the fastest, simplest, most performant way to handle global and scoped UI state in modern React applications. - - -Made with ❤️ for the React community by [@austinserb](https://github.com/austin1serb) \ No newline at end of file diff --git a/CONTRIBUTING.md b/docs/CONTRIBUTING.md similarity index 57% rename from CONTRIBUTING.md rename to docs/CONTRIBUTING.md index 33f2ce3..b6bdd83 100644 --- a/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contributing to React Zero-UI -**Thanks for stopping by.** This project exists because builders like you push boundaries. If you're here to experiment, break things, or ship speed — you're in the right place. +**Thanks for stopping by.** This project exists because builders like you push boundaries. If you're here to experiment, break things, or ship speed - you're in the right place. --- @@ -11,7 +11,7 @@ > UI state should not require re-rendering. > CSS and `data-*` attributes can be enough. -It's fast because it **skips the VDOM entirely** — no state triggers, no diffing, no component redraws. +It's fast because it **skips the VDOM entirely** - no state triggers, no diffing, no component redraws. ### If you contribute: @@ -22,9 +22,10 @@ Stay **pre-rendered, declarative, and brutally fast.** ## 🧠 Monorepo Structure ``` -packages/ -├── core → @react-zero-ui/core (library logic + postcss) -└── cli → create-zero-ui (npx installer) +📁 packages/ +├── core ➡️ @react-zero-ui/core (library logic + postcss) +├── cli ➡️ create-zero-ui (npx installer) +└── eslint-zero-ui ➡️ eslint-zero-ui - in development ``` --- @@ -51,33 +52,34 @@ For questions, proposals, or early feedback. Share ideas before building. Use the templates. -- **Bug** → Include steps to reproduce, expected vs. actual behavior. -- **Feature** → Explain the _why_, and sketch a possible approach. +- **Bug** ➡️ Include steps to reproduce, expected vs. actual behavior. +- **Feature** ➡️ Explain the _why_, and sketch a possible approach. ### 3. Pull Requests - Use semantic commit prefixes: `feat:`, `fix:`, `chore:`, `refactor:` - Add tests if you touch logic, CLI, or rendering behavior. -- Keep PRs focused — one change per pull. -- Fill out the PR template — no empty descriptions. +- Keep PRs focused - one change per pull. +- Fill out the PR template - no empty descriptions. --- ## 🧪 Test Commands ```bash -pnpm test:unit # Core logic tests -pnpm test:cli # CLI creation flow -pnpm test:vite # E2E tests on Vite fixture -pnpm test:next # E2E tests on Next.js fixture -pnpm test # Runs all of the above +pnpm test:unit # Core logic tests +pnpm test:integration # Core logic tests +pnpm test:cli # CLI creation flow +pnpm test:vite # E2E tests on Vite fixture +pnpm test:next # E2E tests on Next.js fixture +pnpm test # Runs all of the above ``` --- ## 🤝 Code of Conduct -Keep it respectful. Push ideas hard, not people. +Keep it respectful and accessible. Push ideas hard, not people. --- diff --git a/docs/assets/demo.md b/docs/assets/demo.md deleted file mode 100644 index dff8337..0000000 --- a/docs/assets/demo.md +++ /dev/null @@ -1,35 +0,0 @@ -## 🚀 Demo + Benchmarks - -| Example | Link | What it shows | Link to Code | -| -- | -- | -- | -- | -| Interactive menu with render tracker | [Main Demo](https://zero-ui.dev/) | Compare Zero‑UI vs. React side‑by‑side while toggling a menu. | [Github](https://zero-ui.dev/react) | -| React benchmark (10 000 nested nodes) | [React 10k](https://zero-ui.dev/react) | How long the traditional React render path takes. | [Github](https://github.com/react-zero-ui/core/tree/main/examples/demo/src/app/react) | -| Zero‑UI benchmark (10 000 nested nodes) | [Zero‑UI 10k](https://zero-ui.dev/zero-ui) | Identical DOM, but powered by Zero‑UI's `data-*` switch. | [Github](https://github.com/react-zero-ui/core/tree/main/examples/demo/src/app/zero-ui) | - -source code for the demo: [Zero Rerender Demo](/examples/demo/) - ---- - -## 🧐 Why Zero‑UI? - -Every `setState` in React triggers the full VDOM → Diff → Reconciliation → Paint pipeline. For _pure UI state_ (themes, menus, toggles) that work is wasted. - -**Zero‑UI introduces "_PRE‑rendering_":** - -1. Tailwind variants for every state are **generated at build‑time**. -2. The app **pre‑renders once**. -3. Runtime state changes only **flip a `data-*`**. - -Result → **5-10× faster visual updates** with **ZERO additional bundle cost**. - -### 📊 Micro‑benchmarks (Apple M1) - -| Nodes updated | React state | Zero‑UI | Speed‑up | -| ------------- | ----------- | ------- | -------- | -| 10,000 | \~50 ms | \~5 ms | **10×** | -| 25,000 | \~180 ms | \~15 ms | **12×** | -| 50,000 | \~300 ms | \~20 ms | **15×** | - -Re‑run these numbers yourself via the links above with chrome dev tools. - ---- \ No newline at end of file diff --git a/docs/assets/experimental.md b/docs/assets/experimental.md deleted file mode 100644 index 9d2af2b..0000000 --- a/docs/assets/experimental.md +++ /dev/null @@ -1,58 +0,0 @@ - -## 🧪 Experimental: SSR-safe `zeroOnClick` - -Enable client-side interactivity **without leaving server components**. -Just 300 bytes of runtime overhead. - -### ⚙️ Installation (Zero-UI Experimental) - -```bash -npm install @react-zero-ui/core@0.3.1-beta.2 -``` - -Initialize once in your root: - -```tsx -"use client" - -/* ① import the generated defaults */ -import { variantKeyMap } from "../.zero-ui/attributes" -/* ② activate the runtime shipped in the package */ -import { activateZeroUiRuntime } from "@react-zero-ui/core/experimental/runtime" - -activateZeroUiRuntime(variantKeyMap) - -export const ZeroUiRuntime = () => null // this component just runs the side effect - -``` - -### Usage - -```tsx -import { zeroSSR } from "@react-zero-ui/core/experimental" - -
- Click me to cycle themes! -
-``` - -Usage is the same as the `useUI` hooks: -```html -
- Interactive Server Component! -
-``` - -**Scoped Version:** - -```tsx -import { zeroScopedOnClick } from '@react-zero-ui/experimental'; - -
// set the scope with a data-attribute that matches the key - -
-``` - -see the source code for the `zeroSSR` object, see [experimental](/packages/core/src/experimental) \ No newline at end of file diff --git a/docs/assets/manual-installation-vite.md b/docs/assets/manual-installation-vite.md deleted file mode 100644 index ad25c9d..0000000 --- a/docs/assets/manual-installation-vite.md +++ /dev/null @@ -1,53 +0,0 @@ - -### Manual Install Vite - -```bash -npm install @react-zero-ui/core @tailwindcss/postcss -``` - ---- - -## 🔧 Setup - -### Vite - -```js -// vite.config.* -import zeroUI from "@react-zero-ui/core/vite"; -import { defineConfig } from 'vite'; -import react from '@vitejs/plugin-react'; - -export default defineConfig({ - // ❗️Remove the default `tailwindcss()` plugin — Zero‑UI extends it internally - plugins: [zeroUI(), react()] -}); -``` -### Next.js (App Router) - -2. **Add the PostCSS plugin (must come _before_ Tailwind).** - - ```js - // postcss.config.js - module.exports = { plugins: { '@react-zero-ui/core/postcss': {}, tailwindcss: {} } }; - ``` - ---- - - - - -1. **Spread `bodyAttributes` on ``** in your root layout. - - ```tsx - // app/layout.tsx - import { bodyAttributes } from './.zero-ui/attributes'; - // or: import { bodyAttributes } from '../.zero-ui/attributes'; - - export default function RootLayout({ children }) { - return ( - - {children} - - ); - } - ``` \ No newline at end of file diff --git a/docs/assets/zero-ui-logo.png b/docs/assets/zero-ui-logo.png new file mode 100644 index 0000000..93de3cc Binary files /dev/null and b/docs/assets/zero-ui-logo.png differ diff --git a/docs/demo.md b/docs/demo.md new file mode 100644 index 0000000..6a4d104 --- /dev/null +++ b/docs/demo.md @@ -0,0 +1,65 @@ +# 🚀 Demo + Benchmarks + +
+ +**See Zero-UI in action** with interactive demos and performance comparisons. + +Experience the difference between React re-renders and Zero-UI's instant updates. + +[🎮 **Live Demo**](https://zero-ui.dev/) | [⚛️ **React Version**](https://zero-ui.dev/react) | [⚡️ **Zero-UI Version**](https://zero-ui.dev/zero-ui) + +
+ +--- + +## 🎯 Interactive Examples + +| Demo | Description | Live Link | Source Code | +| -- | -- | -- | -- | +| **🎛️ Interactive Menu** | Side-by-side comparison with render tracker | [Main Demo](https://zero-ui.dev/) | [GitHub](https://zero-ui.dev/react) | +| **⚛️ React Benchmark** | Traditional React render path (10k nodes) | [React 10k](https://zero-ui.dev/react) | [GitHub](https://github.com/react-zero-ui/core/tree/main/examples/demo/src/app/react) | +| **⚡️ Zero-UI Benchmark** | Identical DOM with `data-*` switching (10k nodes) | [Zero-UI 10k](https://zero-ui.dev/zero-ui) | [GitHub](https://github.com/react-zero-ui/core/tree/main/examples/demo/src/app/zero-ui) | + +> **📁 Full Demo Source:** [Zero Rerender Demo](/examples/demo/) + +--- + +## 🧐 Why Zero-UI? + +Every `setState` in React triggers the full **VDOM ➡️ Diff ➡️ Reconciliation ➡️ Paint** pipeline. For _pure UI state_ (themes, menus, toggles) **that work is wasted**. + +### 🔄 Zero-UI's "PRE-rendering" Approach: + +1. **🏗️ Build-time:** Tailwind variants generated for every state +2. **🎨 Pre-render:** App renders once with all possible states +3. **⚡️ Runtime:** State changes only flip a `data-*` attribute + +**Result:** **5-10× faster visual updates** with **ZERO additional bundle cost**. + +--- + +## 📊 Performance Benchmarks + +
+ +_Tested on Apple M1 - Chrome DevTools Performance Tab_ + +
+ +| **Nodes Updated** | **React State** | **Zero-UI** | **Speed Improvement** | +| :--: | :--: | :--: | :--: | +| 10,000 | ~50 ms | ~5 ms | **🚀 10× faster** | +| 25,000 | ~180 ms | ~15 ms | **🚀 12× faster** | +| 50,000 | ~300 ms | ~20 ms | **🚀 15× faster** | + +> **🔬 Try it yourself:** Re-run these benchmarks using the demo links above with Chrome DevTools. + +--- + +
+ +### Ready to get started? + +[**🚀 Get Started**](https://github.com/react-zero-ui/core/#-quick-start) and never re-render again. + +
diff --git a/docs/experimental.md b/docs/experimental.md new file mode 100644 index 0000000..965492a --- /dev/null +++ b/docs/experimental.md @@ -0,0 +1,197 @@ +
+

🧪 Experimental Runtime (Zero-UI)

+ +**SSR-safe runtime logic** for handling interactivity in React server components without using + +```diff +- use client +``` + +
+
+Designed to be tiny(~300 bytes), deterministic, and fully compatible with + +React Zero-UI's pre-rendered data-attribute model. + +
+ +--- + +### ❓ Why This Approach? + +**The Problem:** A single `onClick` event forces your entire component tree to become client-rendered. In Next.js, this means shipping extra JavaScript, losing SSR benefits, and adding hydration overhead-all for basic interactivity. + +**The Solution:** This design creates the perfect bridge between **static HTML** and **interactive UX**, while maintaining: + +- Server-rendered performance +- Zero JavaScript bundle overhead +- Instant visual feedback + +_Why sacrifice server-side rendering for a simple click handler when 300 bytes of runtime can handle all the clicks in your app?_ + +--- + +## 📦 Core Functionality + +### `activateZeroUiRuntime()` + +The core runtime entrypoint that enables client-side interactivity in server components: + +**How it works:** + +1. **🎯 Single Global Listener** - Registers one click event listener on `document` +2. **👂 Smart Detection** - Listens for clicks on elements with `data-ui` attributes +3. **🔍 Directive Parsing** - Interprets `data-ui` directives in this format. + +```diff ++ data-ui="global:key(val1,val2,...)" ➡️ flips data-key on document.body ++ data-ui="scoped:key(val1,val2,...)" ➡️ flips data-key on closest ancestor/self +``` + +4. **🔄 Round-Robin Cycling** - Cycles through values in sequence +5. **⚡️ Instant DOM Updates** - Updates DOM immediately for Tailwind responsiveness + +> **Note:** Guards against duplicate initialization using `window.__zero` flag. + +--- + +## 🛠️ Helper Functions + +### `zeroSSR.onClick()` & `scopedZeroSSR.onClick()` + +Utility functions that generate valid `data-ui` attributes for JSX/TSX: + +**Global Example:** + +```tsx +zeroSSR.onClick('theme', ['dark', 'light']); +// Returns: { 'data-ui': 'global:theme(dark,light)' } +``` + +**Scoped Example:** + +```tsx +scopedZeroSSR.onClick('modal', ['open', 'closed']); +// Returns: { 'data-ui': 'scoped:modal(open,closed)' } +``` + +**Development Validation:** + +- ✅ Ensures keys are kebab-case +- ✅ Validates at least one value is provided + +--- + +## 🚀 Installation & Setup + +### Step 1: Install Package + +```bash +npm install @react-zero-ui/core@0.3.1-beta.2 +``` + +### Step 2: Generate Variants + +Run your development server to generate the required variant map: + +```bash +npm run dev +``` + +This creates `.zero-ui/attributes.ts` containing the variant map needed for runtime activation. + +### Step 3: Create `` Component + +```tsx +'use client'; + +import { variantKeyMap } from 'path/to/.zero-ui/attributes'; +import { activateZeroUiRuntime } from '@react-zero-ui/core/experimental/runtime'; + +activateZeroUiRuntime(variantKeyMap); + +export const InitZeroUI = () => null; +``` + +### Step 4: Add to Root Layout + +```tsx +import { InitZeroUI } from 'path/to/InitZeroUI'; + +export default function RootLayout({ children }) { + return ( + + + + {children} + + + ); +} +``` + +--- + +## 💡 Usage Examples + +### Global Theme Toggle + +```tsx +import { zeroSSR } from '@react-zero-ui/core/experimental'; + +
Click me to cycle themes!
; +``` + +**Pair with Tailwind variants:** + +```html +
Interactive Server Component!
+``` + +### Scoped Modal Toggle + +```tsx +import { scopedZeroSSR } from '@react-zero-ui/experimental'; + +// ❗️ Scopes based on matching data-* attribute (e.g. data-modal) +
+ +
; +``` + +--- + +## 🧠 Design Philosophy + +### Core Principles + +- **🚫 No React State** - Zero re-renders involved +- **🎯 Pure DOM Mutations** - Works entirely via `data-*` attribute changes +- **🔧 Server Component Compatible** - Full compatibility with all server components +- **⚡️ Tailwind-First** - Designed for conditional CSS classes + +--- + +## 📋 Summary + +| Feature | Description | +| ------------------------------- | --------------------------------------------------------- | +| **`activateZeroUiRuntime()`** | Enables click handling on static components via `data-ui` | +| **`zeroSSR` / `scopedZeroSSR`** | Generate valid click handlers as JSX props | +| **Runtime Overhead** | ~300 bytes total | +| **React Re-renders** | Zero | +| **Server Component Support** | ✅ Full compatibility | + +> **Source Code:** See [experimental](/packages/core/src/experimental) for implementation details. + +--- + +
+ +**The bridge between static HTML and interactive UX** + +_No state. No runtime overhead. Works in server components. ZERO re-renders._ + +[**🚀 Get Started in less than 5 minutes**](/#-quick-start) + +
diff --git a/docs/installation-next.md b/docs/installation-next.md new file mode 100644 index 0000000..38ee391 --- /dev/null +++ b/docs/installation-next.md @@ -0,0 +1,76 @@ +### Next.js (App Router) Setup + +1. **Install the dependencies** + +```bash +npm install @react-zero-ui/core +``` + +```bash +npm install @tailwindcss/postcss +``` + +--- + +2. **Add the PostCSS plugin (must come _before_ Tailwind).** + +```js +// postcss.config.* ESM Syntax +const config = { + // ❗️ Zero-UI must come before Tailwind + plugins: ['@react-zero-ui/core/postcss', '@tailwindcss/postcss'], +}; +export default config; +``` + +```js +// postcss.config.* Common Module Syntax +module.exports = { + // ❗️ Zero-UI must come before Tailwind + plugins: { '@react-zero-ui/core/postcss': {}, tailwindcss: {} }, +}; +``` + +3. **Import Tailwind CSS** + +```css +// global.css +@import "tailwindcss"; +``` + +--- + +4. **Start the App** + +```bash +npm run dev +``` + +> Zero-UI will generate a .zero-ui folder in your project root. and generate the attributes.ts and type definitions for it. + +--- + +5. **Preventing FOUC (Flash Of Unstyled Content)** + +Spread `bodyAttributes` on `` in your root layout. + +```tsx +// app/layout.tsx +import { bodyAttributes } from './.zero-ui/attributes'; + +export default function RootLayout({ children }) { + return ( + + // ❗️ Spread the bodyAttributes on the body tag + {children} + + ); +} +``` + +**Thats it.** +Zero-UI will now add used data-\* attributes to the body tag and the CSS will be injected and transformed by tailwind. + +** 🧪 Checkout our Experimental SSR Safe OnClick Handler ** + +[**🚀 Zero UI OnClick**](/docs/experimental.md) diff --git a/docs/installation-vite.md b/docs/installation-vite.md new file mode 100644 index 0000000..21cda94 --- /dev/null +++ b/docs/installation-vite.md @@ -0,0 +1,45 @@ +### Vite Setup + +1. **Install the dependencies** + +```bash +npm install @react-zero-ui/core +``` + +```bash +npm install @tailwindcss/postcss +``` + +--- + +## 🔧 Setup + +### Vite + +2. **Add the plugin to your vite.config.ts** + +```js +// vite.config.* +import zeroUI from '@react-zero-ui/core/vite'; +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; +import tailwindCss from '@tailwindcss/postcss'; + +export default defineConfig({ + // ❗️Remove the default `tailwindcss()` plugin - and pass it into the `zeroUI` plugin + plugins: [zeroUI({ tailwind: tailwindCss }), react()], +}); +``` + +3. **Import Tailwind CSS** + +```css +// global.css +@import "tailwindcss"; +``` + +**Thats it.** + +The plugin will add the data-\* attributes to the body tag (no FOUC) and the CSS will be injected and transformed by tailwind. + + diff --git a/docs/assets/internal.md b/docs/internal.md similarity index 83% rename from docs/assets/internal.md rename to docs/internal.md index b44cbf3..d9c0d5b 100644 --- a/docs/assets/internal.md +++ b/docs/internal.md @@ -1,12 +1,12 @@ # Internal docs -Below is a **"mental model"** of the Zero‑UI variant extractor—distilled so that _another_ human (or LLM) can reason about, extend, or safely refactor the code‑base. +Below is a **"mental model"** of the Zero‑UI variant extractor-distilled so that _another_ human (or LLM) can reason about, extend, or safely refactor the code‑base. --- ## 1. Top‑level goal -1. **Locate every hook call** `(ast-parsing.cts) → collectUseUIHooks` +1. **Locate every hook call** `(ast-parsing.cts) ➡️ collectUseUIHooks` ```ts const [value, setterFn] = useUI('stateKey', 'initialValue'); @@ -16,14 +16,14 @@ Below is a **"mental model"** of the Zero‑UI variant extractor—distilled so - `stateKey` must be a _local_, static string. - `initialValue` follows the same rule. -3. **Globally scan all project files** for **variant tokens that match any discovered `stateKey`**—regardless of where hooks are declared. `(scanner.cts) → scanVariantTokens` +3. **Globally scan all project files** for **variant tokens that match any discovered `stateKey`**-regardless of where hooks are declared. `(scanner.cts) ➡️ scanVariantTokens` _Examples_ ```html - +
- + ``` ```bash @@ -47,19 +47,25 @@ source files ─► ├─► Map> key: string; // 'stateKey' values: string[]; // ['light', 'dark', …] (unique & sorted) initialValue: string; // from 2nd arg of useUI() + scope: 'global' | 'scoped'; }; ``` -5. **Emit Tailwind `@custom-variant`s** for every `key‑value` pair `(helpers.cts) → buildCss` +5. **Emit Tailwind** `@custom-variant` for every `key‑value` pair `(helpers.cts) ➡️ buildCss` - ```css - @custom-variant ${keySlug}-${valSlug} { - &:where(body[data-${keySlug}="${valSlug}"] *) { @slot; } - [data-${keySlug}="${valSlug}"] &, &[data-${keySlug}="${valSlug}"] { @slot; } - } - ``` +```ts +function buildLocalSelector(keySlug: string, valSlug: string): string { + return; + `[data-${keySlug}="${valSlug}"] &, &[data-${keySlug}="${valSlug}"] { @slot; }`; +} + +function buildGlobalSelector(keySlug: string, valSlug: string): string { + return; + `&:where(body[data-${keySlug}='${valSlug}'] &) { @slot; }`; +} +``` -6. **Generate the attributes file** so SSR can inject the `` data‑attributes `(helpers.cts) → generateAttributesFile`. +6. **Generate the attributes file** so SSR can inject the `` data‑attributes `(helpers.cts) ➡️ generateAttributesFile`. --- @@ -70,7 +76,7 @@ source files ─► ├─► Map> | **A - collectUseUIHooks** | Single AST traversal per file.
• Validate `useUI()` shapes.
• Resolve **stateKey** & **initialValue** with **`literalFromNode`** (§3).
• Builds global set of all state keys. | `HookMeta[]` = `{ stateKey, initialValue }[]`, global `Set` | | **B - global scanVariantTokens** | Single global regex scan pass over all files (same glob & delimiters Tailwind uses).
Matches tokens for **every stateKey discovered in Stage A**. | `Map>` | -The pipeline now ensures tokens are captured globally—regardless of hook declarations in each file. +The pipeline now ensures tokens are captured globally-regardless of hook declarations in each file. --- @@ -82,12 +88,12 @@ Everything funnels through **`literalFromNode`**. Think of it as a deterministic ```bash ┌──────────────────────────────┬──────────────────────────┐ -│ Expression │ Accepted? → Returns │ +│ Expression │ Accepted? ➡️ Returns │ ├──────────────────────────────┼──────────────────────────┤ │ "dark" │ ✅ string literal │ │ `dark` │ ✅ template literal │ │ `th-${COLOR}` │ ✅ if COLOR is const │ -│ "a" + "b" │ ✅ → "ab" │ +│ "a" + "b" │ ✅ ➡️ "ab" │ │ a || b, a ?? b │ ✅ tries left, then right│ │ const DARK = "dark" │ ✅ top-level const only │ │ THEMES.dark │ ✅ const object access │ @@ -114,7 +120,7 @@ Everything funnels through **`literalFromNode`**. Think of it as a deterministic | Helper | Purpose | | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | **`resolveTemplateLiteral`** | Ensures every `${expr}` resolves via `literalFromNode`. | -| **`resolveLocalConstIdentifier`** | Maps an `Identifier` → its `const` initializer _iff_ initializer is a local static string/template. Imported bindings rejected explicitly. | +| **`resolveLocalConstIdentifier`** | Maps an `Identifier` ➡️ its `const` initializer _iff_ initializer is a local static string/template. Imported bindings rejected explicitly. | | **`resolveMemberExpression`** | Static walk of `obj.prop`, `obj['prop']`, `obj?.prop`, arrays, numeric indexes, optional‑chaining… Throws if unresolved. | | **`literalFromNode`** | Router calling above; memoised (`WeakMap`) per AST node. | diff --git a/packages/core/__tests__/fixtures/vite/src/index.css b/docs/rules.md similarity index 100% rename from packages/core/__tests__/fixtures/vite/src/index.css rename to docs/rules.md diff --git a/docs/usage-examples.md b/docs/usage-examples.md new file mode 100644 index 0000000..e69de29 diff --git a/examples/demo/.zero-ui/init-zero-ui.ts b/examples/demo/.zero-ui/init-zero-ui.ts index 5bf0023..809f4b7 100644 --- a/examples/demo/.zero-ui/init-zero-ui.ts +++ b/examples/demo/.zero-ui/init-zero-ui.ts @@ -15,9 +15,9 @@ if (typeof window !== 'undefined') { const [, key, rawVals = ''] = el.dataset.ui!.match(/^cycle:([\w-]+)(?:\((.*?)\))?$/) || []; - if (!(`data-${key}` in bodyAttributes)) return; // unknown variant → bail + if (!(`data-${key}` in bodyAttributes)) return; // unknown variant ➡️ bail - const vals = rawVals.split(','); // '' → [''] OK for toggle + const vals = rawVals.split(','); // '' ➡️ [''] OK for toggle const dsKey = toCamel(`data-${key}`); const target = (el.closest(`[data-${key}]`) as HTMLElement) ?? document.body; diff --git a/package.json b/package.json index 534c6c0..808d816 100644 --- a/package.json +++ b/package.json @@ -1,57 +1,82 @@ { "name": "react-zero-ui-monorepo", - "private": true, - "type": "module", - "engines": { - "node": ">=22" + "private": false, + "description": "Ultra-fast React UI state library with zero runtime, zero re-renders, Tailwind variant support, and automatic data-attribute/css-vars based styling. Replace context, prop drilling, and global stores with build-time magic.", + "keywords": [ + "react", + "react state", + "ui state", + "global state", + "scoped state", + "state management", + "tailwind", + "tailwind variants", + "postcss plugin", + "fastest ui updates", + "zero rerenders", + "zero render", + "no context", + "no prop drilling", + "css driven state", + "data attributes", + "ssr safe", + "instant ui updates", + "react optimization", + "high performance react" + ], + "funding": { + "type": "github", + "url": "https://github.com/sponsors/austin1serb" }, + "type": "module", "workspaces": [ "packages/*" ], - "packageManager": "pnpm@10.13.1", - "references": [ - { - "path": "packages/core" - }, - { - "path": "packages/cli" - }, - { - "path": "packages/eslint-plugin-react-zero-ui" - } - ], "scripts": { - "preinstall": "npx only-allow pnpm", - "reset": "git clean -fdx && pnpm install --frozen-lockfile && pnpm prepack:core && pnpm i-tarball", "bootstrap": "pnpm install --frozen-lockfile && pnpm build && pnpm prepack:core && pnpm i-tarball", "build": "cd packages/core && pnpm build", - "test": "cd packages/core && pnpm test:all && pnpm smoke", - "prepack:core": "pnpm -F @react-zero-ui/core pack --pack-destination ./dist", - "i-tarball": "node scripts/install-local-tarball.js", - "test:vite": "cd packages/core && pnpm test:vite", - "test:next": "cd packages/core && pnpm test:next", - "test:integration": "cd packages/core && pnpm test:integration", - "test:unit": "cd packages/core && pnpm test:unit", - "test:cli": "cd packages/core && pnpm test:cli", + "build-output": "npx esbuild ./packages/core/dist/index.js --bundle --minify --format=esm --external:react --define:process.env.NODE_ENV='\"production\"'", + "dev": "pnpm install && pnpm build && pnpm prepack:core && pnpm i-tarball", "format": "prettier --write .", + "i-tarball": "node scripts/install-local-tarball.js", + "preinstall": "npx only-allow pnpm", "lint": "eslint .", "lint:fix": "eslint . --fix", - "typecheck": "tsc --noEmit --project tsconfig.base.json", + "prepack:core": "pnpm -F @react-zero-ui/core pack --pack-destination ./dist", + "reset": "git clean -fdx && pnpm install --frozen-lockfile && pnpm prepack:core && pnpm i-tarball", "size": "npx esbuild ./packages/core/dist/index.js --bundle --minify --format=esm --external:react --define:process.env.NODE_ENV='\"production\"' | gzip -c | wc -c", - "build-output": "npx esbuild ./packages/core/dist/index.js --bundle --minify --format=esm --external:react --define:process.env.NODE_ENV='\"production\"'" + "test": "cd packages/core && pnpm test:all && pnpm smoke", + "test:cli": "cd packages/core && pnpm test:cli", + "test:integration": "cd packages/core && pnpm test:integration", + "test:next": "cd packages/core && pnpm test:next", + "test:unit": "cd packages/core && pnpm test:unit", + "test:vite": "cd packages/core && pnpm test:vite", + "typecheck": "tsc --noEmit --project tsconfig.base.json" }, "devDependencies": { "@eslint/js": "^9.32.0", "@types/node": "^24.1.0", - "@typescript-eslint/eslint-plugin": "^8.38.0", - "@typescript-eslint/parser": "^8.38.0", "esbuild": "^0.25.8", "eslint": "^9.32.0", "eslint-plugin-import": "^2.32.0", "eslint-plugin-n": "^17.21.3", "prettier": "^3.6.2", - "release-please": "^17.1.1", "tsx": "^4.20.3", "typescript": "^5.9.2" - } -} + }, + "packageManager": "pnpm@10.13.1", + "engines": { + "node": ">=22" + }, + "references": [ + { + "path": "packages/core" + }, + { + "path": "packages/cli" + }, + { + "path": "packages/eslint-zero-ui" + } + ] +} \ No newline at end of file diff --git a/packages/cli/README.md b/packages/cli/README.md index d59dbcf..f7438f2 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -1,89 +1,93 @@ -# Create Zero-UI -A blazing-fast React CLI starter powered by **React Zero-UI** — the pre-rendered UI state engine with zero re-renders and zero runtime overhead. +# create-zero-ui + +> ⚡ Instantly scaffold React Zero-UI into your Next.js or Vite project ```bash -npx create-zero-ui -``` -🏁 Instantly scaffold and patch your **Next.js (App Router)** or **Vite** app with: +npx create-zero-ui -✅ Tailwind CSS v4 integration -✅ Zero-UI Babel + PostCSS setup -✅ Autogenerated `data-*` UI state system -✅ One command, production-ready result +``` --- -## 🧠 What is Zero-UI? +## 🚀 What It Sets Up -Zero-UI is a global UI state engine that updates your interface using `data-*` attributes — **no React state, no VDOM, no re-renders**. -It works by: +### ✅ Shared (Next.js & Vite) -1. Scanning your components for `useUI()` hooks -2. Pre-generating Tailwind variants for each UI state -3. Updating `data-*` attributes on `` to drive the UI instantly +* Adds `@react-zero-ui/core` to your project +* Generates `.zero-ui/attributes.js` + `attributes.d.ts` +* Patches your `tsconfig.json`: -👉 Live Demo: [https://zero-ui.dev](https://zero-ui.dev) -👉 Package: [@react-zero-ui/core](https://www.npmjs.com/package/@react-zero-ui/core) + ```json + "paths": { + "@zero-ui/attributes": ["./.zero-ui/attributes.js"] + } + ``` --- -## 🚀 Quickstart +### 🔷 Next.js Specific -Inside your project root: +* Injects initial `data-*` attributes into `app/layout.tsx` +* Adds `postcss.config` with: -```bash -npx create-zero-ui -``` + ```js + plugins: [ + // ❗zero-ui must come before tailwind + "@react-zero-ui/core/postcss", + "@tailwindcss/postcss" + ] + ``` -That's it — you'll get: +--- -- `.zero-ui/attributes.js` autogen -- Working PostCSS + Tailwind integration -- Babel config patched if needed -- Ready to use `useUI()` in components +### 🔶 Vite Specific ---- +* Patches `vite.config.ts` with: -## 📦 Package Used + ```ts + export default defineConfig({ + plugins: [zeroUI(), react()] + }); + ``` +* Vite **does not require** a PostCSS config -Powered by: +--- -```json -"@react-zero-ui/core": "^0.1.0" -``` +## 🧪 Works With -Full docs and live benchmarks: -👉 [https://github.com/react-zero-ui/core](https://github.com/react-zero-ui/core) +* `Next.js` (App Router) +* `Vite` (React projects) +* `pnpm`, `yarn`, or `npm` --- -## 🧬 Example Usage +## 🛠 Usage -## 🏄‍♂️ Usage +```bash +npx create-zero-ui +``` -![react zero ui usage explained](https://raw.githubusercontent.com/react-zero-ui/core/main/docs/assets/useui-explained.webp) +Follow the CLI prompts to scaffold your config in seconds. --- -## 🛠 Tech Notes +## 📚 Related -- This CLI only supports Tailwind v4+ projects -- It does **not** install Tailwind for you — install Tailwind first -- You must restart your dev server after running the CLI to see effects +* [@react-zero-ui/core](https://github.com/react-zero-ui/core) +* [Documentation](https://github.com/react-zero-ui/core/tree/main/docs) --- -## 🙌 Author - -Made by [@austinserb](https://github.com/austin1serb) +## 🤝 Contributing -Built with ❤️ for the React community. If Zero‑UI makes your app feel ZERO fast, please ⭐️ the repo! +Found a bug or want to help? +PRs welcome at [react-zero-ui/core](https://github.com/react-zero-ui/core). --- -## 📜 License +## License -[MIT](LICENSE) © Austin Serb +MIT diff --git a/packages/cli/bin.js b/packages/cli/bin.js index 2b3f121..1240451 100755 --- a/packages/cli/bin.js +++ b/packages/cli/bin.js @@ -18,8 +18,7 @@ if (!existsSync(resolve(target, 'package.json'))) exec('init', ['-y']); exec(pm === 'yarn' ? 'add' : 'install', ['@react-zero-ui/core']); /* 3️⃣ dev deps */ -// TODO figure out if we can do it without tailwindcss and only the postcss plugin -exec(pm === 'yarn' ? 'add' : 'install', ['postcss', 'tailwindcss', '@tailwindcss/postcss', '--save-dev']); +exec(pm === 'yarn' ? 'add' : 'install', ['@tailwindcss/postcss', '--save-dev']); /* 4️⃣ handoff */ // eslint-disable-next-line import/no-unresolved diff --git a/packages/cli/package.json b/packages/cli/package.json index 98d1ad2..2f2d000 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,24 +1,48 @@ { "name": "create-zero-ui", - "version": "1.0.9", + "version": "1.1.2", + "description": "Zero-UI project scaffolder for React. Instantly sets up zero-runtime UI state, Tailwind variants, PostCSS, and SSR-safe config in Vite or Next.js apps.", + "keywords": [ + "react", + "react state", + "ui state", + "global state", + "scoped state", + "state management", + "tailwind", + "tailwind variants", + "postcss plugin", + "fastest ui updates", + "zero rerenders", + "zero render", + "no context", + "no prop drilling", + "css driven state", + "data attributes", + "ssr safe", + "instant ui updates", + "react optimization", + "high performance react" + ], + "funding": { + "type": "github", + "url": "https://github.com/sponsors/austin1serb" + }, "type": "module", "main": "./bin.js", "bin": { "react-zero-ui": "bin.js" }, - "scripts": { - "test": "node --test ../core/__tests__/unit/cli.test.cjs" - }, "files": [ "bin.js", "package.json", "README.md", "LICENSE" ], + "scripts": { + "test": "node --test ../core/__tests__/unit/cli.test.cjs" + }, "dependencies": { - "@react-zero-ui/core": "^0.2.2", - "postcss": "^8.4.27", - "tailwindcss": "^4.0.0", - "@tailwindcss/postcss": "^4.1.8" + "@react-zero-ui/core": "^0.3.3" } -} +} \ No newline at end of file diff --git a/packages/cli/tests/test-cli.js b/packages/cli/tests/test-cli.js new file mode 100644 index 0000000..4cc8020 --- /dev/null +++ b/packages/cli/tests/test-cli.js @@ -0,0 +1,383 @@ +import { test } from 'node:test'; +import assert from 'node:assert'; +import fs from 'node:fs'; +import path from 'node:path'; +import os from 'node:os'; +import { spawn } from 'node:child_process'; +import { fileURLToPath } from 'node:url'; +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const binScript = path.resolve(__dirname, '../bin.js'); + +test('CLI script uses existing package.json if it exists', async () => { + const testDir = createTestDir(); + + try { + // Create a custom package.json + const customPackageJson = { name: 'my-test-app', version: '2.0.0', description: 'Custom test app' }; + + const packageJsonPath = path.join(testDir, 'package.json'); + fs.writeFileSync(packageJsonPath, JSON.stringify(customPackageJson, null, 2)); + + // Run CLI (this will timeout on npm install, but that's ok for this test) + await runCLIScript(testDir, 5000); + + // Check that our custom package.json is preserved + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')); + assert.strictEqual(packageJson.name, 'my-test-app', 'Custom name should be preserved'); + assert.strictEqual(packageJson.version, '2.0.0', 'Custom version should be preserved'); + assert.strictEqual(packageJson.description, 'Custom test app', 'Custom description should be preserved'); + + console.log('✅ Existing package.json preserved'); + } finally { + cleanupTestDir(testDir); + } +}); + +test('CLI script installs correct dependencies', async () => { + const testDir = createTestDir(); + + try { + // Create package.json to avoid npm init + const packageJson = { name: 'test-app', version: '1.0.0', scripts: {}, dependencies: {}, devDependencies: {} }; + fs.writeFileSync(path.join(testDir, 'package.json'), JSON.stringify(packageJson, null, 2)); + + // Mock npm by creating a fake npm script that logs what would be installed + const mockNpmScript = `#!/bin/bash + echo "Mock npm called with: $@" >> npm-calls.log + + # Simulate package installation by updating package.json + if [[ "$*" == *"install"* ]]; then + node -e " + import fs from 'fs'; + const pkg = JSON.parse(fs.readFileSync('package.json', 'utf-8')); + + // Handle production dependency + if (process.argv.slice(2).includes('@react-zero-ui/core') && !process.argv.slice(2).includes('--save-dev')) { + if (!pkg.dependencies) pkg.dependencies = {}; + pkg.dependencies['@react-zero-ui/core'] = '^1.0.0'; + } + + // Handle dev dependencies + if (process.argv.slice(2).includes('--save-dev')) { + if (!pkg.devDependencies) pkg.devDependencies = {}; + + pkg.devDependencies['@tailwindcss/postcss'] = '^4.1.8'; + } + + fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2)); + " -- $@ + fi + `; + + const mockNpmPath = path.join(testDir, 'npm'); + fs.writeFileSync(mockNpmPath, mockNpmScript); + fs.chmodSync(mockNpmPath, '755'); + + // Update PATH to use our mock npm + const originalPath = process.env.PATH; + process.env.PATH = `${testDir}:${originalPath}`; + + try { + // Run CLI script + await runCLIScript(testDir, 10000).catch((err) => { + console.log('CLI run resulted in:', err.message); + return { error: err.message }; + }); + + // Check that npm was called + const npmCallsPath = path.join(testDir, 'npm-calls.log'); + if (fs.existsSync(npmCallsPath)) { + const npmCalls = fs.readFileSync(npmCallsPath, 'utf-8'); + console.log('NPM calls:', npmCalls); + + assert(npmCalls.includes('install'), 'npm install should be called'); + assert(npmCalls.includes('@react-zero-ui/core'), 'Should install react-zero-ui'); + assert(npmCalls.includes('@tailwindcss/postcss'), 'Should install @tailwindcss/postcss'); + } + + // Check package.json was updated with dependencies + const finalPackageJson = JSON.parse(fs.readFileSync(path.join(testDir, 'package.json'), 'utf-8')); + + // react-zero-ui should be in dependencies (production), not devDependencies + assert(finalPackageJson.dependencies['@react-zero-ui/core'], 'react-zero-ui should be in dependencies'); + assert(finalPackageJson.devDependencies['@tailwindcss/postcss'], '@tailwindcss/postcss should be in devDependencies'); + + console.log('✅ All required dependencies installed'); + } finally { + process.env.PATH = originalPath; + } + } finally { + cleanupTestDir(testDir); + } +}); + +test('CLI script handles different target directories', async () => { + const baseTestDir = createTestDir(); + const subDir = path.join(baseTestDir, 'my-project'); + + try { + // Create subdirectory + fs.mkdirSync(subDir, { recursive: true }); + + await new Promise((resolve, reject) => { + const child = spawn('node', [binScript, 'my-project'], { cwd: baseTestDir, stdio: ['pipe', 'pipe', 'pipe'] }); + + const timer = setTimeout(() => { + child.kill('SIGKILL'); + resolve({ timedOut: true }); + }, 5000); + + child.on('close', (code) => { + clearTimeout(timer); + resolve({ code }); + }); + + child.on('error', (error) => { + clearTimeout(timer); + reject(error); + }); + }); + + // Check that package.json was created in subdirectory + const packageJsonPath = path.join(subDir, 'package.json'); + assert(fs.existsSync(packageJsonPath), 'package.json should be created in target subdirectory'); + + console.log('✅ CLI script works with target directories'); + } finally { + cleanupTestDir(baseTestDir); + } +}); + +// Additional test for library CLI functionality +test('Library CLI initializes project correctly', async () => { + const testDir = createTestDir(); + + try { + // Create a test React component with useUI hook + const componentDir = path.join(testDir, 'components'); + fs.mkdirSync(componentDir, { recursive: true }); + + const testComponent = ` +import { useUI } from '@react-zero-ui/core'; + +export function TestComponent() { + const [count, setCount] = useUI("0", "count"); + + return ( +
+ +
+ ); +} +`; + + fs.writeFileSync(path.join(componentDir, 'TestComponent.jsx'), testComponent); + + // Import and run the library CLI directly + + // Mock console to capture output + const originalConsoleLog = console.log; + const logMessages = []; + console.log = (...args) => { + logMessages.push(args.join(' ')); + originalConsoleLog(...args); + }; + + // Change to test directory and run CLI + const originalCwd = process.cwd(); + process.chdir(testDir); + + try { + await runCLIScript(testDir); + + // Check that initialization messages were logged + console.log('✅ Library CLI initializes project correctly'); + } finally { + process.chdir(originalCwd); + console.log = originalConsoleLog; + } + } finally { + cleanupTestDir(testDir); + } +}); + +// Test error handling in library CLI + +// Test CLI script with no arguments (current directory) +test('CLI script works with no target directory (defaults to current)', async () => { + const testDir = createTestDir(); + + try { + // Mock npm to avoid actual installation but make it create package.json + const mockNpmScript = `#!/bin/bash +echo "Mock npm completed" +# Simulate npm init -y creating package.json when it doesn't exist +if [[ "$*" == *"init"* ]] && [[ ! -f "package.json" ]]; then + echo '{"name": "test-project", "version": "1.0.0", "description": ""}' > package.json +fi +`; + const mockNpmPath = path.join(testDir, 'npm'); + fs.writeFileSync(mockNpmPath, mockNpmScript); + fs.chmodSync(mockNpmPath, '755'); + + const originalPath = process.env.PATH; + process.env.PATH = `${testDir}:${originalPath}`; + + try { + await new Promise((resolve, reject) => { + const child = spawn('node', [binScript], { + // No target directory argument + cwd: testDir, + stdio: ['pipe', 'pipe', 'pipe'], + }); + + const timer = setTimeout(() => { + child.kill('SIGKILL'); + resolve({ timedOut: true }); + }, 5000); + + child.on('close', (code) => { + clearTimeout(timer); + resolve({ code }); + }); + + child.on('error', (error) => { + clearTimeout(timer); + reject(error); + }); + }); + + // Check that package.json was created in current directory + const packageJsonPath = path.join(testDir, 'package.json'); + assert(fs.existsSync(packageJsonPath), 'package.json should be created in current directory'); + + console.log('✅ CLI script works with no target directory specified'); + } finally { + process.env.PATH = originalPath; + } + } finally { + cleanupTestDir(testDir); + } +}); + +// Test CLI script with invalid target directory +test('CLI script handles invalid target directory', async () => { + const testDir = createTestDir(); + + try { + const result = await new Promise((resolve) => { + const child = spawn('node', [binScript, 'non-existent-dir'], { cwd: testDir, stdio: ['pipe', 'pipe', 'pipe'] }); + + let stderr = ''; + child.stderr.on('data', (data) => { + stderr += data.toString(); + }); + + const timer = setTimeout(() => { + child.kill('SIGKILL'); + resolve({ timedOut: true, stderr }); + }, 5000); + + child.on('close', (code) => { + clearTimeout(timer); + resolve({ code, stderr }); + }); + + child.on('error', (error) => { + clearTimeout(timer); + resolve({ error: error.message }); + }); + }); + + // The CLI should either create the directory or handle the error gracefully + assert(result.code !== undefined || result.error || result.timedOut, 'CLI should handle invalid directory gracefully'); + + console.log('✅ CLI script handles invalid target directory'); + } finally { + cleanupTestDir(testDir); + } +}); + +// Helper to create isolated test directory +function createTestDir() { + const testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'zero-ui-cli-test-')); + return testDir; +} + +// Helper to clean up test directory +function cleanupTestDir(testDir) { + if (fs.existsSync(testDir)) { + try { + fs.rmSync(testDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 }); + } catch (error) { + // On Windows/macOS, sometimes files are locked. Try alternative cleanup + console.warn(`Warning: Could not clean up test directory ${testDir}: ${error.message}`); + try { + // Try to remove files individually + const cleanup = (dir) => { + const entries = fs.readdirSync(dir, { withFileTypes: true }); + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + cleanup(fullPath); + try { + fs.rmdirSync(fullPath); + } catch (e) { + // Ignore + console.log(`Error deleting directory ${fullPath}: ${e.message}`); + } + } else { + try { + fs.unlinkSync(fullPath); + } catch (e) { + // Ignore + console.log(`Error deleting file ${fullPath}: ${e.message}`); + } + } + } + }; + cleanup(testDir); + fs.rmdirSync(testDir); + } catch (secondError) { + console.warn(`Final cleanup attempt failed: ${secondError.message}`); + } + } + } +} + +// Helper to run CLI script and capture output +function runCLIScript(targetDir, timeout = 30000) { + return new Promise((resolve, reject) => { + // Updated path to the correct CLI script location + + const child = spawn('node', [binScript, '.'], { cwd: targetDir, stdio: ['pipe', 'pipe', 'pipe'] }); + + let stdout = ''; + let stderr = ''; + + child.stdout.on('data', (data) => { + stdout += data.toString(); + }); + + child.stderr.on('data', (data) => { + stderr += data.toString(); + }); + + const timer = setTimeout(() => { + child.kill('SIGKILL'); + reject(new Error(`CLI script timed out after ${timeout}ms`)); + }, timeout); + + child.on('close', (code) => { + clearTimeout(timer); + resolve({ code, stdout, stderr, success: code === 0 }); + }); + + child.on('error', (error) => { + clearTimeout(timer); + reject(error); + }); + }); +} diff --git a/packages/core/README.md b/packages/core/README.md index bd756c5..b7d43a6 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -1,180 +1,175 @@ -# React Zero‑UI (Beta) +# @react-zero-ui/core -**Instant UI state updates. ZERO React re‑renders. <1 KB runtime.** +![Tagline](https://img.shields.io/badge/The_ZERO_re--render_UI_state_library-%235500AD?style=flat&label=) +![Zero UI logo](https://raw.githubusercontent.com/react-zero-ui/core/upgrade/resolver/docs/assets/zero-ui-logo.png) -Pre‑render your UI once, flip a `data-*` attribute to update — that's it. +**The fastest possible UI updates in React. Period.** +Zero runtime, zero React re-renders, and the simplest developer experience ever. +_Say goodbye to context and prop-drilling._ -npm version npm version License: MIT ![CI](https://github.com/react-zero-ui/core/actions/workflows/ci.yml/badge.svg?branch=main) +[![Bundle size](https://badgen.net/bundlephobia/minzip/@react-zero-ui/core@0.2.6)](https://bundlephobia.com/package/@react-zero-ui/core@0.2.6) +[![npm version](https://img.shields.io/npm/v/@react-zero-ui/core)](https://www.npmjs.com/package/@react-zero-ui/core) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +![CI](https://github.com/react-zero-ui/core/actions/workflows/ci.yml/badge.svg?branch=main) ---- - -## 📚 Quick Links - -- [⚡️ Quick Start](#️-quick-start) -- [🏄 Usage](#-usage) -- [🧬 How it works](#-how-it-works) -- [✅ Features](#-features) -- [🏗 Best Practices](#-best-practices) +[📖 See the proof](https://github.com/react-zero-ui/core/blob/main/docs/assets/demo.md) • [🚀 Quick Start](#-quick-start) • [📚 API Reference](#-api-reference) • [🤝 Contributing](#-contributing) --- -## 🚀 Live Demo +## 🔥 Core Concept: _"Pre-Rendering"_ -| Example | Link | What it shows | Link to Code | -| --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -| Interactive menu with render tracker | Main Demo↗ | Compare Zero‑UI vs. React side‑by‑side while toggling a menu. | Github | -| React benchmark (10 000 nested nodes) | React 10k↗ | How long the traditional React render path takes. | Github | -| Zero‑UI benchmark (10 000 nested nodes) | Zero‑UI 10k↗ | Identical DOM, but powered by Zero‑UI's `data-*` switch. | Github | +Why re-render UI if all states are known at build time? +React Zero-UI **pre-renders** UI states once - at no runtime cost - and flips `data-*` attributes to update. That's it. ---- +```tsx +const [, setTheme] = useUI('theme', 'dark'); -## 🧐 Why Zero‑UI? +// Flip theme to "light" +setTheme('light'); // data-theme="light" on body +``` -Every `setState` in React triggers the full VDOM → Diff → Reconciliation → Paint pipeline. For _pure UI state_ (themes, menus, toggles) that work is wasted. +Tailwind usage: -**Zero‑UI introduces "_PRE‑rendering_":** +```html +
Fast & Reactive
+``` -1. Tailwind variants for every state are **generated at build‑time**. -2. The app **pre‑renders once**. -3. Runtime state changes only **flip a `data-*` attribute on ``**. +--- -Result → **5-10× faster visual updates** with **ZERO additional bundle cost**. +## 🚀 How it Works (Build-Time Magic) -### 📊 Micro‑benchmarks (Apple M1) +React Zero-UI uses a hyper-optimized AST resolver in development that scans your codebase for: -| Nodes updated | React state | Zero‑UI | Speed‑up | -| ------------- | ----------- | ------- | -------- | -| 10,000 | \~50 ms | \~5 ms | **10×** | -| 25,000 | \~180 ms | \~15 ms | **12×** | -| 50,000 | \~300 ms | \~20 ms | **15×** | +- `useUI` and `useScopedUI` hook usage +- Any variables resolving to strings (e.g., `'theme'`, `'modal-open'`) +- Tailwind variant classes (e.g., `theme-dark:bg-black`) -Re‑run these numbers yourself via the links above. +This generates: + +- Optimal CSS with global or scoped variant selectors +- Initial `data-*` attributes injected onto `` (zero FOUC) +- UI state with ease, no prop-drilling +- **Zero runtime overhead in production** --- -## ⚡️ Quick Start +## 🚀 Quick Start -> **Prerequisite:** Tailwind CSS v4 must already be initialized in your project. +**Requires:** Vite or Next.js (App Router) ```bash -# Inside an existing *Next.js (App Router)* or *Vite* repo npx create-zero-ui ``` -That's it — the CLI patch‑installs the required Babel & PostCSS plugins and updates `configs` for you. - -### Manual Install - -```bash -npm install @react-zero-ui/core -``` +Manual config: -Then follow **Setup →** for your bundler. +- [Next.js Setup](/docs/installation-next.md) +- [Vite Setup](/docs/installation-vite.md) --- -## 🔧 Setup - -### Vite +## 📚 API Reference -```js -// vite.config.* -import { zeroUIPlugin } from '@react-zero-ui/core/vite'; +### Basic Hook Signature -export default { - // ❗️Remove the default `tailwindcss()` plugin — Zero‑UI extends it internally - plugins: [zeroUIPlugin()], -}; +```tsx +const [staleValue, setValue] = useUI('key', 'value'); ``` -### Next.js (App Router) +- `key` ➡️ becomes `data-key` on `` +- `value` ➡️ default SSR value +- `staleValue` ➡️ SSR fallback (doesn't update after mount) -1. **Spread `bodyAttributes` on ``** in your root layout. +--- - ```tsx - // app/layout.tsx - import { bodyAttributes } from '@react-zero-ui/core/attributes'; - // or: import { bodyAttributes } from '../.zero-ui/attributes'; +### 🔨 `useUI` – Global UI State - export default function RootLayout({ children }) { - return ( - - {children} - - ); - } - ``` +```tsx +import { useUI } from '@react-zero-ui/core'; -2. **Add the PostCSS plugin (must come _before_ Tailwind).** +const [theme, setTheme] = useUI('theme', 'dark'); +``` - ```js - // postcss.config.js - module.exports = { plugins: { '@react-zero-ui/core/postcss': {}, tailwindcss: {} } }; - ``` +- Updates `data-theme` on `` +- No React re-renders +- Globally accessible with Tailwind --- -## 🏄 Usage +### 🎯 `useScopedUI` – Scoped UI State -![react zero ui usage explained](https://raw.githubusercontent.com/react-zero-ui/core/main/docs/assets/useui-explained.webp) +```tsx +import { useScopedUI } from '@react-zero-ui/core'; ---- +const [theme, setTheme] = useScopedUI('theme', 'dark'); -## 🛠 API +
+ Scoped UI Here +
; +``` -### `useUI(key, defaultValue)` +- Sets `data-*` on a specific DOM node +- Scoped Tailwind variants only apply inside that element +- Prevents FOUC, no re-renders -```ts -const [staleValue, setValue] = useUI<'open' | 'closed'>('sidebar', 'closed'); -``` +--- -- `key` → becomes `data-{key}` on ``. -- `defaultValue` → optional, prevents FOUC. -- **Note:** the returned `staleValue` does **not** update (`useUI` is write‑only). +### 🌈 CSS Variable Support -### Tailwind variants +Pass the `CssVar` flag for variable-based state: -```jsx -
-``` +```tsx +import { CssVar } from '@react-zero-ui/core'; -Any `data-{key}="{value}"` pair becomes a variant: `{key}-{value}:`. +const [blur, setBlur] = useUI('blur', '0px', CssVar); +setBlur('5px'); // body { --blur: 5px } +``` ---- +Scoped example: -## 🧬 How it works +```tsx +const [blur, setBlur] = useScopedUI('blur', '0px', CssVar); -1. **`useUI`** → writes to `data-*` attributes on ``. -2. **Babel plugin** → scans code, finds every `key/value`, injects them into **PostCSS**. -3. **PostCSS plugin** → generates static Tailwind classes **at build‑time**. -4. **Runtime** → changing state only touches the attribute — no VDOM, no reconciliation, no re‑paint. +
+ Scoped blur effect +
; +``` --- -## ✅ Features +## 🧪 Experimental Feature: `zeroOnClick` -- **Zero React re‑renders** for UI‑only state. -- **Global setters** — call from any component or util. -- **Tiny**: < 1 KB gzipped runtime. -- **TypeScript‑first**. -- **SSR‑friendly** (Next.js & Vite SSR). -- **Framework‑agnostic CSS** — generated classes work in plain HTML / Vue / Svelte as well. +Enables interactivity **inside Server Components** without useEffect. +Only ~300 bytes of runtime. + +Read more: [experimental.md](/docs/experimental.md) --- -## 🏗 Best Practices +## 📦 Summary of Benefits + +- 🚀 **Zero React re-renders** +- ⚡️ **Pre-rendered UI**: state embedded at build time +- 📦 **<350B runtime footprint** +- 💫 **Simple DX**: hooks + Tailwind variants +- ⚙️ **AST-powered**: cached fast builds -1. **UI state only** → themes, layout toggles, feature flags. -2. **Business logic stays in React** → fetching, data mutation, etc. -3. **Kebab‑case keys** → e.g. `sidebar-open`. -4. **Provide defaults** to avoid Flash‑Of‑Unstyled‑Content. +Zero re-renders. Zero runtime. Infinite scalability. --- -## 📜 License +## 🤝 Contributing + +We welcome all contributions! -[MIT](LICENSE) © Austin Serb +- 🐛 [Open an issue](https://github.com/react-zero-ui/core/issues) +- 💡 [Start a discussion](https://github.com/react-zero-ui/core/discussions) +- 🔧 [Read the contributing guide](/docs/CONTRIBUTING.md) --- -Built with ❤️ for the React community. If Zero‑UI makes your app feel ZERO fast, please ⭐️ the repo! +Made with ❤️ for the React community by [@austin1serb](https://github.com/austin1serb) diff --git a/packages/core/__tests__/fixtures/next/app/CssVarDemo.tsx b/packages/core/__tests__/fixtures/next/app/CssVarDemo.tsx index 01e3808..edd816b 100644 --- a/packages/core/__tests__/fixtures/next/app/CssVarDemo.tsx +++ b/packages/core/__tests__/fixtures/next/app/CssVarDemo.tsx @@ -13,7 +13,7 @@ export default function CssVarDemo({ index = 0 }) { // 👇 pass `cssVar` flag to switch makeSetter into CSS-var mode const [blur, setBlur] = useScopedUI<'0px' | '4px'>('blur', '0px', cssVar); // global test - return ( + return (
('scope', 'off'); - // #2 No ref at all → missingRef error + // #2 No ref at all ➡️ missingRef error const [, setDialog] = useScopedUI<'open' | 'closed'>('dialog', 'closed'); return ( diff --git a/packages/core/__tests__/fixtures/next/app/page.tsx b/packages/core/__tests__/fixtures/next/app/page.tsx index 49e658a..0f686dc 100644 --- a/packages/core/__tests__/fixtures/next/app/page.tsx +++ b/packages/core/__tests__/fixtures/next/app/page.tsx @@ -5,10 +5,10 @@ import FAQ from './FAQ'; import { ChildComponent } from './ChildComponent'; import { ChildWithoutSetter } from './ChildWithoutSetter'; import CssVarDemo from './CssVarDemo'; - + import { zeroSSR } from '@react-zero-ui/core/experimental'; + import ZeroUiRuntime from './zero-runtime'; - export default function Page() { const [scope, setScope] = useScopedUI<'off' | 'on'>('scope', 'off'); @@ -25,7 +25,6 @@ export default function Page() { const [, setToggleFunction] = useUI<'white' | 'black'>('toggle-function', 'white'); const [, setGlobal] = useUI<'0px' | '4px'>('blur-global', '0px', cssVar); - const toggleFunction = () => { setToggleFunction((prev) => (prev === 'white' ? 'black' : 'white')); }; diff --git a/packages/core/__tests__/fixtures/vite/src/ChildComponent.tsx b/packages/core/__tests__/fixtures/vite/src/ChildComponent.tsx index 00d9d46..2e87ce0 100644 --- a/packages/core/__tests__/fixtures/vite/src/ChildComponent.tsx +++ b/packages/core/__tests__/fixtures/vite/src/ChildComponent.tsx @@ -1,6 +1,6 @@ -import { type UISetterFn } from '@react-zero-ui/core'; +import { type GlobalSetterFn } from '@react-zero-ui/core'; -export function ChildComponent({ setIsOpen }: { setIsOpen: UISetterFn<'open' | 'closed'> }) { +export function ChildComponent({ setIsOpen }: { setIsOpen: GlobalSetterFn<'open' | 'closed'> }) { return (
{ + // Get the directory of this helper file + const __dirname = dirname(fileURLToPath(import.meta.url)); + console.log('__dirname: ', __dirname); + + // Build the path to the CLI module - from helpers/ go up to core/ then to dist/ + const modulePath = path.resolve(__dirname, '../../dist/cli/init.js'); + console.log('[Global Setup] CLI path:', modulePath); + + // Return a wrapper function that runs CLI as separate process to avoid module loading issues + const wrappedCli = async () => { const originalCwd = process.cwd(); try { process.chdir(fixtureDir); // Change to fixture directory + console.log('[Global Setup] Changed to fixture directory:', fixtureDir); - // The init.js exports a cli function, so call it + // Run the CLI as a separate Node.js process to avoid module loading conflicts + const result = execSync(`node "${modulePath}"`, { stdio: 'pipe', encoding: 'utf-8', timeout: 30000 }); - if (typeof mod === 'function') { - return await Promise.resolve(mod(args)); // run the CLI - } else if (typeof mod.default === 'function') { - return await Promise.resolve(mod.default(args)); // run the CLI (ESM default export) - } else { - throw new Error('Could not find CLI function in init.js'); - } + console.log('[Global Setup] CLI executed successfully'); + return result; + } catch (error) { + console.error('[Global Setup] CLI execution failed:', error.message); + if (error.stdout) console.log('STDOUT:', error.stdout); + if (error.stderr) console.log('STDERR:', error.stderr); + throw error; } finally { process.chdir(originalCwd); // Always restore original directory console.log('[Global Setup] Restored original directory:', originalCwd); diff --git a/packages/core/__tests__/helpers/overwriteFile.js b/packages/core/__tests__/helpers/overwriteFile.js index 152fd4c..99a61b8 100644 --- a/packages/core/__tests__/helpers/overwriteFile.js +++ b/packages/core/__tests__/helpers/overwriteFile.js @@ -8,7 +8,7 @@ import fs from 'fs'; */ export async function overwriteFile(filePath, content) { if (!fs.existsSync(filePath)) { - console.warn(`[Reset] ⚠️ File not found: ${filePath} — skipping overwrite.`); + console.warn(`[Reset] ⚠️ File not found: ${filePath} - skipping overwrite.`); return; } diff --git a/packages/core/__tests__/helpers/resetProjectState.js b/packages/core/__tests__/helpers/resetProjectState.js index 8ede516..aa1f6fb 100644 --- a/packages/core/__tests__/helpers/resetProjectState.js +++ b/packages/core/__tests__/helpers/resetProjectState.js @@ -8,8 +8,8 @@ import { overwriteFile } from './overwriteFile.js'; * Reset everything the Zero-UI CLI generates inside a fixture. * * @param projectDir absolute path to the fixture root - * @param isNext true → Next.js fixture (tsconfig + postcss) - * false → Vite fixture (vite.config.ts) + * @param isNext true ➡️ Next.js fixture (tsconfig + postcss) + * false ➡️ Vite fixture (vite.config.ts) */ export async function resetZeroUiState(projectDir, isNext = false) { console.log(`[Reset] Starting Zero-UI state reset for ${isNext ? 'Next.js' : 'Vite'} project`); diff --git a/packages/core/__tests__/unit/fixtures/test-components.jsx b/packages/core/__tests__/unit/fixtures/test-components.jsx deleted file mode 100644 index eb812e1..0000000 --- a/packages/core/__tests__/unit/fixtures/test-components.jsx +++ /dev/null @@ -1,14 +0,0 @@ -/* eslint-disable import/no-unresolved */ -import { THEME, MENU_SIZES, VARS } from './variables'; - -export function ComponentImports() { - const [, setTheme] = useUI(VARS, THEME); - const [, setSize] = useUI('size', MENU_SIZES.medium); - - return ( -
- - -
- ); -} diff --git a/packages/core/__tests__/unit/fixtures/ts-test-components.tsx b/packages/core/__tests__/unit/fixtures/ts-test-components.tsx deleted file mode 100644 index 290116e..0000000 --- a/packages/core/__tests__/unit/fixtures/ts-test-components.tsx +++ /dev/null @@ -1,88 +0,0 @@ -/* eslint-disable import/no-unresolved */ - -// @ts-ignore -import { useUI } from '@zero-ui/core'; - -/*───────────────────────────────────────────┐ -│ Top-level local constants (legal sources) │ -└───────────────────────────────────────────*/ -const DARK = 'dark' as const; -const PREFIX = `th-${DARK}` as const; -const SIZES = { small: 'sm', large: 'lg' } as const; -const MODES = ['auto', 'manual'] as const; - -const COLORS = { primary: 'blue', secondary: 'green' } as const; -const VARIANTS = { dark: `th-${DARK}`, light: COLORS.primary } as const; - -const isMobile = false; - -/*───────────────────────────────────────────┐ -│ Component covering every legal pattern │ -└───────────────────────────────────────────*/ -export function AllPatternsComponent() { - /* ① literal */ - const [theme, setTheme] = useUI('theme', 'light'); - /* ② identifier */ - const [altTheme, setAltTheme] = useUI('altTheme', DARK); - /* ③ static template literal */ - const [variant, setVariant] = useUI('variant', PREFIX); - /* ④ object-member */ - const [size, setSize] = useUI('size', SIZES.large); - /* ⑤ array-index */ - const [mode, setMode] = useUI('mode', MODES[0]); - /* ⑥ nested template + member */ - const [color, setColor] = useUI('color', `bg-${COLORS.primary}`); - /* ⑦ object-member */ - const [variant2, setVariant2] = useUI('variant', VARIANTS.dark); - /* ⑧ nested template + member */ - const [variant3, setVariant3] = useUI('variant', `th-${VARIANTS.light}`); - /* ⑨ BinaryExpression (template + member) */ - const [variant4, setVariant4] = useUI('variant', `th-${VARIANTS.light + '-inverse'}`); - /* ⑩ BinaryExpression (member + template) */ - const [variant5, setVariant5] = useUI('variant', `${VARIANTS.light}-inverse`); - /* ⑪ BinaryExpression (member + member) */ - const [variant6, setVariant6] = useUI('variant', `${VARIANTS.light}-${VARIANTS.dark}`); - /* ⑫ BinaryExpression (template + member) */ - const [variant7, setVariant7] = useUI('variant', `th-${VARIANTS.light}-${VARIANTS.dark}`); - /* ⑬ Optional-chaining w/ unresolvable member should pick th-light */ - // @ts-ignore - const [variant8, setVariant8] = useUI('variant', VARIANTS?.light.d ?? 'th-light'); - /* ⑭ nullish-coalesce */ - const [variant9, setVariant9] = useUI('variant', VARIANTS.light ?? 'th-light'); - - /* ── setters exercised in every allowed style ── */ - const clickHandler = () => { - /* direct literals */ - setTheme('dark'); - - /* identifier */ - setSize(SIZES.small); - - /* template literal */ - setVariant(`th-${DARK}-inverse`); - - /* member expression */ - setColor(COLORS.secondary); - - /* array index */ - setMode(MODES[1]); - - setVariant9(isMobile ? VARIANTS.light : 'th-light'); - }; - - /* conditional toggle with prev-state */ - const toggleAlt = () => setAltTheme((prev: string) => (prev === 'dark' ? 'light' : 'dark')); - - /* logical expression setter */ - useEffect(() => { - mode === 'auto' && setMode(MODES[1]); - }, [mode]); - - return ( -
- - -
{JSON.stringify({ theme, altTheme, variant, size, mode, color }, null, 2)}
-
- ); -} diff --git a/packages/core/__tests__/unit/fixtures/variables.js b/packages/core/__tests__/unit/fixtures/variables.js deleted file mode 100644 index b87369d..0000000 --- a/packages/core/__tests__/unit/fixtures/variables.js +++ /dev/null @@ -1,5 +0,0 @@ -export const THEME = 'dark'; - -export const MENU_SIZES = { small: 'sm', medium: 'md', large: 'lg' }; - -export const VARS = 'theme'; diff --git a/packages/core/package.json b/packages/core/package.json index 466b6ed..11dcdd7 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,22 +1,49 @@ { "name": "@react-zero-ui/core", - "version": "0.3.1-beta.2", - "description": "Zero re-render, global UI state management for React", + "version": "0.3.3", "private": false, - "type": "module", - "main": "./dist/index.js", - "module": "./dist/index.js", - "types": "./dist/index.d.ts", + "description": "Ultra-fast React UI state library with zero runtime, zero re-renders, Tailwind variant support, and automatic data-attribute/css-vars based styling. Replace context, prop drilling, and global stores with build-time magic.", + "keywords": [ + "react", + "react state", + "ui state", + "global state", + "scoped state", + "state management", + "tailwind", + "tailwind variants", + "postcss plugin", + "fastest ui updates", + "zero rerenders", + "zero render", + "no context", + "no prop drilling", + "css driven state", + "data attributes", + "ssr safe", + "instant ui updates", + "react optimization", + "high performance react" + ], + "homepage": "https://github.com/react-zero-ui/core#readme", + "bugs": { + "url": "https://github.com/react-zero-ui/core/issues" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/react-zero-ui/core.git", + "directory": "packages/core" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/austin1serb" + }, + "license": "MIT", + "author": "Austinserb ", "sideEffects": [ "./dist/experimental/runtime.js" ], - "files": [ - "dist/**/*", - "README.md", - "LICENSE", - "!*.test.js", - "!*.test.cjs" - ], + "type": "module", "exports": { ".": { "types": "./dist/index.d.ts", @@ -32,7 +59,6 @@ }, "./cli": { "types": "./dist/cli/init.d.ts", - "require": "./dist/cli/init.js", "import": "./dist/cli/init.js" }, "./experimental": { @@ -44,57 +70,33 @@ "import": "./dist/experimental/runtime.js" } }, + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "files": [ + "dist/**/*", + "README.md", + "LICENSE", + "!*.test.js", + "!*.test.cjs" + ], "scripts": { - "prepack": "pnpm run build", - "smoke": "node scripts/smoke-test.js", "build": "rm -rf dist && tsc -p tsconfig.build.json", "dev": "tsc -p tsconfig.json --watch", - "test:next": "playwright test -c __tests__/config/playwright.next.config.js", - "test:vite": "playwright test -c __tests__/config/playwright.vite.config.js", - "test:integration": "node --test __tests__/unit/index.test.cjs", - "test:cli": "node --test __tests__/unit/*.test.cjs", + "prepack": "pnpm run build", + "smoke": "node scripts/smoke-test.js", "test:all": "pnpm run test:vite && pnpm run test:next && pnpm run test:unit && pnpm run test:cli && pnpm run test:integration", - "test:unit": "tsx --test src/**/*.test.ts" - }, - "keywords": [ - "react", - "ui", - "state", - "css", - "postcss", - "postcss-plugin", - "zero-config", - "react-zero-ui", - "postcss-react-zero-ui", - "pre-rendering", - "no-rerender", - "zero-ui" - ], - "author": "Austinserb ", - "license": "MIT", - "repository": { - "type": "git", - "url": "git+https://github.com/react-zero-ui/core.git", - "directory": "packages/core" - }, - "bugs": { - "url": "https://github.com/react-zero-ui/core/issues" - }, - "homepage": "https://github.com/react-zero-ui/core#readme", - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "@tailwindcss/postcss": "^4.1.10", - "react": ">=16.8.0", - "tailwindcss": "^4.1.10", - "postcss": "^8.5.5" + "test:cli": "node --test __tests__/unit/*.test.cjs", + "test:integration": "node --test __tests__/unit/index.test.cjs", + "test:next": "playwright test -c __tests__/config/playwright.next.config.js", + "test:unit": "tsx --test src/**/*.test.ts", + "test:vite": "playwright test -c __tests__/config/playwright.vite.config.js" }, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", - "@babel/traverse": "^7.28.0", "@babel/parser": "^7.28.0", + "@babel/traverse": "^7.28.0", "@babel/types": "^7.28.0", "fast-glob": "^3.3.3", "lru-cache": "^11.1.0" @@ -105,6 +107,14 @@ "@types/babel__generator": "^7.27.0", "@types/babel__traverse": "^7.20.7", "@types/react": "^19.1.8", + "postcss": "^8.5.6", "tsx": "^4.20.3" + }, + "peerDependencies": { + "@tailwindcss/postcss": "^4.1.10", + "react": ">=16.8.0" + }, + "engines": { + "node": ">=18.0.0" } } \ No newline at end of file diff --git a/packages/core/src/cli/init.ts b/packages/core/src/cli/init.ts index a26bf9a..e1aa1fb 100755 --- a/packages/core/src/cli/init.ts +++ b/packages/core/src/cli/init.ts @@ -10,13 +10,14 @@ async function cli() { return await runZeroUiInit(); } -/* -------- CL I -------- */ -if (require.main === module) { +/* -------- CLI -------- */ +// ES module equivalent of require.main === module +if (import.meta.url === `file://${process.argv[1]}`) { cli().catch((error) => { console.error('CLI failed:', error); process.exit(1); }); } -/* -------- CJS -------- */ -module.exports = cli; // `require('@…/cli')()` +/* -------- ES Module Export -------- */ +export default cli; diff --git a/packages/core/src/experimental/README.md b/packages/core/src/experimental/README.md index 3e5f869..a590d49 100644 --- a/packages/core/src/experimental/README.md +++ b/packages/core/src/experimental/README.md @@ -15,9 +15,8 @@ This is the core runtime entrypoint. When called: 2. **Listens for clicks** on any element (or ancestor) with a `data-ui` attribute. 3. **Parses the `data-ui` directive** with this format: - - * `data-ui="global:key(val1,val2,...)"` → flips `data-key` on `document.body` - * `data-ui="scoped:key(val1,val2,...)"` → flips `data-key` on closest matching ancestor or self + - `data-ui="global:key(val1,val2,...)"` ➡️ flips `data-key` on `document.body` + - `data-ui="scoped:key(val1,val2,...)"` ➡️ flips `data-key` on closest matching ancestor or self 4. **Cycles the value** of the matching `data-*` attribute in a round-robin fashion. @@ -45,17 +44,17 @@ or **In development**, they also perform validation: -* Ensures the key is kebab-case. -* Ensures at least one value is provided. +- Ensures the key is kebab-case. +- Ensures at least one value is provided. --- ## 🧠 Design Notes -* **No React state or re-renders** involved. -* Works entirely via DOM `data-*` mutations. -* Compatible with all server components. -* Fully tree-shakable and side-effect-free unless `activateZeroUiRuntime()` is called. +- **No React state or re-renders** involved. +- Works entirely via DOM `data-*` mutations. +- Compatible with all server components. +- Fully tree-shakable and side-effect-free unless `activateZeroUiRuntime()` is called. This design makes it ideal for pairing with Tailwind-style conditional classes in static components. @@ -63,8 +62,8 @@ This design makes it ideal for pairing with Tailwind-style conditional classes i ## 🧼 Summary -* `activateZeroUiRuntime()` → enables click handling on static components via `data-ui` -* `zeroSSR` / `scopedZeroSSR` → emit valid click handlers as JSX props -* No state. No runtime overhead. Works in server components. +- `activateZeroUiRuntime()` ➡️ enables click handling on static components via `data-ui` +- `zeroSSR` / `scopedZeroSSR` ➡️ emit valid click handlers as JSX props +- No state. No runtime overhead. Works in server components. This runtime is the bridge between **static HTML** and **interactive UX**, while keeping everything **server-rendered** and blazing fast. diff --git a/packages/core/src/experimental/runtime.ts b/packages/core/src/experimental/runtime.ts index a156ad1..5735266 100644 --- a/packages/core/src/experimental/runtime.ts +++ b/packages/core/src/experimental/runtime.ts @@ -1,4 +1,4 @@ -/* ------------------------------------------------------------------ * +/* --- * * Zero-UI click-handler runtime * * * * Listens for clicks on any element that carries a `data-ui` * @@ -11,12 +11,12 @@ * A single `activateZeroUiRuntime()` call wires everything up. * * We guard against duplicate activation in case the component * * appears twice. * - * ------------------------------------------------------------------ */ + * --- */ -/** Map emitted by the compiler: every legal data-* key → true */ +/** Map emitted by the compiler: every legal data-* key ➡️ true */ export type VariantKeyMap = Record; -/* kebab → camel ("data-theme-dark" → "themeDark") */ +/* kebab ➡️ camel ("data-theme-dark" ➡️ "themeDark") */ const kebabToCamel = (attr: string) => attr.slice(5).replace(/-([a-z])/g, (_, c) => c.toUpperCase()); /* One shared RegExp - avoids per-click re-parsing */ diff --git a/packages/core/src/internal.ts b/packages/core/src/internal.ts index 1528ace..3e5b133 100644 --- a/packages/core/src/internal.ts +++ b/packages/core/src/internal.ts @@ -14,7 +14,7 @@ export function makeSetter(key: string, initialValue: T, getTa // enforce kebab-case for the key: lowercase letters, digits and single dashes if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(key)) { throw new Error( - `[Zero-UI] useUI(key, …); key must be kebab-case (e.g. "theme-dark"), got "${key}". ` + `Avoid camelCase or uppercase — they break variant generation.` + `[Zero-UI] useUI(key, …); key must be kebab-case (e.g. "theme-dark"), got "${key}". ` + `Avoid camelCase or uppercase - they break variant generation.` ); } diff --git a/packages/core/src/postcss/ast-generating.ts b/packages/core/src/postcss/ast-generating.ts index d41bfe3..06f3094 100644 --- a/packages/core/src/postcss/ast-generating.ts +++ b/packages/core/src/postcss/ast-generating.ts @@ -181,9 +181,9 @@ export function parseAndUpdateViteConfig(source: string, zeroUiImportPath: strin return modified ? generate(ast).code : null; } -/* ------------------------------------------------------------------ * +/* ------------ * * processConfigObject - mutate a { plugins: [...] } - * ------------------------------------------------------------------ */ + * ------------ */ function processConfigObject(obj: t.ObjectExpression): boolean { let touched = false; diff --git a/packages/core/src/postcss/ast-parsing.test.ts b/packages/core/src/postcss/ast-parsing.test.ts index ce8eeb7..89d8570 100644 --- a/packages/core/src/postcss/ast-parsing.test.ts +++ b/packages/core/src/postcss/ast-parsing.test.ts @@ -10,14 +10,16 @@ test('collectUseUIHooks should collect setters from a component', async () => { 'app/boolean-edge-cases.tsx': ` import { useUI } from '@react-zero-ui/core'; - const featureEnabled = 'feature-enabled'; + const feat = 'feature-enabled'; const bool = false; + const bool2 = true; + const feat2 = 'feature-enabled-2'; const theme = ['true']; export function Component() { const [isVisible, setIsVisible] = useUI<'modal-visible', 'false'>('modal-visible', 'false'); - const [isEnabled, setIsEnabled] = useUI<'feature-enabled', 'true'>(bool ?? featureEnabled, theme[0]); + const [isEnabled, setIsEnabled] = useUI<'feature-enabled', 'true'>(bool ?? feat, theme[0]); return (
{ `; const ast = parse(code, { sourceType: 'module', plugins: ['jsx', 'typescript'] }); const hooks = collectUseUIHooks(ast, code); - console.log('hooks: ', hooks); assert.equal(hooks.length, 2); assert.deepEqual( @@ -101,3 +102,39 @@ test('collectUseUIHooks handles + both hooks', async () => { ] ); }); + +test('collectUseUIHooks NumericLiterals bound to const identifiers', async () => { + const code = ` + import { useUI, useScopedUI } from '@react-zero-ui/core'; + const T = "true"; const M = { "true": "dark", "false": "light" }; const x = M[T] + export function Comp() { + const [, setThemeM] = useUI<'light' | 'dark'>('theme-m', x); + return
; + } + `; + const ast = parse(code, { sourceType: 'module', plugins: ['jsx', 'typescript'] }); + + assert.throws(() => { + collectUseUIHooks(ast, code); + }, /Only local, fully-static/i); +}); + +test('collectUseUIHooks should Resolve Logical Expressions &&', async () => { + const code = ` + import { useUI, useScopedUI } from '@react-zero-ui/core'; + + const bool2 = true; + const feat2 = 'feature-enabled-2'; + + export function Comp() { + const [isEnabled2, setIsEnabled2] = useUI<'feature-enabled-2', 'true'>(bool2 && feat2, 'dark'); + + } + `; + const ast = parse(code, { sourceType: 'module', plugins: ['jsx', 'typescript'] }); + const hooks = collectUseUIHooks(ast, code); + + assert.equal(hooks.length, 1); + assert.equal(hooks[0].stateKey, 'feature-enabled-2', 'stateKey should be feature-enabled-2'); + assert.equal(hooks[0].initialValue, 'dark', 'initialValue should be true'); +}); diff --git a/packages/core/src/postcss/ast-parsing.ts b/packages/core/src/postcss/ast-parsing.ts index cce68e4..530235c 100644 --- a/packages/core/src/postcss/ast-parsing.ts +++ b/packages/core/src/postcss/ast-parsing.ts @@ -19,7 +19,7 @@ const PARSE_OPTS = (f: string): Partial => ({ }); export interface HookMeta { - /** Babel binding object — use `binding.referencePaths` */ + /** Babel binding object - use `binding.referencePaths` */ // binding: Binding; /** Variable name (`setTheme`) */ setterFnName: string; @@ -41,8 +41,10 @@ export interface HookMeta { * reduced to a space-free string. */ const ALL_HOOK_NAMES = new Set([CONFIG.HOOK_NAME, CONFIG.LOCAL_HOOK_NAME]); +type HookName = typeof CONFIG.HOOK_NAME | typeof CONFIG.LOCAL_HOOK_NAME; const OBJ_NAMES = new Set([CONFIG.SSR_HOOK_NAME, CONFIG.SSR_HOOK_NAME_SCOPED]); +type LocalHookName = typeof CONFIG.SSR_HOOK_NAME | typeof CONFIG.SSR_HOOK_NAME_SCOPED; export function collectUseUIHooks(ast: t.File, sourceCode: string): HookMeta[] { const hooks: HookMeta[] = []; @@ -51,7 +53,7 @@ export function collectUseUIHooks(ast: t.File, sourceCode: string): HookMeta[] { const optsBase = { throwOnFail: true, source: sourceCode } as ResolveOpts; - function lit(node: t.Expression, p: NodePath, hook: ResolveOpts['hook']): string | null { + function resolveLiteralMemoized(node: t.Expression, p: NodePath, hook: ResolveOpts['hook']): string | null { if (memo.has(node)) return memo.get(node)!; // clone instead of mutate @@ -75,7 +77,7 @@ export function collectUseUIHooks(ast: t.File, sourceCode: string): HookMeta[] { if (!t.isArrayPattern(id) || !t.isCallExpression(init)) return; // b) callee must be one of our hook names - if (!(t.isIdentifier(init.callee) && ALL_HOOK_NAMES.has(init.callee.name as any))) return; + if (!(t.isIdentifier(init.callee) && ALL_HOOK_NAMES.has(init.callee.name as HookName))) return; if (id.elements.length !== 2) { throwCodeFrame(path, path.opts?.filename, sourceCode, `[Zero-UI] useUI() must destructure two values: [value, setterFn].`); @@ -90,29 +92,32 @@ export function collectUseUIHooks(ast: t.File, sourceCode: string): HookMeta[] { const [keyArg, initialArg] = init.arguments; // resolve state key with new helpers - const stateKey = lit(keyArg as t.Expression, path as NodePath, 'stateKey'); + const stateKey = resolveLiteralMemoized(keyArg as t.Expression, path as NodePath, 'stateKey'); if (stateKey === null) { throwCodeFrame( keyArg, path.opts?.filename, sourceCode, - // TODO add link to docs - `[Zero-UI] State key cannot be resolved at build-time.\n` + `Only local, fully-static strings are supported. - collectUseUIHooks-stateKey` + + `[Zero-UI] State key cannot be resolved at build-time.\n` + + `Only local, fully-static strings are supported. - collectUseUIHooks-stateKey` + + `\nSee: https://github.com/react-zero-ui/core/blob/main/docs/assets/internal.md` ); } // resolve initial value with helpers - const initialValue = lit(initialArg as t.Expression, path as NodePath, 'initialValue'); + const initialValue = resolveLiteralMemoized(initialArg as t.Expression, path as NodePath, 'initialValue'); if (initialValue === null) { throwCodeFrame( initialArg, path.opts?.filename, sourceCode, - // TODO add link to docs + `[Zero-UI] initial value cannot be resolved at build-time.\n` + - `Only local, fully-static objects/arrays are supported. - collectUseUIHooks-initialValue` + `Only local, fully-static objects/arrays are supported. - collectUseUIHooks-initialValue` + + `\nSee: https://github.com/react-zero-ui/core/blob/main/docs/assets/internal.md` ); } @@ -134,7 +139,7 @@ export function collectUseUIHooks(ast: t.File, sourceCode: string): HookMeta[] { if ( !t.isMemberExpression(callee) || !t.isIdentifier(callee.object) || - !OBJ_NAMES.has(callee.object.name as any) || + !OBJ_NAMES.has(callee.object.name as LocalHookName) || !t.isIdentifier(callee.property, { name: 'onClick' }) ) return; @@ -144,7 +149,7 @@ export function collectUseUIHooks(ast: t.File, sourceCode: string): HookMeta[] { const [keyArg, arrArg] = path.node.arguments; /* --- resolve key ------------------------------------------------ */ - const stateKey = lit(keyArg as t.Expression, path, 'stateKey'); + const stateKey = resolveLiteralMemoized(keyArg as t.Expression, path, 'stateKey'); if (stateKey === null) { throwCodeFrame(keyArg, path.opts?.filename, sourceCode, `[Zero-UI] zeroSSR.onClick("key"): key must be a fully-static string.`); } @@ -160,7 +165,7 @@ export function collectUseUIHooks(ast: t.File, sourceCode: string): HookMeta[] { } const values: string[] = []; for (const el of arrArg.elements) { - const v = lit(el as t.Expression, path, 'initialValue'); + const v = resolveLiteralMemoized(el as t.Expression, path, 'initialValue'); if (v === null) { throwCodeFrame(el!, path.opts?.filename, sourceCode, `[Zero-UI] zeroSSR.onClick("${stateKey}",[string]): array values must be static strings.`); } @@ -228,7 +233,7 @@ export interface ProcessVariantsResult { export async function processVariants(changedFiles: string[] | null = null): Promise { const srcFiles = changedFiles ?? findAllSourceFiles(); - /* Phase A — refresh hooks in cache (no token scan yet) */ + /* Phase A - refresh hooks in cache (no token scan yet) */ // Count the number of CPUs and use 1 less than that for concurrency const cpu = Math.max(os.cpus().length - 1, 1); @@ -254,11 +259,11 @@ export async function processVariants(changedFiles: string[] | null = null): Pro fileCache.set(fp, { hash: sig, hooks, tokens: new Map() }); }); - /* Phase B — build global key set */ + /* Phase B - build global key set */ const keySet = new Set(); for (const { hooks } of fileCache.values()) hooks.forEach((h) => keySet.add(h.stateKey)); - /* Phase C — ensure every cache entry has up-to-date tokens */ + /* Phase C - ensure every cache entry has up-to-date tokens */ for (const [fp, entry] of fileCache) { // Re-scan if tokens missing OR if keySet now contains keys we didn't scan for const needsRescan = entry.tokens.size === 0 || [...keySet].some((k) => !entry.tokens.has(k)); @@ -269,7 +274,7 @@ export async function processVariants(changedFiles: string[] | null = null): Pro entry.tokens = scanVariantTokens(code, keySet); } - /* Phase D — aggregate variant & initial-value maps */ + /* Phase D - aggregate variant & initial-value maps */ const variantMap = new Map>(); const initMap = new Map(); const scopeMap = new Map(); @@ -285,7 +290,7 @@ export async function processVariants(changedFiles: string[] | null = null): Pro initMap.set(h.stateKey, h.initialValue); } - /* scope aggregation — always run */ + /* scope aggregation - always run */ const prevScope = scopeMap.get(h.stateKey); if (prevScope && prevScope !== h.scope) { throw new Error(`[Zero-UI] Key "${h.stateKey}" used with both global and scoped hooks.`); @@ -293,14 +298,14 @@ export async function processVariants(changedFiles: string[] | null = null): Pro scopeMap.set(h.stateKey, h.scope); }); - // tokens → variantMap + // tokens ➡️ variantMap tokens.forEach((vals, k) => { if (!variantMap.has(k)) variantMap.set(k, new Set()); vals.forEach((v) => variantMap.get(k)!.add(v)); }); } - /* Phase E — final assembly */ + /* Phase E - final assembly */ const finalVariants: VariantData[] = [...variantMap] .map(([key, set]) => ({ key, values: [...set].sort(), initialValue: initMap.get(key) ?? null, scope: scopeMap.get(key)! })) .sort((a, b) => a.key.localeCompare(b.key)); diff --git a/packages/core/src/postcss/helpers.test.ts b/packages/core/src/postcss/helpers.test.ts index d78be79..a481bc2 100644 --- a/packages/core/src/postcss/helpers.test.ts +++ b/packages/core/src/postcss/helpers.test.ts @@ -62,7 +62,7 @@ test('buildCss emits @custom-variant blocks in stable order', () => { // test('generateAttributesFile writes files once and stays stable', async () => { // await runTest({}, async () => { // /* ------------------------------------------------------------------ * -// * 1. first call — files should be created +// * 1. first call - files should be created // * ------------------------------------------------------------------ */ // const first = await generateAttributesFile(expectedVariants, initialValues); // console.log('first: ', first); @@ -91,7 +91,7 @@ test('buildCss emits @custom-variant blocks in stable order', () => { // `; // assert.strictEqual(norm(tsText), norm(expectedTs), 'attributes.d.ts snapshot mismatch'); // /* ------------------------------------------------------------------ * -// * 2. second call — nothing should change +// * 2. second call - nothing should change // * ------------------------------------------------------------------ */ // const second = await generateAttributesFile(expectedVariants, initialValues); // console.log('second: ', second); diff --git a/packages/core/src/postcss/helpers.ts b/packages/core/src/postcss/helpers.ts index c4da87e..5b55dc7 100644 --- a/packages/core/src/postcss/helpers.ts +++ b/packages/core/src/postcss/helpers.ts @@ -141,7 +141,7 @@ export async function patchTsConfig(): Promise { const configFile = fs.existsSync(path.join(cwd, 'tsconfig.json')) ? 'tsconfig.json' : fs.existsSync(path.join(cwd, 'jsconfig.json')) ? 'jsconfig.json' : null; - // Ignore Vite fixtures — they patch their own config + // Ignore Vite fixtures - they patch their own config const hasViteConfig = ['js', 'mjs', 'ts', 'mts'].some((ext) => fs.existsSync(path.join(cwd, `vite.config.${ext}`))); if (hasViteConfig) { console.log('[Zero-UI] Vite config found, skipping tsconfig patch'); diff --git a/packages/core/src/postcss/index.cts b/packages/core/src/postcss/index.cts index 72ccd88..7636921 100644 --- a/packages/core/src/postcss/index.cts +++ b/packages/core/src/postcss/index.cts @@ -4,14 +4,15 @@ */ import { buildCss, generateAttributesFile, isZeroUiInitialized } from './helpers'; import { runZeroUiInit } from '../cli/postInstall.js'; -import type { PluginCreator, Root, Result } from 'postcss'; import { processVariants } from './ast-parsing'; import { CONFIG } from '../config'; -import { formatError, registerDeps } from './utilities.js'; +import { formatError, registerDeps, Result } from './utilities.js'; + +type Root = { prepend: (css: string) => void }; const zeroUIPlugin = CONFIG.PLUGIN_NAME; -const plugin: PluginCreator = () => { +const plugin = () => { return { postcssPlugin: zeroUIPlugin, async Once(root: Root, { result }: { result: Result }) { diff --git a/packages/core/src/postcss/resolvers.test.ts b/packages/core/src/postcss/resolvers.test.ts index 2019c37..5008c25 100644 --- a/packages/core/src/postcss/resolvers.test.ts +++ b/packages/core/src/postcss/resolvers.test.ts @@ -9,15 +9,18 @@ import traverse from './traverse.cjs'; /* Test Coverage: -1. literalFromNode (8 tests) -- String literals -- Template literals without expressions -- Binary string concatenation with + -- Logical OR expressions (||) -- Nullish coalescing (??) -- Identifiers bound to const -- Template literals with expressions -- Non-literal expressions (returns null) +1. literalFromNode + + LogicalExpressions + ConditionalExpression + BinaryExpression + UnaryExpression + StringLiteral + TemplateLiteral + Identifier + MemberExpression + UnaryExpression + 2. resolveLocalConstIdentifier (6 tests) - Const string literals - Const template literals @@ -40,6 +43,8 @@ Test Coverage: - Optional member expressions (THEMES?.dark) - Computed property with const variable - TypeScript as const assertions + + */ // Helper to find a specific expression node @@ -74,6 +79,145 @@ test('literalFromNode should resolve string literals', async () => { }); }); +test('literalFromNode should resolve UnaryExpression that results in a string', async () => { + await runTest({}, async () => { + const code = `const x = typeof "hello";`; + const found = findExpression( + code, + (n) => t.isUnaryExpression(n) && n.operator === 'typeof' && t.isStringLiteral(n.argument) && n.argument.value === 'hello' + ); + assert(found); + + const opts: ResolveOpts = { throwOnFail: true, source: code }; + const result = literalFromNode(found.node, found.path, opts); + assert.strictEqual(result, 'string'); + }); +}); + +test('literalFromNode should resolve UnaryExpression coerced in TemplateLiteral', async () => { + await runTest({}, async () => { + const code = 'const x = `${!true}`;'; + const found = findExpression( + code, + (n) => + t.isTemplateLiteral(n) && + n.expressions.length === 1 && + t.isUnaryExpression(n.expressions[0]) && + n.expressions[0].operator === '!' && + t.isBooleanLiteral(n.expressions[0].argument) && + n.expressions[0].argument.value === true + ); + assert(found); + + const opts: ResolveOpts = { throwOnFail: true, source: code }; + const result = literalFromNode(found.node, found.path, opts); + assert.strictEqual(result, 'false'); + }); +}); + +test('literalFromNode should resolve !false inside TemplateLiteral', async () => { + await runTest({}, async () => { + const code = 'const x = `flag is: ${!false}`;'; + const found = findExpression( + code, + (n) => + t.isTemplateLiteral(n) && + n.expressions.length === 1 && + t.isUnaryExpression(n.expressions[0]) && + n.expressions[0].operator === '!' && + t.isBooleanLiteral(n.expressions[0].argument) && + n.expressions[0].argument.value === false + ); + assert(found); + + const opts: ResolveOpts = { throwOnFail: true, source: code }; + const result = literalFromNode(found.node, found.path, opts); + assert.strictEqual(result, 'flag is: true'); + }); +}); + +test('literalFromNode should resolve multiple UnaryExpressions inside TemplateLiteral', async () => { + await runTest({}, async () => { + const code = 'const x = `${+true}${-2}${typeof null}`;'; + const found = findExpression( + code, + (n) => + t.isTemplateLiteral(n) && + n.expressions.length === 3 && + t.isUnaryExpression(n.expressions[0]) && + t.isUnaryExpression(n.expressions[1]) && + t.isUnaryExpression(n.expressions[2]) + ); + assert(found); + + const opts: ResolveOpts = { throwOnFail: true, source: code }; + const result = literalFromNode(found.node, found.path, opts); + assert.strictEqual(result, '1-2object'); + }); +}); + +test('literalFromNode should resolve typeof null inside TemplateLiteral', async () => { + await runTest({}, async () => { + const code = 'const x = `type: ${typeof null}`;'; + const found = findExpression( + code, + (n) => t.isTemplateLiteral(n) && n.expressions.length === 1 && t.isUnaryExpression(n.expressions[0]) && n.expressions[0].operator === 'typeof' + ); + assert(found); + + const opts: ResolveOpts = { throwOnFail: true, source: code }; + const result = literalFromNode(found.node, found.path, opts); + assert.strictEqual(result, 'type: object'); + }); +}); + +test('literalFromNode should resolve !someConst with local const', async () => { + await runTest({}, async () => { + const code = ` + const someConst = true; + const x = \`prefix-\${!someConst}\`; + `; + const found = findExpression( + code, + (n) => + t.isTemplateLiteral(n) && + n.expressions.length === 1 && + t.isUnaryExpression(n.expressions[0]) && + t.isIdentifier(n.expressions[0].argument) && + n.expressions[0].operator === '!' + ); + assert(found); + + const opts: ResolveOpts = { throwOnFail: true, source: code }; + const result = literalFromNode(found.node, found.path, opts); + assert.strictEqual(result, 'prefix-false'); + }); +}); + +test('literalFromNode should resolve UnaryExpressions to strings', async () => { + const cases = [ + { description: 'typeof "hello"', code: `const x = typeof "hello";`, expected: 'string' }, + { description: '+42 coerced to string', code: 'const x = `${+42}`;', expected: '42' }, + { description: '-5 coerced to string', code: 'const x = `${-5}`;', expected: '-5' }, + { description: '!false coerced to string', code: 'const x = `${!false}`;', expected: 'true' }, + { description: 'void 0 coerced to string', code: 'const x = `${void 0}`;', expected: 'undefined' }, + ]; + + await runTest({}, async () => { + for (const testCase of cases) { + const { code, expected, description } = testCase; + + const found = findExpression(code, (n) => t.isTemplateLiteral(n) || (t.isUnaryExpression(n) && ['typeof', '+', '-', '!', 'void'].includes(n.operator))); + assert(found, `Expected expression for: ${description}`); + + const opts: ResolveOpts = { throwOnFail: true, source: code }; + const result = literalFromNode(found.node as t.Expression, found.path, opts); + + assert.strictEqual(result, expected, `Failed: ${description}`); + } + }); +}); + test('literalFromNode should resolve template literals with no expressions', async () => { await runTest({}, async () => { const code = 'const x = `hello world`;'; @@ -86,6 +230,56 @@ test('literalFromNode should resolve template literals with no expressions', asy }); }); +test('literalFromNode should return null or throw on invalid UnaryExpressions', async () => { + const cases = [ + { description: 'typeof function call (dynamic)', code: `const x = typeof getValue();`, shouldThrow: false, expectedResult: null }, + { description: 'typeof runtime identifier (undeclared)', code: `const x = typeof runtimeValue;`, shouldThrow: false, expectedResult: null }, + { description: '+imported identifier (illegal)', code: `import { value } from './lib.js'; const x = \`\${+value}\`;`, shouldThrow: true }, + { description: 'Unary ! with non-const identifier', code: `let flag = true; const x = \`\${!flag}\`;`, shouldThrow: false, expectedResult: null }, + { description: 'typeof Symbol() (non-serializable)', code: `const x = \`\${typeof Symbol()}\`;`, shouldThrow: false, expectedResult: null }, + ]; + + await runTest({}, async () => { + for (const testCase of cases) { + const { code, description, shouldThrow } = testCase; + const found = findExpression(code, (n) => t.isTemplateLiteral(n) || (t.isUnaryExpression(n) && ['typeof', '+', '-', '!', 'void'].includes(n.operator))); + assert(found, `Expected expression for: ${description}`); + + const opts: ResolveOpts = { throwOnFail: shouldThrow, source: code }; + + let didThrow = false; + let result: string | null = null; + + try { + result = literalFromNode(found.node as t.Expression, found.path, opts); + } catch (e) { + didThrow = true; + } + + if (shouldThrow) { + assert(didThrow, `Expected to throw for: ${description}`); + } else { + assert.strictEqual(result, null, `Expected null for: ${description}`); + } + } + }); +}); + +// Conditional Expression +test('literalFromNode should handle ConditionalExpression', async () => { + await runTest({}, async () => { + const code = ` + const x = true ? "isTrue" : "isFalse"; + `; + const found = findExpression(code, (n) => t.isConditionalExpression(n)); + assert(found); + + const opts: ResolveOpts = { throwOnFail: true, source: code }; + const result = literalFromNode(found.node as t.ConditionalExpression, found.path, opts); + assert.strictEqual(result, 'isTrue'); + }); +}); + test('literalFromNode should resolve binary string concatenation', async () => { await runTest({}, async () => { const code = `const x = "hello" + " " + "world";`; @@ -98,18 +292,30 @@ test('literalFromNode should resolve binary string concatenation', async () => { }); }); -test('literalFromNode should resolve logical OR expressions', async () => { +test('literalFromNode should resolve various LogicalExpressions to strings', async () => { + const cases = [ + { description: 'OR: undefined || "default"', code: `const undef=undefined; const x = undef || "default";`, expected: 'default' }, + { description: 'OR: "primary" || "fallback"', code: `const x = "primary" || "fallback";`, expected: 'primary' }, + { description: 'OR: null || undefined || "final"', code: `const n=null; const undef=undefined; const x = n || undef || "final";`, expected: 'final' }, + { description: 'OR: null || fallback identifier', code: `const fallback = "default"; const x = null || fallback;`, expected: 'default' }, + { description: 'OR: null || fallback identifier', code: `const fallback = "default"; const x = null || fallback;`, expected: 'default' }, + { description: 'AND: "truthy" && "final"', code: `const x = "truthy" && "final";`, expected: 'final' }, + { description: 'Nullish: null ?? "default"', code: `const x = null ?? "default";`, expected: 'default' }, + { description: 'Nullish: "set" ?? "default"', code: `const x = "set" ?? "default";`, expected: 'set' }, + ]; + await runTest({}, async () => { - const code = ` - const fallback = "default"; - const x = undefined || fallback; - `; - const found = findExpression(code, (n) => t.isLogicalExpression(n) && n.operator === '||'); - assert(found); + for (const testCase of cases) { + const { code, expected, description } = testCase; - const opts: ResolveOpts = { throwOnFail: true, source: code }; - const result = literalFromNode(found.node, found.path, opts); - assert.strictEqual(result, 'default'); + const found = findExpression(code, (n) => t.isLogicalExpression(n)); + assert(found, `Expected to find LogicalExpression in: ${description}`); + + const opts: ResolveOpts = { throwOnFail: true, source: code }; + const result = literalFromNode(found.node, found.path, opts); + + assert.strictEqual(result, expected, `Failed: ${description}`); + } }); }); @@ -171,6 +377,32 @@ test('literalFromNode should return null for non-literal expressions', async () }); }); +test('literalFromNode should resolve ArrayExpression values via static index access', async () => { + const cases = [ + { description: 'array access with numeric index', code: `const COLORS = ["red", "green", "blue"]; const x = COLORS[1];`, expected: 'green' }, + { description: 'array access with numeric index', code: `const idx = 0; const COLORS = ["red", "green", "blue"]; const x = COLORS[idx];`, expected: 'red' }, + // { description: 'nested object in array access', code: `const THEMES = [{ name: "light" }, { name: "dark" }]; const x = THEMES[1].name;`, expected: 'dark' }, + // { description: 'template literal inside array', code: 'const VALUES = [`va${"lue"}`]; const x = VALUES[0];', expected: 'value' }, + // { description: 'computed numeric index from const', code: `const IDX = 2; const LIST = ["a", "b", 'c']; const x = LIST[IDX];`, expected: 'c' }, + // { description: 'array inside object', code: `const DATA = { values: ["a", "b", "c"] }; const x = DATA.values[0];`, expected: 'a' }, + ]; + + await runTest({}, async () => { + for (const testCase of cases) { + const { code, description, expected } = testCase; + + const found = findExpression(code, (n) => t.isMemberExpression(n) || t.isOptionalMemberExpression(n)); + assert(found, `Expected MemberExpression for: ${description}`); + + const opts: ResolveOpts = { throwOnFail: true, source: code }; + const result = literalFromNode(found.node as t.Expression, found.path, opts); + console.log('result: ', result); + + assert.strictEqual(result, expected, `Failed: ${description}`); + } + }); +}); + // Tests for resolveLocalConstIdentifier test('resolveLocalConstIdentifier should resolve const string literals', async () => { await runTest({}, async () => { @@ -214,7 +446,7 @@ test('resolveLocalConstIdentifier should return null for non-identifier', async }); }); -test('resolveLocalConstIdentifier should return null for let/var variables', async () => { +test('resolveLocalConstIdentifier should throw for let/var variables', async () => { await runTest({}, async () => { const code = ` let THEME = "dark"; @@ -224,8 +456,9 @@ test('resolveLocalConstIdentifier should return null for let/var variables', asy assert(found); const opts: ResolveOpts = { throwOnFail: true, source: code }; - const result = resolveLocalConstIdentifier(found.node, found.path, opts); - assert.strictEqual(result, null); + assert.throws(() => { + resolveLocalConstIdentifier(found.node, found.path, opts); + }, /Only top-level `const` variables are allowed./); }); }); @@ -320,146 +553,140 @@ test('resolveTemplateLiteral should throw for dynamic expressions', async () => }); // Tests for resolveMemberExpression -test('resolveMemberExpression should resolve simple object property', async () => { - await runTest({}, async () => { - const code = ` - const THEMES = { dark: "dark-theme", light: "light-theme" }; - const x = THEMES.dark; - `; - const found = findExpression(code, (n) => t.isMemberExpression(n)); - assert(found); - - const opts: ResolveOpts = { throwOnFail: true, source: code }; - const result = resolveMemberExpression(found.node as t.MemberExpression, found.path, literalFromNode, opts); - assert.strictEqual(result, 'dark-theme'); - }); -}); - -test('resolveMemberExpression should resolve computed property access', async () => { - await runTest({}, async () => { - const code = ` - const THEMES = { dark: "dark-theme", light: "light-theme" }; - const x = THEMES["dark"]; - `; - const found = findExpression(code, (n) => t.isMemberExpression(n) && n.computed); - assert(found); - const opts: ResolveOpts = { throwOnFail: true, source: code }; - const result = resolveMemberExpression(found.node as t.MemberExpression, found.path, literalFromNode, opts); - assert.strictEqual(result, 'dark-theme'); - }); -}); +test('resolveMemberExpression should handle valid and invalid member expressions', async () => { + const cases = [ + { + description: 'simple object property', + code: `const THEMES = { dark: "dark-theme", light: "light-theme" }; const x = THEMES.dark;`, + expected: 'dark-theme', + }, + { + description: 'computed property access', + code: `const THEMES = { dark: "dark-theme", light: "light-theme" }; const x = THEMES["dark"];`, + expected: 'dark-theme', + }, + { + description: 'nested object property', + code: `const THEMES = { brand: { primary: "blue", secondary: "green" } }; const x = THEMES.brand.primary;`, + expected: 'blue', + }, + { description: 'array access by index', code: `const COLORS = ["red", "green", "blue"]; const x = COLORS[1];`, expected: 'green' }, + { description: 'optional member expression', code: `const THEMES = { dark: "dark-theme" }; const x = THEMES?.dark;`, expected: 'dark-theme' }, + { + description: 'computed property using const identifier', + code: `const KEY = "dark"; const THEMES = { dark: "dark-theme" }; const x = THEMES[KEY];`, + expected: 'dark-theme', + }, + { description: 'TypeScript const assertion', code: `const THEMES = { dark: "dark-theme" } as const; const x = THEMES.dark;`, expected: 'dark-theme' }, + { + description: 'nonexistent property should throw', + code: `const THEMES = { dark: "dark-theme" }; const x = THEMES.nonexistent;`, + shouldThrow: /cannot be resolved at build-time/, + }, + { description: 'imported object should throw', code: `import { THEMES } from './constants'; const x = THEMES.dark;`, shouldThrow: /Imports Not Allowed/ }, + ]; -test('resolveMemberExpression should resolve nested object properties', async () => { await runTest({}, async () => { - const code = ` - const THEMES = { - brand: { - primary: "blue", - secondary: "green" - } - }; - const x = THEMES.brand.primary; - `; - const found = findExpression(code, (n) => t.isMemberExpression(n) && t.isMemberExpression(n.object)); - assert(found); - - const opts: ResolveOpts = { throwOnFail: true, source: code }; - const result = resolveMemberExpression(found.node as t.MemberExpression, found.path, literalFromNode, opts); - assert.strictEqual(result, 'blue'); + for (const testCase of cases) { + const { description, code, expected, shouldThrow } = testCase; + + const found = findExpression(code, (n) => t.isMemberExpression(n) || t.isOptionalMemberExpression(n)); + assert(found, `Expected member expression for: ${description}`); + + const opts: ResolveOpts = { throwOnFail: true, source: code }; + + if (shouldThrow) { + assert.throws( + () => { + resolveMemberExpression(found.node as any, found.path, literalFromNode, opts); + }, + shouldThrow, + `Expected error for: ${description}` + ); + } else { + const result = resolveMemberExpression(found.node as any, found.path, literalFromNode, opts); + assert.strictEqual(result, expected, `Failed: ${description}`); + } + } }); }); -test('resolveMemberExpression should resolve array access', async () => { - await runTest({}, async () => { - const code = ` - const COLORS = ["red", "green", "blue"]; - const x = COLORS[1]; - `; - const found = findExpression(code, (n) => t.isMemberExpression(n) && n.computed); - assert(found); - - const opts: ResolveOpts = { throwOnFail: true, source: code }; - const result = resolveMemberExpression(found.node as t.MemberExpression, found.path, literalFromNode, opts); - assert.strictEqual(result, 'green'); - }); -}); +test.skip('literalFromNode should resolve NumericLiterals bound to const identifiers', async () => { + const cases = [ + { description: 'const binding to numeric literal', code: `const IDX = 2; const x = IDX;`, expected: '2' }, + { description: 'numeric const as object key', code: `const idx = 1; const M = { "1": "yes", 2: "no" }; const x = M[idx];`, expected: 'yes' }, + { + description: 'rejected let-bound numeric literal', + code: `let IDX = 0; const LIST = ["a", "b"]; const x = LIST[IDX];`, + shouldThrow: /Only top-level `const` variables are allowed/, + }, + ]; -test('resolveMemberExpression should throw for non-existent properties', async () => { await runTest({}, async () => { - const code = ` - const THEMES = { dark: "dark-theme" }; - const x = THEMES.nonexistent; - `; - const found = findExpression(code, (n) => t.isMemberExpression(n)); - assert(found); - - const opts: ResolveOpts = { throwOnFail: true, source: code }; - assert.throws(() => { - resolveMemberExpression(found.node as t.MemberExpression, found.path, literalFromNode, opts); - }, /cannot be resolved at build-time/); + for (const testCase of cases) { + const { code, expected, shouldThrow, description } = testCase; + + const found = findExpression(code, (n) => t.isIdentifier(n) || t.isMemberExpression(n) || t.isTemplateLiteral(n)); + assert(found, `Expected expression for: ${description}`); + + const opts: ResolveOpts = { throwOnFail: true, source: code }; + + if (shouldThrow) { + assert.throws( + () => { + literalFromNode(found.node as t.Expression, found.path, opts); + }, + shouldThrow, + `Expected failure: ${description}` + ); + } else { + const result = literalFromNode(found.node as t.Expression, found.path, opts); + assert.strictEqual(result, expected, `Failed: ${description}`); + } + } }); }); -test('resolveMemberExpression should throw for imported objects', async () => { - await runTest({}, async () => { - const code = ` - import { THEMES } from './constants'; - const x = THEMES.dark; - `; - const found = findExpression(code, (n) => t.isMemberExpression(n)); - assert(found); - - const opts: ResolveOpts = { throwOnFail: true, source: code }; - assert.throws(() => { - resolveMemberExpression(found.node as t.MemberExpression, found.path, literalFromNode, opts); - }, /Imports Not Allowed/); - }); -}); +test.skip('literalFromNode should resolve NumericLiterals bound to const identifiers', async () => { + const cases = [ + { + description: 'object access with boolean identifier', + code: `const T = true; const M = { "true": "yes", "false": "no" }; const x = M[T];`, + expected: 'yes', + }, + // { description: 'boolean literal as key', code: `const x = { true: 'yes' }[true];`, expected: 'yes' }, + { description: 'boolean const used as key', code: `const FLAG = "false"; const x = { true: 'yes', false: 'no' }[FLAG];`, expected: 'no' }, + ]; -test('resolveMemberExpression should handle optional member expressions', async () => { await runTest({}, async () => { - const code = ` - const THEMES = { dark: "dark-theme" }; - const x = THEMES?.dark; - `; - const found = findExpression(code, (n) => t.isOptionalMemberExpression(n)); - assert(found); - - const opts: ResolveOpts = { throwOnFail: true, source: code }; - // Cast to MemberExpression since the function handles both - const result = resolveMemberExpression(found.node as any, found.path, literalFromNode, opts); - assert.strictEqual(result, 'dark-theme'); + for (const testCase of cases) { + const { code, expected, description } = testCase; + const found = findExpression(code, (n) => t.isIdentifier(n) || t.isMemberExpression(n) || t.isTemplateLiteral(n)); + assert(found, `Expected expression for: ${description}`); + const opts: ResolveOpts = { throwOnFail: true, source: code }; + + const result = literalFromNode(found.node as t.Expression, found.path, opts); + assert.strictEqual(result, expected, `Failed: ${description}`); + } }); }); -test('resolveMemberExpression should handle computed property with const variable', async () => { - await runTest({}, async () => { - const code = ` - const KEY = "dark"; - const THEMES = { dark: "dark-theme" }; - const x = THEMES[KEY]; - `; - const found = findExpression(code, (n) => t.isMemberExpression(n) && n.computed); - assert(found); - - const opts: ResolveOpts = { throwOnFail: true, source: code }; - const result = resolveMemberExpression(found.node as t.MemberExpression, found.path, literalFromNode, opts); - assert.strictEqual(result, 'dark-theme'); - }); -}); +test('literalFromNode should resolve SequenceExpression values', async () => { + const cases = [ + { description: 'sequence returns last string literal', code: `const doSomething = () => {}; const x = (doSomething(), "hello");`, expected: 'hello' }, + { description: 'sequence returns last numeric literal', code: `const doSomething = () => {}; const x = (doSomething(), "42");`, expected: '42' }, + ]; -test('resolveMemberExpression should handle TS as const assertions', async () => { await runTest({}, async () => { - const code = ` - const THEMES = { dark: "dark-theme" } as const; - const x = THEMES.dark; - `; - const found = findExpression(code, (n) => t.isMemberExpression(n)); - assert(found); - - const opts: ResolveOpts = { throwOnFail: true, source: code }; - const result = resolveMemberExpression(found.node as t.MemberExpression, found.path, literalFromNode, opts); - assert.strictEqual(result, 'dark-theme'); + for (const testCase of cases) { + const { code, expected, description } = testCase; + const found = findExpression(code, (n) => t.isSequenceExpression(n)); + assert(found, `Expected expression for: ${description}`); + const opts: ResolveOpts = { throwOnFail: true, source: code }; + + const result = literalFromNode(found.node as t.Expression, found.path, opts); + assert.strictEqual(result, expected, `Failed: ${description}`); + } }); }); diff --git a/packages/core/src/postcss/resolvers.ts b/packages/core/src/postcss/resolvers.ts index 0c61854..e3f483b 100644 --- a/packages/core/src/postcss/resolvers.ts +++ b/packages/core/src/postcss/resolvers.ts @@ -3,6 +3,8 @@ import * as t from '@babel/types'; import { NodePath } from '@babel/traverse'; import { throwCodeFrame } from './ast-parsing.js'; import { generate } from '@babel/generator'; + +const VERBOSE = false; export interface ResolveOpts { throwOnFail?: boolean; // default false source?: string; // optional; fall back to path.hub.file.code @@ -10,60 +12,148 @@ export interface ResolveOpts { } /** - * This function will decide which function to call based on the node type - * 1. String literal - * 2. Template literal with no expressions - * 3. Binary expression (a + b) - * 4. Logical expression (a || b, a ?? b) - * 5. Identifier bound to local const - * 6. Template literal with expressions - * 7. Member expression - * 8. Optional member expression - * 9. Everything else is illegal + * Higher up the call tree we verify with typescript that the node resolves to a string literal. and has no whitespace. + * We just have to resolve it at build time. + * + * This function will decide which function to call based on the node type (ALL RESOLVE TO STRINGS) + * StringLiteral + * TemplateLiteral (both static and dynamic expressions resolved recursively) + * Identifier (local const) + * BinaryExpression (+ operator) + * UnaryExpression (covers numeric/string coercions and logical negation explicitly) + * LogicalExpression (||, ??) + * ConditionalExpression (condition ? expr1 : expr2) + * ArrayExpression (["a", "b"][index]) + * NumericLiteral (coerced) + * MemberExpression (static, computed, nested objects/arrays) + * OptionalMemberExpression (a?.b) + * ObjectExpression (via MemberExpression chains) + * BooleanLiteral (handled explicitly by isBooleanLiteral) + SequenceExpression (already handled explicitly by taking last expression) + * @param node - The node to convert * @param path - The path to the node - * @returns The string literal or null if the node is not a string literal or template literal with no expressions or identifier bound to local const + * @returns - The string literal resolved or null */ export function literalFromNode(node: t.Expression, path: NodePath, opts: ResolveOpts): string | null { + // StringLiteral + if (t.isStringLiteral(node)) return node.value; + // NumericLiteral - convert numbers to strings + if (t.isNumericLiteral(node)) return String(node.value); + // BooleanLiteral returned as string + if (t.isBooleanLiteral(node)) return String(node.value); + // TemplateLiteral without ${} + if (t.isTemplateLiteral(node) && node.expressions.length === 0) return node.quasis[0].value.cooked ?? node.quasis[0].value.raw; + + VERBOSE && console.log('48 -> literalFromNode'); + /* ── Fast path via Babel constant-folder ───────────── */ const ev = fastEval(node, path); - if (ev.confident && typeof ev.value === 'string') return ev.value; - // String / template (no ${}) - if (t.isStringLiteral(node)) return node.value; - if (t.isTemplateLiteral(node) && node.expressions.length === 0) { - const text = node.quasis[0].value.cooked ?? node.quasis[0].value.raw; - return text; + if (ev.confident && typeof ev.value === 'string') { + containsIllegalIdentifiers(node, path, opts); // 👈 throws if invalid + return ev.value; + } + + VERBOSE && console.log('58 -> literalFromNode -> ev: '); + + // ConditionalExpression + if (t.isConditionalExpression(node)) { + const testResult = fastEval(node.test, path); + if (testResult.confident) { + const branch = testResult.value ? node.consequent : node.alternate; + return literalFromNode(branch as t.Expression, path, opts); + } + // If test isn't statically evaluable, return null + return null; } + + VERBOSE && console.log('70 -> literalFromNode'); + + // BinaryExpression with + operator if (t.isBinaryExpression(node) && node.operator === '+') { + // Resolve left const left = literalFromNode(node.left as t.Expression, path, opts); + // Resolve right const right = literalFromNode(node.right as t.Expression, path, opts); return left !== null && right !== null ? left + right : null; } + VERBOSE && console.log('82 -> literalFromNode'); + + // SequenceExpression (already handled explicitly by taking last expression) + if (t.isSequenceExpression(node)) { + const last = node.expressions.at(-1); + if (last) return literalFromNode(last, path, opts); + } + + VERBOSE && console.log('89 -> literalFromNode'); + + if (t.isUnaryExpression(node)) { + const arg = literalFromNode(node.argument as t.Expression, path, opts); + if (arg === null) return null; + + switch (node.operator) { + case 'typeof': + return typeof arg; + case '+': + return typeof arg === 'number' || !isNaN(Number(arg)) ? String(+arg) : null; + case '-': + return typeof arg === 'number' || !isNaN(Number(arg)) ? String(-arg) : null; + case '!': + return String(!arg); + case 'void': + return 'undefined'; + default: + return null; + } + } + + VERBOSE && console.log('112 -> literalFromNode'); + /* ── Logical fallback (a || b , a ?? b) ───────────── */ if (t.isLogicalExpression(node) && (node.operator === '||' || node.operator === '??')) { // try left; if it resolves, use it, otherwise fall back to right const left = literalFromNode(node.left as t.Expression, path, opts); - if (left !== null) return left; - return literalFromNode(node.right as t.Expression, path, opts); + if (left === 'true') return left; + if (left === 'false' || left === 'undefined' || left === 'null') { + return literalFromNode(node.right as t.Expression, path, opts); + } + } + if (t.isLogicalExpression(node) && node.operator === '&&') { + const left = literalFromNode(node.left as t.Expression, path, opts); + if (left === 'false' || left === 'undefined' || left === 'null') return null; + if (left === 'true') return literalFromNode(node.right as t.Expression, path, opts); + if (opts.throwOnFail) { + throwCodeFrame(path, path.opts?.filename, opts.source ?? path.opts?.source?.code, `[Zero-UI] Logical && expression could not be resolved at build time.`); + } } - // Identifier bound to local const (also handles object/array literals - // via the recursive call inside resolveLocalConstIdentifier) + VERBOSE && console.log('122 -> literalFromNode'); + + // "Is this node an Identifier?" + // "If yes, can I resolve it to a literal value like a string, number, or boolean?" const idLit = resolveLocalConstIdentifier(node, path, opts); - if (idLit !== null) return idLit; + VERBOSE && console.log('127 -> literalFromNode -> idLit: ', idLit); + if (idLit !== null) return String(idLit); + + VERBOSE && console.log('130 -> literalFromNode'); // Template literal with ${expr} or ${CONSTANT} if (t.isTemplateLiteral(node)) { + VERBOSE && console.log('135 -> literalFromNode -> template literal'); return resolveTemplateLiteral(node, path, literalFromNode, opts); } + VERBOSE && console.log('138 -> literalFromNode'); + if (t.isMemberExpression(node) || t.isOptionalMemberExpression(node)) { // treat optional-member exactly the same return resolveMemberExpression(node as t.MemberExpression, path, literalFromNode, opts); } + VERBOSE && console.log('END -> literalFromNode', node); + return null; } @@ -74,46 +164,40 @@ export function literalFromNode(node: t.Expression, path: NodePath, opts Returns {confident, value} or {confident: false} \*──────────────────────────────────────────────────────────*/ -export function fastEval(node: t.Expression, path: NodePath) { +export function fastEval(node: t.Expression, path: NodePath): { confident: boolean; value?: string } { // ❶ If the node *is* the current visitor path, we can evaluate directly. - if (node === path.node && (path as any).evaluate) { - return (path as any).evaluate(); // safe, returns {confident, value} + if (node === path.node && (path as NodePath).evaluate) { + return path.evaluate(); // safe, returns {confident, value} } // ❷ Otherwise try to locate a child-path that wraps `node`. // (Babel exposes .get() only for *named* keys, so we must scan.) for (const key of Object.keys(path.node)) { - const sub = (path as any).get?.(key); - if (sub?.node === node && sub.evaluate) { + const sub = (path as NodePath).get?.(key) as NodePath | undefined; + if (sub?.node === node && sub?.evaluate) { return sub.evaluate(); } } - // ❸ Give up → undefined (caller falls back to manual resolver) + // ❸ Give up ➡️ undefined (caller falls back to manual resolver) return { confident: false }; } /*──────────────────────────────────────────────────────────*\ - resolveLocalConstIdentifier - --------------------------- - Resolve an **Identifier** node to a *space-free string literal* **only when** + Resolve an **Identifier** node 1. It is bound in the **same file** (Program scope), 2. Declared with **`const`** (not `let` / `var`), - 3. Initialised to a **string literal** or a **static template literal**, - 4. The final string has **no whitespace** (`/^\S+$/`). + 3. Initialized to a **string literal** or a **static template literal**, Anything else (inner-scope `const`, dynamic value, imported binding, spaces) - ➜ return `null` — the caller will decide whether to throw or keep searching. + ➜ return `null` - the caller will decide whether to throw or keep searching. If the binding is *imported*, we delegate to `throwCodeFrame()` so the developer gets a consistent, actionable error message. \*──────────────────────────────────────────────────────────*/ -export function resolveLocalConstIdentifier( - node: t.Expression, // <- widened - path: NodePath, - opts: ResolveOpts -): string | null { +export function resolveLocalConstIdentifier(node: t.Expression, path: NodePath, opts: ResolveOpts): string | number | boolean | null { + VERBOSE && console.log('resolveLocalConstIdentifier -> 190'); /* Fast-exit when node isn't an Identifier */ if (!t.isIdentifier(node)) return null; @@ -143,6 +227,14 @@ export function resolveLocalConstIdentifier( /* 2. Allow only top-level `const` */ if (!binding.path.isVariableDeclarator() || binding.scope.block.type !== 'Program' || (binding.path.parent as t.VariableDeclaration).kind !== 'const') { + if ((binding.path.parent as t.VariableDeclaration).kind !== 'const') { + throwCodeFrame( + path, + path.opts?.filename, + opts.source ?? path.opts?.source?.code, + `[Zero-UI] Only top-level \`const\` variables are allowed. '${node.name}' is not valid.` + ); + } return null; } @@ -155,12 +247,17 @@ export function resolveLocalConstIdentifier( init = (init as any).expression; // step into the real value } - let text: string | null = null; + let text: string | number | boolean | null = null; if (t.isStringLiteral(init)) { text = init.value; } else if (t.isTemplateLiteral(init)) { text = resolveTemplateLiteral(init, binding.path, literalFromNode, opts); + } else if (t.isNumericLiteral(init)) { + const raw = String(init.value); + if (/^\S+$/.test(raw)) text = raw; + } else if (t.isBooleanLiteral(init)) { + text = init.value; // ➡️ 'true' or 'false' } return text; @@ -179,12 +276,12 @@ export function resolveLocalConstIdentifier( string literal **without spaces**. 3. If an expression's binding is *imported*, we delegate to `throwCodeFrame`. - 4. Any failure → return `null` so the caller can emit its own error. + 4. Any failure ➡️ return `null` so the caller can emit its own error. Returned value -------------- - • `string` → safe, space-free literal. - • `null` → invalid (dynamic / contains spaces / unresolved). + • `string` ➡️ safe, space-free literal. + • `null` ➡️ invalid (dynamic / contains spaces / unresolved). \*──────────────────────────────────────────────────────────*/ export function resolveTemplateLiteral( node: t.TemplateLiteral, @@ -224,15 +321,12 @@ export function resolveTemplateLiteral( } /*────────────────────────────────────*\ - resolveMemberExpression - a member expression is an object access like `THEMES.dark` or `THEMES['dark']` or `THEMES.brand.primary` - ----------------------- Resolve a **MemberExpression** like `THEMES.dark` or `THEMES['dark']` (optionally nested: `THEMES.brand.primary`) to a **space-free string** - **iff**: - + **if**: • The **base identifier** is a top-level `const` **ObjectExpression** • Every hop in the chain exists and is either - - another ObjectExpression (→ continue) or + - another ObjectExpression (➡️ continue) or - a **StringLiteral** terminal value • All keys are static (`Identifier`, `StringLiteral`, or numeric index on an ArrayExpression) @@ -251,7 +345,8 @@ export function resolveMemberExpression( literalFromNode: (expr: t.Expression, p: NodePath, opts: ResolveOpts) => string | null, opts: ResolveOpts ): string | null { - /** Collect the property chain (deep → shallow) */ + VERBOSE && console.log('resolveMemberExpression -> 352'); + /** Collect the property chain (deep ➡️ shallow) */ const props: (string | number)[] = []; let current: t.Expression | t.PrivateName = node; @@ -267,15 +362,15 @@ export function resolveMemberExpression( } else if (t.isNumericLiteral(expr)) { props.unshift(expr.value); } else { - const lit = literalFromNode(expr, path, opts); - if (lit === null) + const lit = literalFromNode(expr, path, { ...opts, throwOnFail: true }); + if (lit === null) { throwCodeFrame( path, path.opts?.filename, opts.source ?? path.opts?.source?.code, - '[Zero-UI] Member expression must resolve to a static space-free string.' + '[Zero-UI] Member expression must resolve to a static space-free string.\n' + 'only use const identifiers as keys.' ); - + } const num = Number(lit); props.unshift(Number.isFinite(num) ? num : lit); } @@ -325,7 +420,7 @@ export function resolveMemberExpression( } } - /* ── NEW: bail-out with an explicit error if nothing was found ───────── */ + /* ── bail-out with an explicit error if nothing was found ───────── */ if (value == null) { throwCodeFrame( path, @@ -336,17 +431,29 @@ export function resolveMemberExpression( } /* ─────────────────────────────────────────────────────── */ - /* existing tail logic (unwrap, recurse, return string)… */ + /* ── existing unwrap ─ */ if (t.isTSAsExpression(value)) value = value.expression; + /* ── recursively resolve nested member expressions ─ */ if (t.isMemberExpression(value)) { return resolveMemberExpression(value, path, literalFromNode, opts); } + /* ── support literals ─ */ if (t.isStringLiteral(value)) return value.value; if (t.isTemplateLiteral(value)) { return resolveTemplateLiteral(value, path, literalFromNode, opts); } + + /* ── NEW: resolve Identifier bindings recursively ─ */ + if (t.isIdentifier(value)) { + const idBinding = path.scope.getBinding(value.name); + if (!idBinding || !idBinding.path.isVariableDeclarator()) return null; + const resolvedInit = idBinding.path.node.init; + if (!resolvedInit) return null; + return literalFromNode(resolvedInit as t.Expression, idBinding.path, opts); + } + VERBOSE && console.log('resolveMemberExpression -> 460'); return null; } @@ -358,12 +465,60 @@ export function resolveMemberExpression( \*──────────────────────────────────────────────────────────*/ function resolveObjectValue(obj: t.ObjectExpression, key: string): t.Expression | null | undefined { for (const p of obj.properties) { + // Matches: { dark: 'theme' } - key = 'dark' if (t.isObjectProperty(p) && !p.computed && t.isIdentifier(p.key) && p.key.name === key) { return p.value as t.Expression; } + + // Matches: { ['dark']: 'theme' } - key = 'dark' if (t.isObjectProperty(p) && p.computed && t.isStringLiteral(p.key) && p.key.value === key) { return p.value as t.Expression; } + + // Matches: { "dark": "theme" } or { "1": "theme" } - key = 'dark' or '1' + // if (t.isObjectProperty(p) && t.isStringLiteral(p.key) && p.key.value === key) { + // return p.value as t.Expression; + // } + + // // ✅ New: Matches { 1: "theme" } - key = '1' + // if (t.isObjectProperty(p) && t.isNumericLiteral(p.key) && String(p.key.value) === key) { + // return p.value as t.Expression; + // } } + return null; } + +function containsIllegalIdentifiers(node: t.Node, path: NodePath, opts: ResolveOpts): void { + t.traverseFast(node, (subNode) => { + if (!t.isIdentifier(subNode)) return; + + const binding = path.scope.getBinding(subNode.name); + if (!binding) { + throwCodeFrame( + path, + path.opts?.filename, + opts.source ?? path.opts?.source?.code, + `[Zero-UI] Identifier '${subNode.name}' is not declared. Only local top-level consts are allowed.` + ); + } + + if (binding.path.isImportSpecifier() || binding.path.isImportDefaultSpecifier() || binding.path.isImportNamespaceSpecifier()) { + throwCodeFrame( + path, + path.opts?.filename, + opts.source ?? path.opts?.source?.code, + `[Zero-UI] Imports Not Allowed:\n Inline it or alias to a local const first.` + ); + } + + if (binding.scope.block.type !== 'Program' || (binding.path.parent as t.VariableDeclaration).kind !== 'const') { + throwCodeFrame( + path, + path.opts?.filename, + opts.source ?? path.opts?.source?.code, + `[Zero-UI] Only top-level \`const\` variables are allowed. '${subNode.name}' is not valid.` + ); + } + }); +} diff --git a/packages/core/src/postcss/scanner.ts b/packages/core/src/postcss/scanner.ts index e8d46f5..b748889 100644 --- a/packages/core/src/postcss/scanner.ts +++ b/packages/core/src/postcss/scanner.ts @@ -7,7 +7,7 @@ export function scanVariantTokens(src: string, keys: Set): Map"'`\s]*[^<>"'`\s:]/g; const TOK2 = /[^<>"'`\s.(){}[\]#=%]*[^<>"'`\s.(){}[\]#=%:]/g; const tokens = [...(src.match(TOK1) ?? []), ...(src.match(TOK2) ?? [])]; @@ -19,7 +19,7 @@ export function scanVariantTokens(src: string, keys: Set): Map, callback: () => Promise) { diff --git a/packages/core/src/postcss/utilities.ts b/packages/core/src/postcss/utilities.ts index cd9248b..98c8eca 100644 --- a/packages/core/src/postcss/utilities.ts +++ b/packages/core/src/postcss/utilities.ts @@ -1,5 +1,3 @@ -import { Result } from 'postcss'; - export function formatError(err: unknown) { const error = err instanceof Error ? err : new Error(String(err)); const eWithLoc = error as Error & { loc?: { file?: string; line?: number; column?: number } }; @@ -24,6 +22,13 @@ export function formatError(err: unknown) { return { friendly, loc: eWithLoc.loc }; } +export type Result = { + messages: { type: string; plugin: string; file: string; parent: string }[]; + opts: { from: string }; + prepend: (css: string) => void; + warn: (message: string, options?: { endIndex?: number; index?: number; node?: Node; plugin?: string; word?: string }) => void; +}; + export function registerDeps(result: Result, plugin: string, files: string[], parent: string) { files.forEach((file) => { result.messages.push({ type: 'dependency', plugin, file, parent }); diff --git a/packages/core/src/postcss/vite.ts b/packages/core/src/postcss/vite.ts index 26280f0..a87b06a 100644 --- a/packages/core/src/postcss/vite.ts +++ b/packages/core/src/postcss/vite.ts @@ -1,18 +1,18 @@ //src/postcss/vite.ts // vite-plugin-zero-ui.ts (ESM wrapper) -import tailwindcss from '@tailwindcss/postcss'; import zeroUiPostcss from './index.cjs'; +import tailwindcssInternal from '@tailwindcss/postcss'; import path from 'path'; // @ts-ignore import type { Plugin } from 'vite'; -export default function zeroUI(): Plugin { +export default function zeroUI({ tailwind }: { tailwind?: () => any } = {}): Plugin { return { name: 'vite-react-zero-ui', enforce: 'pre' as const, // run before other Vite plugins async config() { - return { css: { postcss: { plugins: [zeroUiPostcss, tailwindcss()] } } }; + return { css: { postcss: { plugins: [zeroUiPostcss, tailwind ? tailwind : tailwindcssInternal()] } } }; }, async transformIndexHtml(html: string): Promise { const { bodyAttributes } = await import(path.join(process.cwd(), './.zero-ui/attributes.js')); diff --git a/packages/core/tsconfig.build.json b/packages/core/tsconfig.build.json index 261f11d..c714811 100644 --- a/packages/core/tsconfig.build.json +++ b/packages/core/tsconfig.build.json @@ -1,7 +1,7 @@ // tsconfig.build.json { "extends": "../../tsconfig.base.json", - /* — compile exactly one file — */ + /* - compile exactly one file - */ "include": [ "src/**/*" ], @@ -9,11 +9,11 @@ "src/**/*.test.ts", "./src/postcss/test-utilities.ts" ], - /* — compiler output — */ + /* - compiler output - */ "compilerOptions": { "esModuleInterop": true, "rootDir": "./src", // keeps relative paths clean - "outDir": "./dist", // compiled JS → dist/ + "outDir": "./dist", // compiled JS ➡️ dist/ "noEmit": false, "removeComments": false } diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index ece91b4..e203816 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -1,13 +1,17 @@ { "extends": "../../tsconfig.base.json", - /* — compile exactly one file — */ - "include": ["src/**/*"], - "exclude": ["node_modules"], - /* — compiler output — */ + /* - compile exactly one file - */ + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules" + ], + /* - compiler output - */ "compilerOptions": { "moduleResolution": "nodenext", "esModuleInterop": true, "rootDir": "./src", // keeps relative paths clean - "outDir": "./dist" // compiled JS → dist/ + "outDir": "./dist" // compiled JS ➡️ dist/ } -} +} \ No newline at end of file diff --git a/packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/.zero-ui/attributes.d.ts b/packages/eslint-zero-ui/__tests__/fixtures/next/.zero-ui/attributes.d.ts similarity index 100% rename from packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/.zero-ui/attributes.d.ts rename to packages/eslint-zero-ui/__tests__/fixtures/next/.zero-ui/attributes.d.ts diff --git a/packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/.zero-ui/attributes.js b/packages/eslint-zero-ui/__tests__/fixtures/next/.zero-ui/attributes.js similarity index 100% rename from packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/.zero-ui/attributes.js rename to packages/eslint-zero-ui/__tests__/fixtures/next/.zero-ui/attributes.js diff --git a/packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/app/ChildComponent.tsx b/packages/eslint-zero-ui/__tests__/fixtures/next/app/ChildComponent.tsx similarity index 79% rename from packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/app/ChildComponent.tsx rename to packages/eslint-zero-ui/__tests__/fixtures/next/app/ChildComponent.tsx index 6808d9c..2e87ce0 100644 --- a/packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/app/ChildComponent.tsx +++ b/packages/eslint-zero-ui/__tests__/fixtures/next/app/ChildComponent.tsx @@ -1,6 +1,6 @@ -import { type ScopedSetterFn } from '@react-zero-ui/core'; +import { type GlobalSetterFn } from '@react-zero-ui/core'; -export function ChildComponent({ setIsOpen }: { setIsOpen: ScopedSetterFn }) { +export function ChildComponent({ setIsOpen }: { setIsOpen: GlobalSetterFn<'open' | 'closed'> }) { return (
('scope', 'off'); - // #2 No ref at all → missingRef error + // #2 No ref at all ➡️ missingRef error const [, setDialog] = useScopedUI<'open' | 'closed'>('dialog', 'closed'); return ( diff --git a/packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/app/UseEffectComponent.tsx b/packages/eslint-zero-ui/__tests__/fixtures/next/app/UseEffectComponent.tsx similarity index 100% rename from packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/app/UseEffectComponent.tsx rename to packages/eslint-zero-ui/__tests__/fixtures/next/app/UseEffectComponent.tsx diff --git a/packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/app/globals.css b/packages/eslint-zero-ui/__tests__/fixtures/next/app/globals.css similarity index 100% rename from packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/app/globals.css rename to packages/eslint-zero-ui/__tests__/fixtures/next/app/globals.css diff --git a/packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/app/layout.tsx b/packages/eslint-zero-ui/__tests__/fixtures/next/app/layout.tsx similarity index 100% rename from packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/app/layout.tsx rename to packages/eslint-zero-ui/__tests__/fixtures/next/app/layout.tsx diff --git a/packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/app/page.tsx b/packages/eslint-zero-ui/__tests__/fixtures/next/app/page.tsx similarity index 96% rename from packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/app/page.tsx rename to packages/eslint-zero-ui/__tests__/fixtures/next/app/page.tsx index 0fbe89a..d7b7fd8 100644 --- a/packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/app/page.tsx +++ b/packages/eslint-zero-ui/__tests__/fixtures/next/app/page.tsx @@ -1,5 +1,5 @@ 'use client'; -import { useUI } from '@react-zero-ui/core'; +import { useScopedUI, useUI } from '@react-zero-ui/core'; import UseEffectComponent from './UseEffectComponent'; import FAQ from './FAQ'; import { ChildComponent } from './ChildComponent'; @@ -11,9 +11,9 @@ export default function Page() { const [, setThemeThree] = useUI<'light' | 'dark'>('theme-three', 'light'); const [, setToggle] = useUI<'true' | 'false'>('toggle-boolean', 'true'); const [, setNumber] = useUI<'1' | '2'>('number', '1'); - const [, setOpen] = useUI<'open' | 'closed'>('faq', 'closed'); // Same key everywhere! - const [, setScope] = useUI<'off' | 'on'>('scope', 'off'); - const [, setMobile] = useUI<'true' | 'false'>('mobile', 'false'); + const [, setOpen] = useScopedUI<'open' | 'closed'>('faq', 'closed'); // Same key everywhere! + const [, setScope] = useScopedUI<'off' | 'on'>('scope', 'off'); + const [, setMobile] = useScopedUI<'true' | 'false'>('mobile', 'false'); const [, setChildOpen] = useUI<'open' | 'closed'>('child', 'closed'); const [, setToggleFunction] = useUI<'white' | 'black'>('toggle-function', 'white'); diff --git a/packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/app/variables.ts b/packages/eslint-zero-ui/__tests__/fixtures/next/app/variables.ts similarity index 100% rename from packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/app/variables.ts rename to packages/eslint-zero-ui/__tests__/fixtures/next/app/variables.ts diff --git a/packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/eslint.config.mjs b/packages/eslint-zero-ui/__tests__/fixtures/next/eslint.config.mjs similarity index 95% rename from packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/eslint.config.mjs rename to packages/eslint-zero-ui/__tests__/fixtures/next/eslint.config.mjs index 44277cc..fcf93a9 100644 --- a/packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/eslint.config.mjs +++ b/packages/eslint-zero-ui/__tests__/fixtures/next/eslint.config.mjs @@ -2,7 +2,7 @@ import { dirname } from 'path'; import { fileURLToPath } from 'url'; import { FlatCompat } from '@eslint/eslintrc'; import tsParser from '@typescript-eslint/parser'; -import zeroUiPlugin from 'eslint-plugin-react-zero-ui'; +import zeroUiPlugin from 'eslint-zero-ui'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); diff --git a/packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/next-env.d.ts b/packages/eslint-zero-ui/__tests__/fixtures/next/next-env.d.ts similarity index 100% rename from packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/next-env.d.ts rename to packages/eslint-zero-ui/__tests__/fixtures/next/next-env.d.ts diff --git a/packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/package.json b/packages/eslint-zero-ui/__tests__/fixtures/next/package.json similarity index 79% rename from packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/package.json rename to packages/eslint-zero-ui/__tests__/fixtures/next/package.json index 092b106..1e669b2 100644 --- a/packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/package.json +++ b/packages/eslint-zero-ui/__tests__/fixtures/next/package.json @@ -9,6 +9,7 @@ "lint": "eslint . --ext .js,.jsx,.ts,.tsx" }, "dependencies": { + "@react-zero-ui/core": "file:/Users/austinserb/Desktop/React-Zero/react-zero-ui/dist/react-zero-ui-core-0.3.1-beta.2.tgz", "next": "^15.0.0", "react": "^18.2.0", "react-dom": "^18.2.0" @@ -20,9 +21,9 @@ "@types/react": "19.1.7", "eslint": "^9.32.0", "eslint-config-next": "^15.4.5", - "eslint-plugin-react-zero-ui": "workspace:*", + "eslint-zero-ui": "workspace:*", "postcss": "^8.5.5", "tailwindcss": "^4.1.10", "typescript": "5.8.3" } -} +} \ No newline at end of file diff --git a/packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/postcss.config.mjs b/packages/eslint-zero-ui/__tests__/fixtures/next/postcss.config.mjs similarity index 100% rename from packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/postcss.config.mjs rename to packages/eslint-zero-ui/__tests__/fixtures/next/postcss.config.mjs diff --git a/packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/tsconfig.json b/packages/eslint-zero-ui/__tests__/fixtures/next/tsconfig.json similarity index 54% rename from packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/tsconfig.json rename to packages/eslint-zero-ui/__tests__/fixtures/next/tsconfig.json index 2530bc6..f0e1067 100644 --- a/packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next/tsconfig.json +++ b/packages/eslint-zero-ui/__tests__/fixtures/next/tsconfig.json @@ -1,10 +1,6 @@ { "compilerOptions": { - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], + "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "forceConsistentCasingInFileNames": true, "skipLibCheck": true, @@ -19,21 +15,8 @@ "jsx": "preserve", "target": "ES2017", "baseUrl": ".", - "paths": { - "@zero-ui/attributes": [ - "./.zero-ui/attributes.js" - ] - } + "paths": { "@zero-ui/attributes": ["./.zero-ui/attributes.js"] } }, - "include": [ - "**/*.ts", - "**/*.tsx", - ".next/**/*.d.ts", - ".next/types/**/*.ts", - ".zero-ui/**/*.d.ts", - "next-env.d.ts" - ], - "exclude": [ - "node_modules" - ] -} \ No newline at end of file + "include": ["**/*.ts", "**/*.tsx", ".next/**/*.d.ts", ".next/types/**/*.ts", ".zero-ui/**/*.d.ts", "next-env.d.ts"], + "exclude": ["node_modules"] +} diff --git a/packages/eslint-plugin-react-zero-ui/package.json b/packages/eslint-zero-ui/package.json similarity index 73% rename from packages/eslint-plugin-react-zero-ui/package.json rename to packages/eslint-zero-ui/package.json index e972381..3a1de12 100644 --- a/packages/eslint-plugin-react-zero-ui/package.json +++ b/packages/eslint-zero-ui/package.json @@ -1,5 +1,5 @@ { - "name": "eslint-plugin-react-zero-ui", + "name": "eslint-zero-ui", "version": "0.0.1-beta.1", "description": "ESLint rules for React Zero-UI", "type": "module", @@ -22,11 +22,13 @@ "prepare": "pnpm run build" }, "peerDependencies": { - "@typescript-eslint/parser": "^6.21.0", - "eslint": "^7.7.0" + "@typescript-eslint/parser": "^8.39.0", + "eslint": "^9.0.0" }, "devDependencies": { - "@typescript-eslint/utils": "^8.38.0", - "typescript": "^5.4.3" + "@typescript-eslint/utils": "^8.39.0" + }, + "dependencies": { + "typescript": "^5.9.2" } -} +} \ No newline at end of file diff --git a/packages/eslint-plugin-react-zero-ui/src/index.ts b/packages/eslint-zero-ui/src/index.ts similarity index 100% rename from packages/eslint-plugin-react-zero-ui/src/index.ts rename to packages/eslint-zero-ui/src/index.ts diff --git a/packages/eslint-plugin-react-zero-ui/src/rules/require-data-attr.ts b/packages/eslint-zero-ui/src/rules/require-data-attr.ts similarity index 97% rename from packages/eslint-plugin-react-zero-ui/src/rules/require-data-attr.ts rename to packages/eslint-zero-ui/src/rules/require-data-attr.ts index 30bfe99..ea85b29 100644 --- a/packages/eslint-plugin-react-zero-ui/src/rules/require-data-attr.ts +++ b/packages/eslint-zero-ui/src/rules/require-data-attr.ts @@ -1,6 +1,6 @@ import { ESLintUtils, TSESTree as T } from '@typescript-eslint/utils'; -const createRule = ESLintUtils.RuleCreator((name) => `https://github.com/serbyte/eslint-plugin-react-zero-ui/blob/main/docs/${name}.md`); +const createRule = ESLintUtils.RuleCreator((name) => `https://github.com/serbyte/eslint-zero-ui/blob/main/docs/${name}.md`); // At top of create() const hookLoc = new Map(); diff --git a/packages/eslint-plugin-react-zero-ui/tsconfig.json b/packages/eslint-zero-ui/tsconfig.json similarity index 100% rename from packages/eslint-plugin-react-zero-ui/tsconfig.json rename to packages/eslint-zero-ui/tsconfig.json diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 10c2fa5..e89a19c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,13 +13,7 @@ importers: version: 9.32.0 '@types/node': specifier: ^24.1.0 - version: 24.1.0 - '@typescript-eslint/eslint-plugin': - specifier: ^8.38.0 - version: 8.38.0(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) - '@typescript-eslint/parser': - specifier: ^8.38.0 - version: 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) + version: 24.2.0 esbuild: specifier: ^0.25.8 version: 0.25.8 @@ -28,16 +22,13 @@ importers: version: 9.32.0(jiti@2.5.1) eslint-plugin-import: specifier: ^2.32.0 - version: 2.32.0(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.5.1)) + version: 2.32.0(eslint@9.32.0(jiti@2.5.1)) eslint-plugin-n: specifier: ^17.21.3 version: 17.21.3(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) prettier: specifier: ^3.6.2 version: 3.6.2 - release-please: - specifier: ^17.1.1 - version: 17.1.1 tsx: specifier: ^4.20.3 version: 4.20.3 @@ -97,17 +88,8 @@ importers: packages/cli: dependencies: '@react-zero-ui/core': - specifier: ^0.2.2 - version: 0.2.7(@tailwindcss/postcss@4.1.11)(postcss@8.5.6)(react@19.1.1)(tailwindcss@4.1.11) - '@tailwindcss/postcss': - specifier: ^4.1.8 - version: 4.1.11 - postcss: - specifier: ^8.4.27 - version: 8.5.6 - tailwindcss: - specifier: ^4.0.0 - version: 4.1.11 + specifier: ^0.3.3 + version: 0.3.3(@tailwindcss/postcss@4.1.11)(react@19.1.1) packages/core: dependencies: @@ -135,15 +117,9 @@ importers: lru-cache: specifier: ^11.1.0 version: 11.1.0 - postcss: - specifier: ^8.5.5 - version: 8.5.6 react: specifier: '>=16.8.0' version: 19.1.1 - tailwindcss: - specifier: ^4.1.10 - version: 4.1.11 devDependencies: '@playwright/test': specifier: ^1.54.0 @@ -160,25 +136,28 @@ importers: '@types/react': specifier: ^19.1.8 version: 19.1.9 + postcss: + specifier: ^8.5.6 + version: 8.5.6 tsx: specifier: ^4.20.3 version: 4.20.3 - packages/eslint-plugin-react-zero-ui: + packages/eslint-zero-ui: dependencies: '@typescript-eslint/parser': - specifier: ^6.21.0 - version: 6.21.0(eslint@7.32.0)(typescript@5.9.2) + specifier: ^8.39.0 + version: 8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) eslint: - specifier: ^7.7.0 - version: 7.32.0 - devDependencies: - '@typescript-eslint/utils': - specifier: ^8.38.0 - version: 8.38.0(eslint@7.32.0)(typescript@5.9.2) + specifier: ^9.0.0 + version: 9.32.0(jiti@2.5.1) typescript: - specifier: ^5.4.3 + specifier: ^5.9.2 version: 5.9.2 + devDependencies: + '@typescript-eslint/utils': + specifier: ^8.39.0 + version: 8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) packages: @@ -190,9 +169,6 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} - '@babel/code-frame@7.12.11': - resolution: {integrity: sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==} - '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} @@ -243,10 +219,6 @@ packages: resolution: {integrity: sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw==} engines: {node: '>=6.9.0'} - '@babel/highlight@7.25.9': - resolution: {integrity: sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==} - engines: {node: '>=6.9.0'} - '@babel/parser@7.28.0': resolution: {integrity: sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==} engines: {node: '>=6.0.0'} @@ -270,9 +242,6 @@ packages: '@clack/prompts@0.8.2': resolution: {integrity: sha512-6b9Ab2UiZwJYA9iMyboYyW9yJvAO9V753ZhS+DHKEjZRKAxPPOb7MXXu84lsPFG+vZt6FRFniZ8rXi+zCIw4yQ==} - '@conventional-commits/parser@0.4.1': - resolution: {integrity: sha512-H2ZmUVt6q+KBccXfMBhbBF14NlANeqHTXL4qCL6QGbMzrc4HDXyzWuxPxPNbz71f/5UkR5DrycP5VO9u7crahg==} - '@emnapi/runtime@1.4.5': resolution: {integrity: sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==} @@ -454,10 +423,6 @@ packages: resolution: {integrity: sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/eslintrc@0.4.3': - resolution: {integrity: sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==} - engines: {node: ^10.12.0 || >=12.0.0} - '@eslint/eslintrc@3.3.1': resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -474,10 +439,6 @@ packages: resolution: {integrity: sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@google-automations/git-file-utils@3.0.0': - resolution: {integrity: sha512-e+WLoKR0TchIhKsSDOnd/su171eXKAAdLpP2tS825UAloTgfYus53kW8uKoVj9MAsMjXGXsJ2s1ASgjq81xVdA==} - engines: {node: '>= 18'} - '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -486,19 +447,10 @@ packages: resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} engines: {node: '>=18.18.0'} - '@humanwhocodes/config-array@0.5.0': - resolution: {integrity: sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead - '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} - '@humanwhocodes/object-schema@1.2.1': - resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} - deprecated: Use @eslint/object-schema instead - '@humanwhocodes/retry@0.3.1': resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} engines: {node: '>=18.18'} @@ -507,9 +459,6 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@iarna/toml@3.0.0': - resolution: {integrity: sha512-td6ZUkz2oS3VeleBcN+m//Q6HlCFCPrnI0FZhrt/h4XqLEdOyYp2u21nd8MdsR+WJy5r9PTDaHTDDfhf4H4l6Q==} - '@img/sharp-darwin-arm64@0.34.3': resolution: {integrity: sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -649,18 +598,6 @@ packages: '@jridgewell/trace-mapping@0.3.29': resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==} - '@jsep-plugin/assignment@1.3.0': - resolution: {integrity: sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==} - engines: {node: '>= 10.16.0'} - peerDependencies: - jsep: ^0.4.0||^1.0.0 - - '@jsep-plugin/regex@1.0.4': - resolution: {integrity: sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==} - engines: {node: '>= 10.16.0'} - peerDependencies: - jsep: ^0.4.0||^1.0.0 - '@next/env@15.4.5': resolution: {integrity: sha512-ruM+q2SCOVCepUiERoxOmZY9ZVoecR3gcXNwCYZRvQQWRjhOiPJGmQ2fAiLR6YKWXcSAh7G79KEFxN3rwhs4LQ==} @@ -724,58 +661,6 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@octokit/auth-token@4.0.0': - resolution: {integrity: sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==} - engines: {node: '>= 18'} - - '@octokit/core@5.2.2': - resolution: {integrity: sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==} - engines: {node: '>= 18'} - - '@octokit/endpoint@9.0.6': - resolution: {integrity: sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==} - engines: {node: '>= 18'} - - '@octokit/graphql@7.1.1': - resolution: {integrity: sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==} - engines: {node: '>= 18'} - - '@octokit/openapi-types@24.2.0': - resolution: {integrity: sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==} - - '@octokit/plugin-paginate-rest@11.4.4-cjs.2': - resolution: {integrity: sha512-2dK6z8fhs8lla5PaOTgqfCGBxgAv/le+EhPs27KklPhm1bKObpu6lXzwfUEQ16ajXzqNrKMujsFyo9K2eaoISw==} - engines: {node: '>= 18'} - peerDependencies: - '@octokit/core': '5' - - '@octokit/plugin-request-log@4.0.1': - resolution: {integrity: sha512-GihNqNpGHorUrO7Qa9JbAl0dbLnqJVrV8OXe2Zm5/Y4wFkZQDfTreBzVmiRfJVfE4mClXdihHnbpyyO9FSX4HA==} - engines: {node: '>= 18'} - peerDependencies: - '@octokit/core': '5' - - '@octokit/plugin-rest-endpoint-methods@13.3.2-cjs.1': - resolution: {integrity: sha512-VUjIjOOvF2oELQmiFpWA1aOPdawpyaCUqcEBc/UOUnj3Xp6DJGrJ1+bjUIIDzdHjnFNO6q57ODMfdEZnoBkCwQ==} - engines: {node: '>= 18'} - peerDependencies: - '@octokit/core': ^5 - - '@octokit/request-error@5.1.1': - resolution: {integrity: sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==} - engines: {node: '>= 18'} - - '@octokit/request@8.4.1': - resolution: {integrity: sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==} - engines: {node: '>= 18'} - - '@octokit/rest@20.1.2': - resolution: {integrity: sha512-GmYiltypkHHtihFwPRxlaorG5R9VAHuk/vbszVoRTGXnAsY60wYLkh/E2XiFmdZmqrisw+9FaazS1i5SbdWYgA==} - engines: {node: '>= 18'} - - '@octokit/types@13.10.0': - resolution: {integrity: sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==} - '@pivanov/utils@0.0.2': resolution: {integrity: sha512-q9CN0bFWxWgMY5hVVYyBgez1jGiLBa6I+LkG37ycylPhFvEGOOeaADGtUSu46CaZasPnlY8fCdVJZmrgKb1EPA==} peerDependencies: @@ -804,14 +689,12 @@ packages: react: '>=16.8.0' tailwindcss: ^4.1.10 - '@react-zero-ui/core@0.2.7': - resolution: {integrity: sha512-LMu+Zm4VHiJOiLNbs5fhLUK0+RxpnlurjgA7D24LuXBDLuYd22cQKiYBUOidi92nmo9uq4s8hMz7TGiAqhcc3w==} + '@react-zero-ui/core@0.3.3': + resolution: {integrity: sha512-ePcck57gfZrspPf8OqFc8gFsjGkCeBEYGXwIxuSsKwg/Z/AENcIt2RoAsRjY0chywAY5h3Xdk3dOeqrb7jnlqg==} engines: {node: '>=18.0.0'} peerDependencies: '@tailwindcss/postcss': ^4.1.10 - postcss: ^8.5.5 react: '>=16.8.0' - tailwindcss: ^4.1.10 '@rollup/pluginutils@5.2.0': resolution: {integrity: sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==} @@ -1034,20 +917,11 @@ packages: '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - '@types/minimist@1.2.5': - resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} - '@types/node@20.19.9': resolution: {integrity: sha512-cuVNgarYWZqxRJDQHEB58GEONhOK79QVR/qYx4S7kcUObQvUwvFnYxJuuHUKm2aieN9X3yZB4LZsuYNU1Qphsw==} - '@types/node@24.1.0': - resolution: {integrity: sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==} - - '@types/normalize-package-data@2.4.4': - resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} - - '@types/npm-package-arg@6.1.4': - resolution: {integrity: sha512-vDgdbMy2QXHnAruzlv68pUtXCjmqUk3WrBAsRboRovsOmxbfn/WiYCjmecyKjGztnMps5dWp4Uq2prp+Ilo17Q==} + '@types/node@24.2.0': + resolution: {integrity: sha512-3xyG3pMCq3oYCNg7/ZP+E1ooTaGB4cG8JWRsqqOYQdbWNY4zbaV0Ennrd7stjiJEFZCaybcIgpTjJWHRfBSIDw==} '@types/react-dom@19.1.7': resolution: {integrity: sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==} @@ -1062,103 +936,48 @@ packages: '@types/react@19.1.9': resolution: {integrity: sha512-WmdoynAX8Stew/36uTSVMcLJJ1KRh6L3IZRx1PZ7qJtBqT3dYTgyDTx8H1qoRghErydW7xw9mSJ3wS//tCRpFA==} - '@types/unist@2.0.11': - resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} - - '@types/yargs-parser@21.0.3': - resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - - '@types/yargs@16.0.9': - resolution: {integrity: sha512-tHhzvkFXZQeTECenFoRljLBYPZJ7jAVxqqtEI0qTLOmuultnFp4I9yKE17vTuhf7BkhCu7I4XuemPgikDVuYqA==} - - '@typescript-eslint/eslint-plugin@8.38.0': - resolution: {integrity: sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.38.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' - - '@typescript-eslint/parser@6.21.0': - resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/parser@8.38.0': - resolution: {integrity: sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==} + '@typescript-eslint/parser@8.39.0': + resolution: {integrity: sha512-g3WpVQHngx0aLXn6kfIYCZxM6rRJlWzEkVpqEFLT3SgEDsp9cpCbxxgwnE504q4H+ruSDh/VGS6nqZIDynP+vg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.38.0': - resolution: {integrity: sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg==} + '@typescript-eslint/project-service@8.39.0': + resolution: {integrity: sha512-CTzJqaSq30V/Z2Og9jogzZt8lJRR5TKlAdXmWgdu4hgcC9Kww5flQ+xFvMxIBWVNdxJO7OifgdOK4PokMIWPew==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <5.9.0' - - '@typescript-eslint/scope-manager@6.21.0': - resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==} - engines: {node: ^16.0.0 || >=18.0.0} - - '@typescript-eslint/scope-manager@8.38.0': - resolution: {integrity: sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/tsconfig-utils@8.38.0': - resolution: {integrity: sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==} + '@typescript-eslint/scope-manager@8.39.0': + resolution: {integrity: sha512-8QOzff9UKxOh6npZQ/4FQu4mjdOCGSdO3p44ww0hk8Vu+IGbg0tB/H1LcTARRDzGCC8pDGbh2rissBuuoPgH8A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/type-utils@8.38.0': - resolution: {integrity: sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg==} + '@typescript-eslint/tsconfig-utils@8.39.0': + resolution: {integrity: sha512-Fd3/QjmFV2sKmvv3Mrj8r6N8CryYiCS8Wdb/6/rgOXAWGcFuc+VkQuG28uk/4kVNVZBQuuDHEDUpo/pQ32zsIQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/types@6.21.0': - resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==} - engines: {node: ^16.0.0 || >=18.0.0} - - '@typescript-eslint/types@8.38.0': - resolution: {integrity: sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==} + '@typescript-eslint/types@8.39.0': + resolution: {integrity: sha512-ArDdaOllnCj3yn/lzKn9s0pBQYmmyme/v1HbGIGB0GB/knFI3fWMHloC+oYTJW46tVbYnGKTMDK4ah1sC2v0Kg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@6.21.0': - resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - - '@typescript-eslint/typescript-estree@8.38.0': - resolution: {integrity: sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==} + '@typescript-eslint/typescript-estree@8.39.0': + resolution: {integrity: sha512-ndWdiflRMvfIgQRpckQQLiB5qAKQ7w++V4LlCHwp62eym1HLB/kw7D9f2e8ytONls/jt89TEasgvb+VwnRprsw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/utils@8.38.0': - resolution: {integrity: sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==} + '@typescript-eslint/utils@8.39.0': + resolution: {integrity: sha512-4GVSvNA0Vx1Ktwvf4sFE+exxJ3QGUorQG1/A5mRfRNZtkBT2xrA/BCO2H0eALx/PnvCS6/vmYwRdDA41EoffkQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.9.0' + typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/visitor-keys@6.21.0': - resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==} - engines: {node: ^16.0.0 || >=18.0.0} - - '@typescript-eslint/visitor-keys@8.38.0': - resolution: {integrity: sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g==} + '@typescript-eslint/visitor-keys@8.39.0': + resolution: {integrity: sha512-ldgiJ+VAhQCfIjeOgu8Kj5nSxds0ktPOSO9p4+0VDH2R2pLvQraaM5Oen2d7NxzMCm+Sn/vJT+mv2H5u6b/3fA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@vercel/analytics@1.5.0': @@ -1187,54 +1006,23 @@ packages: vue-router: optional: true - '@xmldom/xmldom@0.8.10': - resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==} - engines: {node: '>=10.0.0'} - acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@7.4.1: - resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} - engines: {node: '>=0.4.0'} - hasBin: true - acorn@8.15.0: resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} hasBin: true - agent-base@7.1.4: - resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} - engines: {node: '>= 14'} - ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - ajv@8.17.1: - resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} - - ansi-colors@4.1.3: - resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} - engines: {node: '>=6'} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} - ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} - argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -1242,17 +1030,10 @@ packages: resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} engines: {node: '>= 0.4'} - array-ify@1.0.0: - resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} - array-includes@3.1.9: resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} engines: {node: '>= 0.4'} - array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - array.prototype.findlastindex@1.2.6: resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} engines: {node: '>= 0.4'} @@ -1269,21 +1050,10 @@ packages: resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} engines: {node: '>= 0.4'} - arrify@1.0.1: - resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} - engines: {node: '>=0.10.0'} - - astral-regex@2.0.0: - resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} - engines: {node: '>=8'} - async-function@1.0.0: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} - async-retry@1.3.3: - resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} - available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} @@ -1291,17 +1061,11 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - before-after-hook@2.2.3: - resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} - bippy@0.3.17: resolution: {integrity: sha512-0wG0kF9IM2MfS65mpU/3oU+0bRT5Wlh0oTqeRU8eJUU2+ga/QTGr3ZxzVEbQ1051NgADC8W+im1fP3Ln0Vof+Q==} peerDependencies: react: '>=17.0.1' - boolbase@1.0.0: - resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} @@ -1333,21 +1097,9 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - camelcase-keys@6.2.2: - resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==} - engines: {node: '>=8'} - - camelcase@5.3.1: - resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} - engines: {node: '>=6'} - caniuse-lite@1.0.30001731: resolution: {integrity: sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==} - chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} - chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -1359,32 +1111,14 @@ packages: client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} - cliui@7.0.4: - resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} - - cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} - clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} - code-suggester@5.0.0: - resolution: {integrity: sha512-/xyGfSM/hMYxl12kqoYoOwUm0D1uuVT2nWcMiTq2Fn5MLi+BlWkHq5AUvtniDJwVSdI3jgbK4AOzGws+v/dFPQ==} - engines: {node: '>=18.0.0'} - hasBin: true - - color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} - color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} @@ -1395,25 +1129,9 @@ packages: resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} engines: {node: '>=12.5.0'} - compare-func@2.0.0: - resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} - concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - conventional-changelog-conventionalcommits@6.1.0: - resolution: {integrity: sha512-3cS3GEtR78zTfMzk0AizXKKIdN4OvSh7ibNz6/DPbhWWQu7LqE/8+/GqSodV+sywUR2gpJAdP/1JFf4XtN7Zpw==} - engines: {node: '>=14'} - - conventional-changelog-writer@6.0.1: - resolution: {integrity: sha512-359t9aHorPw+U+nHzUXHS5ZnPBOizRxfQsWT5ZDHBfvfxQOAik+yfuhKXG66CN5LEWPpMNnIMHUTCKeYNprvHQ==} - engines: {node: '>=14'} - hasBin: true - - conventional-commits-filter@3.0.0: - resolution: {integrity: sha512-1ymej8b5LouPx9Ox0Dw/qAO2dVdfpRFq28e5Y0jJEU8ZrLdy0vOSkkIInwmxErFGhg6SALro60ZrwYFVTUDo4Q==} - engines: {node: '>=14'} - convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -1421,13 +1139,6 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - css-select@5.2.2: - resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} - - css-what@6.2.2: - resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} - engines: {node: '>= 6'} - csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} @@ -1443,9 +1154,6 @@ packages: resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} engines: {node: '>= 0.4'} - dateformat@3.0.3: - resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==} - debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: @@ -1463,14 +1171,6 @@ packages: supports-color: optional: true - decamelize-keys@1.1.1: - resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} - engines: {node: '>=0.10.0'} - - decamelize@1.2.0: - resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} - engines: {node: '>=0.10.0'} - deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -1482,79 +1182,25 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} - deprecation@2.3.1: - resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} - - detect-indent@6.1.0: - resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} - engines: {node: '>=8'} - detect-libc@2.0.4: resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} engines: {node: '>=8'} - diff@5.2.0: - resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} - engines: {node: '>=0.3.1'} - - diff@7.0.0: - resolution: {integrity: sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==} - engines: {node: '>=0.3.1'} - - dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} - doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - - dom-serializer@2.0.0: - resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} - - domelementtype@2.3.0: - resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} - - domhandler@5.0.3: - resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} - engines: {node: '>= 4'} - - domutils@3.2.2: - resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} - - dot-prop@5.3.0: - resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} - engines: {node: '>=8'} - dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - electron-to-chromium@1.5.194: - resolution: {integrity: sha512-SdnWJwSUot04UR51I2oPD8kuP2VI37/CADR1OHsFOUzZIvfWJBO6q11k5P/uKNyTT3cdOsnyjkrZ+DDShqYqJA==} - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + electron-to-chromium@1.5.196: + resolution: {integrity: sha512-FnnXV0dXANe7YNtKl/Af1raw+sBBUPuwcNEWfLOJyumXBvfQEBsnc0Gn+yEnVscq4x3makTtrlf4TjAo7lcXTQ==} enhanced-resolve@5.18.2: resolution: {integrity: sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==} engines: {node: '>=10.13.0'} - enquirer@2.4.1: - resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} - engines: {node: '>=8.6'} - - entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} - - error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - es-abstract@1.24.0: resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} engines: {node: '>= 0.4'} @@ -1592,10 +1238,6 @@ packages: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} - escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -1652,26 +1294,10 @@ packages: peerDependencies: eslint: '>=8.23.0' - eslint-scope@5.1.1: - resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} - engines: {node: '>=8.0.0'} - eslint-scope@8.4.0: resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint-utils@2.1.0: - resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==} - engines: {node: '>=6'} - - eslint-visitor-keys@1.3.0: - resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} - engines: {node: '>=4'} - - eslint-visitor-keys@2.1.0: - resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} - engines: {node: '>=10'} - eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1680,12 +1306,6 @@ packages: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@7.32.0: - resolution: {integrity: sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==} - engines: {node: ^10.12.0 || >=12.0.0} - deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. - hasBin: true - eslint@9.32.0: resolution: {integrity: sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1700,15 +1320,6 @@ packages: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - espree@7.3.1: - resolution: {integrity: sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==} - engines: {node: ^10.12.0 || >=12.0.0} - - esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - esquery@1.6.0: resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} @@ -1717,10 +1328,6 @@ packages: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} - estraverse@4.3.0: - resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} - engines: {node: '>=4.0'} - estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} @@ -1748,20 +1355,9 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-uri@3.0.6: - resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} - fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} - figures@3.2.0: - resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} - engines: {node: '>=8'} - - file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} - file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -1770,18 +1366,10 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} - find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} - flat-cache@4.0.1: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} @@ -1807,9 +1395,6 @@ packages: react-dom: optional: true - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - fsevents@2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1827,9 +1412,6 @@ packages: resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} engines: {node: '>= 0.4'} - functional-red-black-tree@1.0.1: - resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} - functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} @@ -1837,10 +1419,6 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} @@ -1864,14 +1442,6 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported - - globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} - globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} @@ -1884,10 +1454,6 @@ packages: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} - globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} - globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} @@ -1898,26 +1464,10 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - - handlebars@4.7.8: - resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} - engines: {node: '>=0.4.7'} - hasBin: true - - hard-rejection@2.1.0: - resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} - engines: {node: '>=6'} - has-bigints@1.1.0: resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} engines: {node: '>= 0.4'} - has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} - has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} @@ -1941,37 +1491,10 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - he@1.2.0: - resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} - hasBin: true - - hosted-git-info@2.8.9: - resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} - - hosted-git-info@4.1.0: - resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} - engines: {node: '>=10'} - - http-proxy-agent@7.0.2: - resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} - engines: {node: '>= 14'} - - https-proxy-agent@7.0.6: - resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} - engines: {node: '>= 14'} - - ignore@4.0.6: - resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} - engines: {node: '>= 4'} - ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} - ignore@7.0.5: - resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} - engines: {node: '>= 4'} - import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -1980,17 +1503,6 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} - - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} @@ -1999,9 +1511,6 @@ packages: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} - is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-arrayish@0.3.2: resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} @@ -2041,10 +1550,6 @@ packages: resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} engines: {node: '>= 0.4'} - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - is-generator-function@1.1.0: resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} engines: {node: '>= 0.4'} @@ -2069,14 +1574,6 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - is-obj@2.0.0: - resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} - engines: {node: '>=8'} - - is-plain-obj@1.1.0: - resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} - engines: {node: '>=0.10.0'} - is-regex@1.2.1: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} @@ -2126,18 +1623,10 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} - hasBin: true - js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true - jsep@1.4.0: - resolution: {integrity: sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==} - engines: {node: '>= 10.16.0'} - jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -2146,21 +1635,12 @@ packages: json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - json-stringify-safe@5.0.1: - resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} - json5@1.0.2: resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} hasBin: true @@ -2170,18 +1650,9 @@ packages: engines: {node: '>=6'} hasBin: true - jsonpath-plus@10.3.0: - resolution: {integrity: sha512-8TNmfeTCk2Le33A3vRRwtuworG/L5RrgMvdjhKZxvyShO+mBu2fP50OWUjRLNtvw344DdDarFh9buFAZs5ujeA==} - engines: {node: '>=18.0.0'} - hasBin: true - keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - kind-of@6.0.3: - resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} - engines: {node: '>=0.10.0'} - kleur@4.1.5: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} @@ -2254,26 +1725,13 @@ packages: resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} engines: {node: '>= 12.0.0'} - lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - - locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} - locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - lodash.ismatch@4.4.0: - resolution: {integrity: sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==} - lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - lodash.truncate@4.4.2: - resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} - lru-cache@11.1.0: resolution: {integrity: sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==} engines: {node: 20 || >=22} @@ -2281,29 +1739,13 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} - map-obj@1.0.1: - resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} - engines: {node: '>=0.10.0'} - - map-obj@4.3.0: - resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} - engines: {node: '>=8'} - math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - meow@8.1.2: - resolution: {integrity: sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==} - engines: {node: '>=10'} - merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -2312,29 +1754,13 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} - min-indent@1.0.1: - resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} - engines: {node: '>=4'} - minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} - - minimatch@9.0.3: - resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} - engines: {node: '>=16 || 14 >=14.17'} - minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} - minimist-options@4.1.0: - resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} - engines: {node: '>= 6'} - minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -2351,10 +1777,6 @@ packages: engines: {node: '>=10'} hasBin: true - modify-values@1.0.1: - resolution: {integrity: sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==} - engines: {node: '>=0.10.0'} - motion-dom@12.23.12: resolution: {integrity: sha512-RcR4fvMCTESQBD/uKQe49D5RUeDOokkGRmz4ceaJKDBgHYtZtntC/s2vLvY38gqGaytinij/yi3hMcWVcEF5Kw==} @@ -2390,9 +1812,6 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - neo-async@2.6.2: - resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - next@15.4.5: resolution: {integrity: sha512-nJ4v+IO9CPmbmcvsPebIoX3Q+S7f6Fu08/dEWu0Ttfa+wVwQRh9epcmsyCPjmL2b8MxC+CkBR97jgDhUUztI3g==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} @@ -2414,22 +1833,9 @@ packages: sass: optional: true - node-html-parser@6.1.13: - resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==} - node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} - normalize-package-data@2.5.0: - resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} - - normalize-package-data@3.0.3: - resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} - engines: {node: '>=10'} - - nth-check@2.1.1: - resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - object-inspect@1.13.4: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} @@ -2454,9 +1860,6 @@ packages: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -2465,48 +1868,22 @@ packages: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} - p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} - p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} - p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} - p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} - p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} - parse-diff@0.11.1: - resolution: {integrity: sha512-Oq4j8LAOPOcssanQkIjxosjATBIEJhCxMCxPhMu+Ci4wdNmAEdx0O+a7gzbR2PyKXgKPvRLIN5g224+dJAsKHA==} - - parse-github-repo-url@1.4.1: - resolution: {integrity: sha512-bSWyzBKqcSL4RrncTpGsEKoJ7H8a4L3++ifTAbTFeMHyq2wRV+42DGmQcHIrJIvdcacjIOxEuKH/w4tthF17gg==} - - parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} - path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -2514,10 +1891,6 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -2563,10 +1936,6 @@ packages: engines: {node: '>=14'} hasBin: true - progress@2.0.3: - resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} - engines: {node: '>=0.4.0'} - punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -2574,10 +1943,6 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - quick-lru@4.0.1: - resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} - engines: {node: '>=8'} - react-dom@19.1.1: resolution: {integrity: sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==} peerDependencies: @@ -2607,18 +1972,6 @@ packages: resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==} engines: {node: '>=0.10.0'} - read-pkg-up@7.0.1: - resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} - engines: {node: '>=8'} - - read-pkg@5.2.0: - resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} - engines: {node: '>=8'} - - redent@3.0.0: - resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} - engines: {node: '>=8'} - reflect.getprototypeof@1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} @@ -2627,23 +1980,6 @@ packages: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} - regexpp@3.2.0: - resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} - engines: {node: '>=8'} - - release-please@17.1.1: - resolution: {integrity: sha512-baFGx79P5hGxbtDqf8p+ThwQjHT/byst6EtnCkjfA6FcK5UnaERn6TBI+8wSsaVIohPG2urYjZaPkITxDS3/Pw==} - engines: {node: '>=18.0.0'} - hasBin: true - - require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - - require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -2656,19 +1992,10 @@ packages: engines: {node: '>= 0.4'} hasBin: true - retry@0.13.1: - resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} - engines: {node: '>= 4'} - reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - rollup@4.46.2: resolution: {integrity: sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -2692,10 +2019,6 @@ packages: scheduler@0.26.0: resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} - semver@5.7.2: - resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} - hasBin: true - semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -2751,48 +2074,14 @@ packages: sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - - slice-ansi@4.0.0: - resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} - engines: {node: '>=10'} - source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} - source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - - spdx-correct@3.2.0: - resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} - - spdx-exceptions@2.5.0: - resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} - - spdx-expression-parse@3.0.1: - resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - - spdx-license-ids@3.0.21: - resolution: {integrity: sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==} - - split@1.0.1: - resolution: {integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==} - - sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - stop-iteration-iterator@1.1.0: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - string.prototype.trim@1.2.10: resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} engines: {node: '>= 0.4'} @@ -2805,18 +2094,10 @@ packages: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} - strip-indent@3.0.0: - resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} - engines: {node: '>=8'} - strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -2834,10 +2115,6 @@ packages: babel-plugin-macros: optional: true - supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} - supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -2846,10 +2123,6 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - table@6.9.0: - resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} - engines: {node: '>=10.0.0'} - tailwindcss@4.1.11: resolution: {integrity: sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==} @@ -2861,26 +2134,10 @@ packages: resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} engines: {node: '>=18'} - text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - - through@2.3.8: - resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - trim-newlines@3.0.1: - resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} - engines: {node: '>=8'} - - ts-api-utils@1.4.3: - resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==} - engines: {node: '>=16'} - peerDependencies: - typescript: '>=4.2.0' - ts-api-utils@2.1.0: resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} engines: {node: '>=18.12'} @@ -2907,26 +2164,6 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - type-fest@0.18.1: - resolution: {integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==} - engines: {node: '>=10'} - - type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - - type-fest@0.6.0: - resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} - engines: {node: '>=8'} - - type-fest@0.8.1: - resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} - engines: {node: '>=8'} - - type-fest@3.13.1: - resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} - engines: {node: '>=14.16'} - typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -2943,21 +2180,11 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} - typescript@4.9.5: - resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} - engines: {node: '>=4.2.0'} - hasBin: true - typescript@5.9.2: resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} engines: {node: '>=14.17'} hasBin: true - uglify-js@3.19.3: - resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} - engines: {node: '>=0.8.0'} - hasBin: true - unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} @@ -2965,20 +2192,8 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici-types@7.8.0: - resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==} - - unist-util-is@4.1.0: - resolution: {integrity: sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==} - - unist-util-visit-parents@3.1.1: - resolution: {integrity: sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==} - - unist-util-visit@2.0.3: - resolution: {integrity: sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==} - - universal-user-agent@6.0.1: - resolution: {integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==} + undici-types@7.10.0: + resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==} unplugin@2.1.0: resolution: {integrity: sha512-us4j03/499KhbGP8BU7Hrzrgseo+KdfJYWcbcajCOqsAyb8Gk0Yn2kiUIcZISYCb1JFaZfIuG3b42HmguVOKCQ==} @@ -2993,12 +2208,6 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - v8-compile-cache@2.4.0: - resolution: {integrity: sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==} - - validate-npm-package-license@3.0.4: - resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} - webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} @@ -3027,55 +2236,13 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - wordwrap@1.0.0: - resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - xpath@0.0.34: - resolution: {integrity: sha512-FxF6+rkr1rNSQrhUNYrAFJpRXNzlDoMxeXN5qI84939ylEv3qqPFKa85Oxr6tDaJKqwW6KKyo2v26TSv3k6LeA==} - engines: {node: '>=0.6.0'} - - y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - yallist@5.0.0: resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} engines: {node: '>=18'} - yaml@2.8.0: - resolution: {integrity: sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==} - engines: {node: '>= 14.6'} - hasBin: true - - yargs-parser@20.2.9: - resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} - engines: {node: '>=10'} - - yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - - yargs@16.2.0: - resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} - engines: {node: '>=10'} - - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} - yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -3089,10 +2256,6 @@ snapshots: '@jridgewell/gen-mapping': 0.3.12 '@jridgewell/trace-mapping': 0.3.29 - '@babel/code-frame@7.12.11': - dependencies: - '@babel/highlight': 7.25.9 - '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.27.1 @@ -3166,13 +2329,6 @@ snapshots: '@babel/template': 7.27.2 '@babel/types': 7.28.2 - '@babel/highlight@7.25.9': - dependencies: - '@babel/helper-validator-identifier': 7.27.1 - chalk: 2.4.2 - js-tokens: 4.0.0 - picocolors: 1.1.1 - '@babel/parser@7.28.0': dependencies: '@babel/types': 7.28.2 @@ -3211,11 +2367,6 @@ snapshots: picocolors: 1.1.1 sisteransi: 1.0.5 - '@conventional-commits/parser@0.4.1': - dependencies: - unist-util-visit: 2.0.3 - unist-util-visit-parents: 3.1.1 - '@emnapi/runtime@1.4.5': dependencies: tslib: 2.8.1 @@ -3299,11 +2450,6 @@ snapshots: '@esbuild/win32-x64@0.25.8': optional: true - '@eslint-community/eslint-utils@4.7.0(eslint@7.32.0)': - dependencies: - eslint: 7.32.0 - eslint-visitor-keys: 3.4.3 - '@eslint-community/eslint-utils@4.7.0(eslint@9.32.0(jiti@2.5.1))': dependencies: eslint: 9.32.0(jiti@2.5.1) @@ -3325,20 +2471,6 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/eslintrc@0.4.3': - dependencies: - ajv: 6.12.6 - debug: 4.4.1 - espree: 7.3.1 - globals: 13.24.0 - ignore: 4.0.6 - import-fresh: 3.3.1 - js-yaml: 3.14.1 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - '@eslint/eslintrc@3.3.1': dependencies: ajv: 6.12.6 @@ -3362,12 +2494,6 @@ snapshots: '@eslint/core': 0.15.1 levn: 0.4.1 - '@google-automations/git-file-utils@3.0.0': - dependencies: - '@octokit/rest': 20.1.2 - '@octokit/types': 13.10.0 - minimatch: 5.1.6 - '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.6': @@ -3375,24 +2501,12 @@ snapshots: '@humanfs/core': 0.19.1 '@humanwhocodes/retry': 0.3.1 - '@humanwhocodes/config-array@0.5.0': - dependencies: - '@humanwhocodes/object-schema': 1.2.1 - debug: 4.4.1 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - '@humanwhocodes/module-importer@1.0.1': {} - '@humanwhocodes/object-schema@1.2.1': {} - '@humanwhocodes/retry@0.3.1': {} '@humanwhocodes/retry@0.4.3': {} - '@iarna/toml@3.0.0': {} - '@img/sharp-darwin-arm64@0.34.3': optionalDependencies: '@img/sharp-libvips-darwin-arm64': 1.2.0 @@ -3497,14 +2611,6 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.4 - '@jsep-plugin/assignment@1.3.0(jsep@1.4.0)': - dependencies: - jsep: 1.4.0 - - '@jsep-plugin/regex@1.0.4(jsep@1.4.0)': - dependencies: - jsep: 1.4.0 - '@next/env@15.4.5': {} '@next/swc-darwin-arm64@15.4.5': @@ -3543,69 +2649,6 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.19.1 - '@octokit/auth-token@4.0.0': {} - - '@octokit/core@5.2.2': - dependencies: - '@octokit/auth-token': 4.0.0 - '@octokit/graphql': 7.1.1 - '@octokit/request': 8.4.1 - '@octokit/request-error': 5.1.1 - '@octokit/types': 13.10.0 - before-after-hook: 2.2.3 - universal-user-agent: 6.0.1 - - '@octokit/endpoint@9.0.6': - dependencies: - '@octokit/types': 13.10.0 - universal-user-agent: 6.0.1 - - '@octokit/graphql@7.1.1': - dependencies: - '@octokit/request': 8.4.1 - '@octokit/types': 13.10.0 - universal-user-agent: 6.0.1 - - '@octokit/openapi-types@24.2.0': {} - - '@octokit/plugin-paginate-rest@11.4.4-cjs.2(@octokit/core@5.2.2)': - dependencies: - '@octokit/core': 5.2.2 - '@octokit/types': 13.10.0 - - '@octokit/plugin-request-log@4.0.1(@octokit/core@5.2.2)': - dependencies: - '@octokit/core': 5.2.2 - - '@octokit/plugin-rest-endpoint-methods@13.3.2-cjs.1(@octokit/core@5.2.2)': - dependencies: - '@octokit/core': 5.2.2 - '@octokit/types': 13.10.0 - - '@octokit/request-error@5.1.1': - dependencies: - '@octokit/types': 13.10.0 - deprecation: 2.3.1 - once: 1.4.0 - - '@octokit/request@8.4.1': - dependencies: - '@octokit/endpoint': 9.0.6 - '@octokit/request-error': 5.1.1 - '@octokit/types': 13.10.0 - universal-user-agent: 6.0.1 - - '@octokit/rest@20.1.2': - dependencies: - '@octokit/core': 5.2.2 - '@octokit/plugin-paginate-rest': 11.4.4-cjs.2(@octokit/core@5.2.2) - '@octokit/plugin-request-log': 4.0.1(@octokit/core@5.2.2) - '@octokit/plugin-rest-endpoint-methods': 13.3.2-cjs.1(@octokit/core@5.2.2) - - '@octokit/types@13.10.0': - dependencies: - '@octokit/openapi-types': 24.2.0 - '@pivanov/utils@0.0.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: react: 19.1.1 @@ -3635,7 +2678,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@react-zero-ui/core@0.2.7(@tailwindcss/postcss@4.1.11)(postcss@8.5.6)(react@19.1.1)(tailwindcss@4.1.11)': + '@react-zero-ui/core@0.3.3(@tailwindcss/postcss@4.1.11)(react@19.1.1)': dependencies: '@babel/code-frame': 7.27.1 '@babel/generator': 7.28.0 @@ -3645,9 +2688,7 @@ snapshots: '@tailwindcss/postcss': 4.1.11 fast-glob: 3.3.3 lru-cache: 11.1.0 - postcss: 8.5.6 react: 19.1.1 - tailwindcss: 4.1.11 transitivePeerDependencies: - supports-color @@ -3813,19 +2854,13 @@ snapshots: '@types/json5@0.0.29': {} - '@types/minimist@1.2.5': {} - '@types/node@20.19.9': dependencies: undici-types: 6.21.0 - '@types/node@24.1.0': + '@types/node@24.2.0': dependencies: - undici-types: 7.8.0 - - '@types/normalize-package-data@2.4.4': {} - - '@types/npm-package-arg@6.1.4': {} + undici-types: 7.10.0 '@types/react-dom@19.1.7(@types/react@19.1.9)': dependencies: @@ -3839,116 +2874,44 @@ snapshots: dependencies: csstype: 3.1.3 - '@types/unist@2.0.11': {} - - '@types/yargs-parser@21.0.3': {} - - '@types/yargs@16.0.9': - dependencies: - '@types/yargs-parser': 21.0.3 - - '@typescript-eslint/eslint-plugin@8.38.0(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2)': - dependencies: - '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) - '@typescript-eslint/scope-manager': 8.38.0 - '@typescript-eslint/type-utils': 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) - '@typescript-eslint/utils': 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) - '@typescript-eslint/visitor-keys': 8.38.0 - eslint: 9.32.0(jiti@2.5.1) - graphemer: 1.4.0 - ignore: 7.0.5 - natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.9.2) - typescript: 5.9.2 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/parser@6.21.0(eslint@7.32.0)(typescript@5.9.2)': - dependencies: - '@typescript-eslint/scope-manager': 6.21.0 - '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.9.2) - '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.4.1 - eslint: 7.32.0 - optionalDependencies: - typescript: 5.9.2 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2)': + '@typescript-eslint/parser@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: - '@typescript-eslint/scope-manager': 8.38.0 - '@typescript-eslint/types': 8.38.0 - '@typescript-eslint/typescript-estree': 8.38.0(typescript@5.9.2) - '@typescript-eslint/visitor-keys': 8.38.0 + '@typescript-eslint/scope-manager': 8.39.0 + '@typescript-eslint/types': 8.39.0 + '@typescript-eslint/typescript-estree': 8.39.0(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 8.39.0 debug: 4.4.1 eslint: 9.32.0(jiti@2.5.1) typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.38.0(typescript@5.9.2)': + '@typescript-eslint/project-service@8.39.0(typescript@5.9.2)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.38.0(typescript@5.9.2) - '@typescript-eslint/types': 8.38.0 + '@typescript-eslint/tsconfig-utils': 8.39.0(typescript@5.9.2) + '@typescript-eslint/types': 8.39.0 debug: 4.4.1 typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@6.21.0': - dependencies: - '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/visitor-keys': 6.21.0 - - '@typescript-eslint/scope-manager@8.38.0': + '@typescript-eslint/scope-manager@8.39.0': dependencies: - '@typescript-eslint/types': 8.38.0 - '@typescript-eslint/visitor-keys': 8.38.0 + '@typescript-eslint/types': 8.39.0 + '@typescript-eslint/visitor-keys': 8.39.0 - '@typescript-eslint/tsconfig-utils@8.38.0(typescript@5.9.2)': + '@typescript-eslint/tsconfig-utils@8.39.0(typescript@5.9.2)': dependencies: typescript: 5.9.2 - '@typescript-eslint/type-utils@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2)': - dependencies: - '@typescript-eslint/types': 8.38.0 - '@typescript-eslint/typescript-estree': 8.38.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) - debug: 4.4.1 - eslint: 9.32.0(jiti@2.5.1) - ts-api-utils: 2.1.0(typescript@5.9.2) - typescript: 5.9.2 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/types@6.21.0': {} - - '@typescript-eslint/types@8.38.0': {} - - '@typescript-eslint/typescript-estree@6.21.0(typescript@5.9.2)': - dependencies: - '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.4.1 - globby: 11.1.0 - is-glob: 4.0.3 - minimatch: 9.0.3 - semver: 7.7.2 - ts-api-utils: 1.4.3(typescript@5.9.2) - optionalDependencies: - typescript: 5.9.2 - transitivePeerDependencies: - - supports-color + '@typescript-eslint/types@8.39.0': {} - '@typescript-eslint/typescript-estree@8.38.0(typescript@5.9.2)': + '@typescript-eslint/typescript-estree@8.39.0(typescript@5.9.2)': dependencies: - '@typescript-eslint/project-service': 8.38.0(typescript@5.9.2) - '@typescript-eslint/tsconfig-utils': 8.38.0(typescript@5.9.2) - '@typescript-eslint/types': 8.38.0 - '@typescript-eslint/visitor-keys': 8.38.0 + '@typescript-eslint/project-service': 8.39.0(typescript@5.9.2) + '@typescript-eslint/tsconfig-utils': 8.39.0(typescript@5.9.2) + '@typescript-eslint/types': 8.39.0 + '@typescript-eslint/visitor-keys': 8.39.0 debug: 4.4.1 fast-glob: 3.3.3 is-glob: 4.0.3 @@ -3959,36 +2922,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.38.0(eslint@7.32.0)(typescript@5.9.2)': - dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@7.32.0) - '@typescript-eslint/scope-manager': 8.38.0 - '@typescript-eslint/types': 8.38.0 - '@typescript-eslint/typescript-estree': 8.38.0(typescript@5.9.2) - eslint: 7.32.0 - typescript: 5.9.2 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2)': + '@typescript-eslint/utils@8.39.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2)': dependencies: '@eslint-community/eslint-utils': 4.7.0(eslint@9.32.0(jiti@2.5.1)) - '@typescript-eslint/scope-manager': 8.38.0 - '@typescript-eslint/types': 8.38.0 - '@typescript-eslint/typescript-estree': 8.38.0(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.39.0 + '@typescript-eslint/types': 8.39.0 + '@typescript-eslint/typescript-estree': 8.39.0(typescript@5.9.2) eslint: 9.32.0(jiti@2.5.1) typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@6.21.0': - dependencies: - '@typescript-eslint/types': 6.21.0 - eslint-visitor-keys: 3.4.3 - - '@typescript-eslint/visitor-keys@8.38.0': + '@typescript-eslint/visitor-keys@8.39.0': dependencies: - '@typescript-eslint/types': 8.38.0 + '@typescript-eslint/types': 8.39.0 eslint-visitor-keys: 4.2.1 '@vercel/analytics@1.5.0(next@15.4.5(@babel/core@7.28.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)': @@ -3996,22 +2943,12 @@ snapshots: next: 15.4.5(@babel/core@7.28.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) react: 19.1.1 - '@xmldom/xmldom@0.8.10': {} - - acorn-jsx@5.3.2(acorn@7.4.1): - dependencies: - acorn: 7.4.1 - acorn-jsx@5.3.2(acorn@8.15.0): dependencies: acorn: 8.15.0 - acorn@7.4.1: {} - acorn@8.15.0: {} - agent-base@7.1.4: {} - ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -4019,29 +2956,10 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ajv@8.17.1: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.0.6 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - - ansi-colors@4.1.3: {} - - ansi-regex@5.0.1: {} - - ansi-styles@3.2.1: - dependencies: - color-convert: 1.9.3 - ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 - argparse@1.0.10: - dependencies: - sprintf-js: 1.0.3 - argparse@2.0.1: {} array-buffer-byte-length@1.0.2: @@ -4049,8 +2967,6 @@ snapshots: call-bound: 1.0.4 is-array-buffer: 3.0.5 - array-ify@1.0.0: {} - array-includes@3.1.9: dependencies: call-bind: 1.0.8 @@ -4062,8 +2978,6 @@ snapshots: is-string: 1.1.1 math-intrinsics: 1.1.0 - array-union@2.1.0: {} - array.prototype.findlastindex@1.2.6: dependencies: call-bind: 1.0.8 @@ -4098,24 +3012,14 @@ snapshots: get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 - arrify@1.0.1: {} - - astral-regex@2.0.0: {} - async-function@1.0.0: {} - async-retry@1.3.3: - dependencies: - retry: 0.13.1 - available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.1.0 balanced-match@1.0.2: {} - before-after-hook@2.2.3: {} - bippy@0.3.17(@types/react@19.1.9)(react@19.1.1): dependencies: '@types/react-reconciler': 0.28.9(@types/react@19.1.9) @@ -4123,8 +3027,6 @@ snapshots: transitivePeerDependencies: - '@types/react' - boolbase@1.0.0: {} - brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 @@ -4141,7 +3043,7 @@ snapshots: browserslist@4.25.1: dependencies: caniuse-lite: 1.0.30001731 - electron-to-chromium: 1.5.194 + electron-to-chromium: 1.5.196 node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.25.1) @@ -4164,22 +3066,8 @@ snapshots: callsites@3.1.0: {} - camelcase-keys@6.2.2: - dependencies: - camelcase: 5.3.1 - map-obj: 4.3.0 - quick-lru: 4.0.1 - - camelcase@5.3.1: {} - caniuse-lite@1.0.30001731: {} - chalk@2.4.2: - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -4189,43 +3077,15 @@ snapshots: client-only@0.0.1: {} - cliui@7.0.4: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 + clsx@2.1.1: {} - cliui@8.0.1: + color-convert@2.0.1: dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 + color-name: 1.1.4 - clsx@2.1.1: {} + color-name@1.1.4: {} - code-suggester@5.0.0: - dependencies: - '@octokit/rest': 20.1.2 - '@types/yargs': 16.0.9 - async-retry: 1.3.3 - diff: 5.2.0 - glob: 7.2.3 - parse-diff: 0.11.1 - yargs: 16.2.0 - - color-convert@1.9.3: - dependencies: - color-name: 1.1.3 - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.3: {} - - color-name@1.1.4: {} - - color-string@1.9.1: + color-string@1.9.1: dependencies: color-name: 1.1.4 simple-swizzle: 0.2.2 @@ -4237,32 +3097,8 @@ snapshots: color-string: 1.9.1 optional: true - compare-func@2.0.0: - dependencies: - array-ify: 1.0.0 - dot-prop: 5.3.0 - concat-map@0.0.1: {} - conventional-changelog-conventionalcommits@6.1.0: - dependencies: - compare-func: 2.0.0 - - conventional-changelog-writer@6.0.1: - dependencies: - conventional-commits-filter: 3.0.0 - dateformat: 3.0.3 - handlebars: 4.7.8 - json-stringify-safe: 5.0.1 - meow: 8.1.2 - semver: 7.7.2 - split: 1.0.1 - - conventional-commits-filter@3.0.0: - dependencies: - lodash.ismatch: 4.4.0 - modify-values: 1.0.1 - convert-source-map@2.0.0: {} cross-spawn@7.0.6: @@ -4271,16 +3107,6 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - css-select@5.2.2: - dependencies: - boolbase: 1.0.0 - css-what: 6.2.2 - domhandler: 5.0.3 - domutils: 3.2.2 - nth-check: 2.1.1 - - css-what@6.2.2: {} - csstype@3.1.3: {} data-view-buffer@1.0.2: @@ -4301,8 +3127,6 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.2 - dateformat@3.0.3: {} - debug@3.2.7: dependencies: ms: 2.1.3 @@ -4311,13 +3135,6 @@ snapshots: dependencies: ms: 2.1.3 - decamelize-keys@1.1.1: - dependencies: - decamelize: 1.2.0 - map-obj: 1.0.1 - - decamelize@1.2.0: {} - deep-is@0.1.4: {} define-data-property@1.1.4: @@ -4332,76 +3149,25 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 - deprecation@2.3.1: {} - - detect-indent@6.1.0: {} - detect-libc@2.0.4: {} - diff@5.2.0: {} - - diff@7.0.0: {} - - dir-glob@3.0.1: - dependencies: - path-type: 4.0.0 - doctrine@2.1.0: dependencies: esutils: 2.0.3 - doctrine@3.0.0: - dependencies: - esutils: 2.0.3 - - dom-serializer@2.0.0: - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - entities: 4.5.0 - - domelementtype@2.3.0: {} - - domhandler@5.0.3: - dependencies: - domelementtype: 2.3.0 - - domutils@3.2.2: - dependencies: - dom-serializer: 2.0.0 - domelementtype: 2.3.0 - domhandler: 5.0.3 - - dot-prop@5.3.0: - dependencies: - is-obj: 2.0.0 - dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 es-errors: 1.3.0 gopd: 1.2.0 - electron-to-chromium@1.5.194: {} - - emoji-regex@8.0.0: {} + electron-to-chromium@1.5.196: {} enhanced-resolve@5.18.2: dependencies: graceful-fs: 4.2.11 tapable: 2.2.2 - enquirer@2.4.1: - dependencies: - ansi-colors: 4.1.3 - strip-ansi: 6.0.1 - - entities@4.5.0: {} - - error-ex@1.3.2: - dependencies: - is-arrayish: 0.2.1 - es-abstract@1.24.0: dependencies: array-buffer-byte-length: 1.0.2 @@ -4515,8 +3281,6 @@ snapshots: escalade@3.2.0: {} - escape-string-regexp@1.0.5: {} - escape-string-regexp@4.0.0: {} eslint-compat-utils@0.5.1(eslint@9.32.0(jiti@2.5.1)): @@ -4532,11 +3296,10 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.32.0(jiti@2.5.1)): + eslint-module-utils@2.12.1(eslint-import-resolver-node@0.3.9)(eslint@9.32.0(jiti@2.5.1)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) eslint: 9.32.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: @@ -4549,7 +3312,7 @@ snapshots: eslint: 9.32.0(jiti@2.5.1) eslint-compat-utils: 0.5.1(eslint@9.32.0(jiti@2.5.1)) - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint@9.32.0(jiti@2.5.1)): + eslint-plugin-import@2.32.0(eslint@9.32.0(jiti@2.5.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -4560,7 +3323,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.32.0(jiti@2.5.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.32.0(jiti@2.5.1)) + eslint-module-utils: 2.12.1(eslint-import-resolver-node@0.3.9)(eslint@9.32.0(jiti@2.5.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -4571,8 +3334,6 @@ snapshots: semver: 6.3.1 string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 - optionalDependencies: - '@typescript-eslint/parser': 8.38.0(eslint@9.32.0(jiti@2.5.1))(typescript@5.9.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -4593,73 +3354,15 @@ snapshots: transitivePeerDependencies: - typescript - eslint-scope@5.1.1: - dependencies: - esrecurse: 4.3.0 - estraverse: 4.3.0 - eslint-scope@8.4.0: dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 - eslint-utils@2.1.0: - dependencies: - eslint-visitor-keys: 1.3.0 - - eslint-visitor-keys@1.3.0: {} - - eslint-visitor-keys@2.1.0: {} - eslint-visitor-keys@3.4.3: {} eslint-visitor-keys@4.2.1: {} - eslint@7.32.0: - dependencies: - '@babel/code-frame': 7.12.11 - '@eslint/eslintrc': 0.4.3 - '@humanwhocodes/config-array': 0.5.0 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.1 - doctrine: 3.0.0 - enquirer: 2.4.1 - escape-string-regexp: 4.0.0 - eslint-scope: 5.1.1 - eslint-utils: 2.1.0 - eslint-visitor-keys: 2.1.0 - espree: 7.3.1 - esquery: 1.6.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 - functional-red-black-tree: 1.0.1 - glob-parent: 5.1.2 - globals: 13.24.0 - ignore: 4.0.6 - import-fresh: 3.3.1 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - js-yaml: 3.14.1 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - progress: 2.0.3 - regexpp: 3.2.0 - semver: 7.7.2 - strip-ansi: 6.0.1 - strip-json-comments: 3.1.1 - table: 6.9.0 - text-table: 0.2.0 - v8-compile-cache: 2.4.0 - transitivePeerDependencies: - - supports-color - eslint@9.32.0(jiti@2.5.1): dependencies: '@eslint-community/eslint-utils': 4.7.0(eslint@9.32.0(jiti@2.5.1)) @@ -4708,14 +3411,6 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 4.2.1 - espree@7.3.1: - dependencies: - acorn: 7.4.1 - acorn-jsx: 5.3.2(acorn@7.4.1) - eslint-visitor-keys: 1.3.0 - - esprima@4.0.1: {} - esquery@1.6.0: dependencies: estraverse: 5.3.0 @@ -4724,8 +3419,6 @@ snapshots: dependencies: estraverse: 5.3.0 - estraverse@4.3.0: {} - estraverse@5.3.0: {} estree-walker@2.0.2: {} @@ -4750,20 +3443,10 @@ snapshots: fast-levenshtein@2.0.6: {} - fast-uri@3.0.6: {} - fastq@1.19.1: dependencies: reusify: 1.1.0 - figures@3.2.0: - dependencies: - escape-string-regexp: 1.0.5 - - file-entry-cache@6.0.1: - dependencies: - flat-cache: 3.2.0 - file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -4772,22 +3455,11 @@ snapshots: dependencies: to-regex-range: 5.0.1 - find-up@4.1.0: - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - find-up@5.0.0: dependencies: locate-path: 6.0.0 path-exists: 4.0.0 - flat-cache@3.2.0: - dependencies: - flatted: 3.3.3 - keyv: 4.5.4 - rimraf: 3.0.2 - flat-cache@4.0.1: dependencies: flatted: 3.3.3 @@ -4808,8 +3480,6 @@ snapshots: react: 19.1.1 react-dom: 19.1.1(react@19.1.1) - fs.realpath@1.0.0: {} - fsevents@2.3.2: optional: true @@ -4827,14 +3497,10 @@ snapshots: hasown: 2.0.2 is-callable: 1.2.7 - functional-red-black-tree@1.0.1: {} - functions-have-names@1.2.3: {} gensync@1.0.0-beta.2: {} - get-caller-file@2.0.5: {} - get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -4871,19 +3537,6 @@ snapshots: dependencies: is-glob: 4.0.3 - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - - globals@13.24.0: - dependencies: - type-fest: 0.20.2 - globals@14.0.0: {} globals@15.15.0: {} @@ -4893,38 +3546,14 @@ snapshots: define-properties: 1.2.1 gopd: 1.2.0 - globby@11.1.0: - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.3 - ignore: 5.3.2 - merge2: 1.4.1 - slash: 3.0.0 - globrex@0.1.2: {} gopd@1.2.0: {} graceful-fs@4.2.11: {} - graphemer@1.4.0: {} - - handlebars@4.7.8: - dependencies: - minimist: 1.2.8 - neo-async: 2.6.2 - source-map: 0.6.1 - wordwrap: 1.0.0 - optionalDependencies: - uglify-js: 3.19.3 - - hard-rejection@2.1.0: {} - has-bigints@1.1.0: {} - has-flag@3.0.0: {} - has-flag@4.0.0: {} has-property-descriptors@1.0.2: @@ -4945,34 +3574,8 @@ snapshots: dependencies: function-bind: 1.1.2 - he@1.2.0: {} - - hosted-git-info@2.8.9: {} - - hosted-git-info@4.1.0: - dependencies: - lru-cache: 6.0.0 - - http-proxy-agent@7.0.2: - dependencies: - agent-base: 7.1.4 - debug: 4.4.1 - transitivePeerDependencies: - - supports-color - - https-proxy-agent@7.0.6: - dependencies: - agent-base: 7.1.4 - debug: 4.4.1 - transitivePeerDependencies: - - supports-color - - ignore@4.0.6: {} - ignore@5.3.2: {} - ignore@7.0.5: {} - import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -4980,15 +3583,6 @@ snapshots: imurmurhash@0.1.4: {} - indent-string@4.0.0: {} - - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - - inherits@2.0.4: {} - internal-slot@1.1.0: dependencies: es-errors: 1.3.0 @@ -5001,8 +3595,6 @@ snapshots: call-bound: 1.0.4 get-intrinsic: 1.3.0 - is-arrayish@0.2.1: {} - is-arrayish@0.3.2: optional: true @@ -5046,8 +3638,6 @@ snapshots: dependencies: call-bound: 1.0.4 - is-fullwidth-code-point@3.0.0: {} - is-generator-function@1.1.0: dependencies: call-bound: 1.0.4 @@ -5070,10 +3660,6 @@ snapshots: is-number@7.0.0: {} - is-obj@2.0.0: {} - - is-plain-obj@1.1.0: {} - is-regex@1.2.1: dependencies: call-bound: 1.0.4 @@ -5121,49 +3707,28 @@ snapshots: js-tokens@4.0.0: {} - js-yaml@3.14.1: - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - js-yaml@4.1.0: dependencies: argparse: 2.0.1 - jsep@1.4.0: {} - jsesc@3.1.0: {} json-buffer@3.0.1: {} - json-parse-even-better-errors@2.3.1: {} - json-schema-traverse@0.4.1: {} - json-schema-traverse@1.0.0: {} - json-stable-stringify-without-jsonify@1.0.1: {} - json-stringify-safe@5.0.1: {} - json5@1.0.2: dependencies: minimist: 1.2.8 json5@2.2.3: {} - jsonpath-plus@10.3.0: - dependencies: - '@jsep-plugin/assignment': 1.3.0(jsep@1.4.0) - '@jsep-plugin/regex': 1.0.4(jsep@1.4.0) - jsep: 1.4.0 - keyv@4.5.4: dependencies: json-buffer: 3.0.1 - kind-of@6.0.3: {} - kleur@4.1.5: {} levn@0.4.1: @@ -5216,56 +3781,24 @@ snapshots: lightningcss-win32-arm64-msvc: 1.30.1 lightningcss-win32-x64-msvc: 1.30.1 - lines-and-columns@1.2.4: {} - - locate-path@5.0.0: - dependencies: - p-locate: 4.1.0 - locate-path@6.0.0: dependencies: p-locate: 5.0.0 - lodash.ismatch@4.4.0: {} - lodash.merge@4.6.2: {} - lodash.truncate@4.4.2: {} - lru-cache@11.1.0: {} lru-cache@5.1.1: dependencies: yallist: 3.1.1 - lru-cache@6.0.0: - dependencies: - yallist: 4.0.0 - magic-string@0.30.17: dependencies: '@jridgewell/sourcemap-codec': 1.5.4 - map-obj@1.0.1: {} - - map-obj@4.3.0: {} - math-intrinsics@1.1.0: {} - meow@8.1.2: - dependencies: - '@types/minimist': 1.2.5 - camelcase-keys: 6.2.2 - decamelize-keys: 1.1.1 - hard-rejection: 2.1.0 - minimist-options: 4.1.0 - normalize-package-data: 3.0.3 - read-pkg-up: 7.0.1 - redent: 3.0.0 - trim-newlines: 3.0.1 - type-fest: 0.18.1 - yargs-parser: 20.2.9 - merge2@1.4.1: {} micromatch@4.0.8: @@ -5273,30 +3806,14 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 - min-indent@1.0.1: {} - minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 - minimatch@5.1.6: - dependencies: - brace-expansion: 2.0.2 - - minimatch@9.0.3: - dependencies: - brace-expansion: 2.0.2 - minimatch@9.0.5: dependencies: brace-expansion: 2.0.2 - minimist-options@4.1.0: - dependencies: - arrify: 1.0.1 - is-plain-obj: 1.1.0 - kind-of: 6.0.3 - minimist@1.2.8: {} minipass@7.1.2: {} @@ -5307,8 +3824,6 @@ snapshots: mkdirp@3.0.1: {} - modify-values@1.0.1: {} - motion-dom@12.23.12: dependencies: motion-utils: 12.23.6 @@ -5331,8 +3846,6 @@ snapshots: natural-compare@1.4.0: {} - neo-async@2.6.2: {} - next@15.4.5(@babel/core@7.28.0)(@playwright/test@1.54.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1): dependencies: '@next/env': 15.4.5 @@ -5357,31 +3870,8 @@ snapshots: - '@babel/core' - babel-plugin-macros - node-html-parser@6.1.13: - dependencies: - css-select: 5.2.2 - he: 1.2.0 - node-releases@2.0.19: {} - normalize-package-data@2.5.0: - dependencies: - hosted-git-info: 2.8.9 - resolve: 1.22.10 - semver: 5.7.2 - validate-npm-package-license: 3.0.4 - - normalize-package-data@3.0.3: - dependencies: - hosted-git-info: 4.1.0 - is-core-module: 2.16.1 - semver: 7.7.2 - validate-npm-package-license: 3.0.4 - - nth-check@2.1.1: - dependencies: - boolbase: 1.0.0 - object-inspect@1.13.4: {} object-keys@1.1.1: {} @@ -5415,10 +3905,6 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 - once@1.4.0: - dependencies: - wrappy: 1.0.2 - optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -5434,49 +3920,24 @@ snapshots: object-keys: 1.1.1 safe-push-apply: 1.0.0 - p-limit@2.3.0: - dependencies: - p-try: 2.2.0 - p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 - p-locate@4.1.0: - dependencies: - p-limit: 2.3.0 - p-locate@5.0.0: dependencies: p-limit: 3.1.0 - p-try@2.2.0: {} - parent-module@1.0.1: dependencies: callsites: 3.1.0 - parse-diff@0.11.1: {} - - parse-github-repo-url@1.4.1: {} - - parse-json@5.2.0: - dependencies: - '@babel/code-frame': 7.27.1 - error-ex: 1.3.2 - json-parse-even-better-errors: 2.3.1 - lines-and-columns: 1.2.4 - path-exists@4.0.0: {} - path-is-absolute@1.0.1: {} - path-key@3.1.1: {} path-parse@1.0.7: {} - path-type@4.0.0: {} - picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -5511,14 +3972,10 @@ snapshots: prettier@3.6.2: {} - progress@2.0.3: {} - punycode@2.3.1: {} queue-microtask@1.2.3: {} - quick-lru@4.0.1: {} - react-dom@19.1.1(react@19.1.1): dependencies: react: 19.1.1 @@ -5555,24 +4012,6 @@ snapshots: react@19.1.1: {} - read-pkg-up@7.0.1: - dependencies: - find-up: 4.1.0 - read-pkg: 5.2.0 - type-fest: 0.8.1 - - read-pkg@5.2.0: - dependencies: - '@types/normalize-package-data': 2.4.4 - normalize-package-data: 2.5.0 - parse-json: 5.2.0 - type-fest: 0.6.0 - - redent@3.0.0: - dependencies: - indent-string: 4.0.0 - strip-indent: 3.0.0 - reflect.getprototypeof@1.0.10: dependencies: call-bind: 1.0.8 @@ -5593,48 +4032,6 @@ snapshots: gopd: 1.2.0 set-function-name: 2.0.2 - regexpp@3.2.0: {} - - release-please@17.1.1: - dependencies: - '@conventional-commits/parser': 0.4.1 - '@google-automations/git-file-utils': 3.0.0 - '@iarna/toml': 3.0.0 - '@octokit/graphql': 7.1.1 - '@octokit/request': 8.4.1 - '@octokit/request-error': 5.1.1 - '@octokit/rest': 20.1.2 - '@types/npm-package-arg': 6.1.4 - '@xmldom/xmldom': 0.8.10 - chalk: 4.1.2 - code-suggester: 5.0.0 - conventional-changelog-conventionalcommits: 6.1.0 - conventional-changelog-writer: 6.0.1 - conventional-commits-filter: 3.0.0 - detect-indent: 6.1.0 - diff: 7.0.0 - figures: 3.2.0 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 - js-yaml: 4.1.0 - jsonpath-plus: 10.3.0 - node-html-parser: 6.1.13 - parse-github-repo-url: 1.4.1 - semver: 7.7.2 - type-fest: 3.13.1 - typescript: 4.9.5 - unist-util-visit: 2.0.3 - unist-util-visit-parents: 3.1.1 - xpath: 0.0.34 - yaml: 2.8.0 - yargs: 17.7.2 - transitivePeerDependencies: - - supports-color - - require-directory@2.1.1: {} - - require-from-string@2.0.2: {} - resolve-from@4.0.0: {} resolve-pkg-maps@1.0.0: {} @@ -5645,14 +4042,8 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - retry@0.13.1: {} - reusify@1.1.0: {} - rimraf@3.0.2: - dependencies: - glob: 7.2.3 - rollup@4.46.2: dependencies: '@types/estree': 1.0.8 @@ -5705,8 +4096,6 @@ snapshots: scheduler@0.26.0: {} - semver@5.7.2: {} - semver@6.3.1: {} semver@7.7.2: {} @@ -5804,49 +4193,13 @@ snapshots: sisteransi@1.0.5: {} - slash@3.0.0: {} - - slice-ansi@4.0.0: - dependencies: - ansi-styles: 4.3.0 - astral-regex: 2.0.0 - is-fullwidth-code-point: 3.0.0 - source-map-js@1.2.1: {} - source-map@0.6.1: {} - - spdx-correct@3.2.0: - dependencies: - spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.21 - - spdx-exceptions@2.5.0: {} - - spdx-expression-parse@3.0.1: - dependencies: - spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.21 - - spdx-license-ids@3.0.21: {} - - split@1.0.1: - dependencies: - through: 2.3.8 - - sprintf-js@1.0.3: {} - stop-iteration-iterator@1.1.0: dependencies: es-errors: 1.3.0 internal-slot: 1.1.0 - string-width@4.2.3: - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - string.prototype.trim@1.2.10: dependencies: call-bind: 1.0.8 @@ -5870,16 +4223,8 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - strip-bom@3.0.0: {} - strip-indent@3.0.0: - dependencies: - min-indent: 1.0.1 - strip-json-comments@3.1.1: {} styled-jsx@5.1.6(@babel/core@7.28.0)(react@19.1.1): @@ -5889,24 +4234,12 @@ snapshots: optionalDependencies: '@babel/core': 7.28.0 - supports-color@5.5.0: - dependencies: - has-flag: 3.0.0 - supports-color@7.2.0: dependencies: has-flag: 4.0.0 supports-preserve-symlinks-flag@1.0.0: {} - table@6.9.0: - dependencies: - ajv: 8.17.1 - lodash.truncate: 4.4.2 - slice-ansi: 4.0.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - tailwindcss@4.1.11: {} tapable@2.2.2: {} @@ -5920,20 +4253,10 @@ snapshots: mkdirp: 3.0.1 yallist: 5.0.0 - text-table@0.2.0: {} - - through@2.3.8: {} - to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - trim-newlines@3.0.1: {} - - ts-api-utils@1.4.3(typescript@5.9.2): - dependencies: - typescript: 5.9.2 - ts-api-utils@2.1.0(typescript@5.9.2): dependencies: typescript: 5.9.2 @@ -5963,16 +4286,6 @@ snapshots: dependencies: prelude-ls: 1.2.1 - type-fest@0.18.1: {} - - type-fest@0.20.2: {} - - type-fest@0.6.0: {} - - type-fest@0.8.1: {} - - type-fest@3.13.1: {} - typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.4 @@ -6006,13 +4319,8 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typescript@4.9.5: {} - typescript@5.9.2: {} - uglify-js@3.19.3: - optional: true - unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 @@ -6022,22 +4330,7 @@ snapshots: undici-types@6.21.0: {} - undici-types@7.8.0: {} - - unist-util-is@4.1.0: {} - - unist-util-visit-parents@3.1.1: - dependencies: - '@types/unist': 2.0.11 - unist-util-is: 4.1.0 - - unist-util-visit@2.0.3: - dependencies: - '@types/unist': 2.0.11 - unist-util-is: 4.1.0 - unist-util-visit-parents: 3.1.1 - - universal-user-agent@6.0.1: {} + undici-types@7.10.0: {} unplugin@2.1.0: dependencies: @@ -6055,13 +4348,6 @@ snapshots: dependencies: punycode: 2.3.1 - v8-compile-cache@2.4.0: {} - - validate-npm-package-license@3.0.4: - dependencies: - spdx-correct: 3.2.0 - spdx-expression-parse: 3.0.1 - webpack-virtual-modules@0.6.2: optional: true @@ -6112,50 +4398,8 @@ snapshots: word-wrap@1.2.5: {} - wordwrap@1.0.0: {} - - wrap-ansi@7.0.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - wrappy@1.0.2: {} - - xpath@0.0.34: {} - - y18n@5.0.8: {} - yallist@3.1.1: {} - yallist@4.0.0: {} - yallist@5.0.0: {} - yaml@2.8.0: {} - - yargs-parser@20.2.9: {} - - yargs-parser@21.1.1: {} - - yargs@16.2.0: - dependencies: - cliui: 7.0.4 - escalade: 3.2.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 20.2.9 - - yargs@17.7.2: - dependencies: - cliui: 8.0.1 - escalade: 3.2.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 21.1.1 - yocto-queue@0.1.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 5ff0745..be4cf04 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -5,3 +5,9 @@ packages: onlyBuiltDependencies: - '@tailwindcss/oxide' - sharp + +strictPeerDependencies: true + +publicHoistPattern: + - '*eslint*' + - '*typescript*' diff --git a/scripts/install-local-tarball.js b/scripts/install-local-tarball.js index 1c52f39..ecebb46 100644 --- a/scripts/install-local-tarball.js +++ b/scripts/install-local-tarball.js @@ -7,11 +7,7 @@ const pkg = readdirSync(dist) .filter((f) => f.endsWith('.tgz')) .sort((a, b) => statSync(join(dist, b)).mtimeMs - statSync(join(dist, a)).mtimeMs)[0]; -const fixtures = [ - 'packages/core/__tests__/fixtures/next', - 'packages/core/__tests__/fixtures/vite', - 'packages/eslint-plugin-react-zero-ui/__tests__/fixtures/next', -]; +const fixtures = ['packages/core/__tests__/fixtures/next', 'packages/core/__tests__/fixtures/vite']; for (const dir of fixtures) { const pkgJson = join(dir, 'package.json');