diff --git a/.changeset/config.json b/.changeset/config.json index 5a28f58..ff507b2 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -2,7 +2,7 @@ "$schema": "https://unpkg.com/@changesets/config@3.0.2/schema.json", "changelog": "@changesets/cli/changelog", "commit": false, - "fixed": [["ruru-ui"]], + "fixed": [["ruru-ui"], ["ruru-ui-cli"]], "linked": [], "access": "restricted", "baseBranch": "main", diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 803fbd4..eab20d2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,12 +30,6 @@ jobs: - name: Lint Format run: pnpm lint:prettier - - name: Check Types - run: pnpm build --filter=./packages/* - - - name: Run ESLint - run: pnpm lint --filter=./packages/* - # This workflow contains a single job called "build" build: runs-on: ubuntu-latest @@ -55,4 +49,4 @@ jobs: run: pnpm i --frozen-lockfile - name: Build Check - run: pnpm build + run: pnpm build --filter=./packages/* diff --git a/.husky/pre-commit b/.husky/pre-commit index 3b62b0e..9928bf8 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1 +1 @@ -pnpm prettier \ No newline at end of file +pnpm run --filter=./apps/www build:registry && pnpm prettier diff --git a/.prettierignore b/.prettierignore index 7494207..3b5ac43 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,3 +2,5 @@ pnpm-lock.yaml .github/**/*.md .content-collections/**/* + +**/*.mdx \ No newline at end of file diff --git a/apps/www/.prettierignore b/apps/www/.prettierignore new file mode 100644 index 0000000..6e1fb3a --- /dev/null +++ b/apps/www/.prettierignore @@ -0,0 +1 @@ +**/*.mdx \ No newline at end of file diff --git a/apps/www/__registry__/index.tsx b/apps/www/__registry__/index.tsx new file mode 100644 index 0000000..279f4ef --- /dev/null +++ b/apps/www/__registry__/index.tsx @@ -0,0 +1,129 @@ +// @ts-nocheck +// This file is autogenerated by scripts/build-registry.ts +// Do not edit this file directly. +import * as React from "react"; + +export const Index: Record = { + components: { + avatar: { + name: "avatar", + type: "components:ui", + registryDependencies: undefined, + component: React.lazy( + () => import("@/../../packages/ui/src/components/avatar"), + ), + source: "", + files: ["@/../../packages/ui/src/components/avatar.tsx"], + category: "undefined", + subcategory: undefined, + }, + badge: { + name: "badge", + type: "components:ui", + registryDependencies: undefined, + component: React.lazy( + () => import("@/../../packages/ui/src/components/badge"), + ), + source: "", + files: ["@/../../packages/ui/src/components/badge.tsx"], + category: "undefined", + subcategory: undefined, + }, + button: { + name: "button", + type: "components:ui", + registryDependencies: undefined, + component: React.lazy( + () => import("@/../../packages/ui/src/components/button"), + ), + source: "", + files: ["@/../../packages/ui/src/components/button.tsx"], + category: "undefined", + subcategory: ["spinner"], + }, + checkbox: { + name: "checkbox", + type: "components:ui", + registryDependencies: undefined, + component: React.lazy( + () => import("@/../../packages/ui/src/components/checkbox"), + ), + source: "", + files: ["@/../../packages/ui/src/components/checkbox.tsx"], + category: "undefined", + subcategory: undefined, + }, + input: { + name: "input", + type: "components:ui", + registryDependencies: undefined, + component: React.lazy( + () => import("@/../../packages/ui/src/components/input"), + ), + source: "", + files: ["@/../../packages/ui/src/components/input.tsx"], + category: "undefined", + subcategory: undefined, + }, + select: { + name: "select", + type: "components:ui", + registryDependencies: undefined, + component: React.lazy( + () => import("@/../../packages/ui/src/components/select"), + ), + source: "", + files: ["@/../../packages/ui/src/components/select.tsx"], + category: "undefined", + subcategory: undefined, + }, + spinner: { + name: "spinner", + type: "components:ui", + registryDependencies: undefined, + component: React.lazy( + () => import("@/../../packages/ui/src/components/spinner"), + ), + source: "", + files: ["@/../../packages/ui/src/components/spinner.tsx"], + category: "undefined", + subcategory: undefined, + }, + switch: { + name: "switch", + type: "components:ui", + registryDependencies: undefined, + component: React.lazy( + () => import("@/../../packages/ui/src/components/switch"), + ), + source: "", + files: ["@/../../packages/ui/src/components/switch.tsx"], + category: "undefined", + subcategory: undefined, + }, + textarea: { + name: "textarea", + type: "components:ui", + registryDependencies: undefined, + component: React.lazy( + () => import("@/../../packages/ui/src/components/textarea"), + ), + source: "", + files: ["@/../../packages/ui/src/components/textarea.tsx"], + category: "undefined", + subcategory: undefined, + }, + tooltip: { + name: "tooltip", + type: "components:ui", + registryDependencies: undefined, + component: React.lazy( + () => import("@/../../packages/ui/src/components/tooltip"), + ), + source: "", + files: ["@/../../packages/ui/src/components/tooltip.tsx"], + category: "undefined", + subcategory: undefined, + }, + }, +}; diff --git a/apps/www/components/hero.tsx b/apps/www/components/hero.tsx index d79bf27..1f4de3d 100644 --- a/apps/www/components/hero.tsx +++ b/apps/www/components/hero.tsx @@ -1,6 +1,9 @@ +"use client"; + import React from "react"; import { GitHubLogoIcon } from "@radix-ui/react-icons"; import Link from "next/link"; +import { buttonVariants } from "ruru-ui/components/button"; const Hero = () => { return ( @@ -87,9 +90,9 @@ const Hero = () => { Give a star diff --git a/apps/www/components/preview/wrapper.tsx b/apps/www/components/preview/wrapper.tsx index b1740e8..23b195e 100644 --- a/apps/www/components/preview/wrapper.tsx +++ b/apps/www/components/preview/wrapper.tsx @@ -8,7 +8,7 @@ export function Wrapper(
diff --git a/apps/www/content/docs/cli.mdx b/apps/www/content/docs/cli.mdx new file mode 100644 index 0000000..db4caca --- /dev/null +++ b/apps/www/content/docs/cli.mdx @@ -0,0 +1,122 @@ +--- +title: Cli +description: The CLI is a command-line interface that allows you to add components to your project. +--- + +import { Tabs, Tab } from "fumadocs-ui/components/tabs"; + +## init + +Use the `init` command to initialize dependencies for a new project. + +The `init`, and CSS variables for the project. + + + +```bash +npx ruru-ui-cli@latest init +``` + + +```bash +pnpm dlx ruru-ui-cli@latest init +``` + + +```bash +npx ruru-ui@latest init +``` + + +```bash +bunx --bun ruru-ui@latest init +``` + + + + + ```txt + +◇ Would you like to use TypeScript (recommended)? Yes +◇ use default configuration. No +◇ Where is your global CSS file? ./app/globals.css +◇ Where is your tailwind.config.js located? ./tailwind.config.js +◇ Would you like to use CSS variables for colors? Yes +◇ Are you using a custom tailwind prefix eg. tw-? (Leave blank if not) (Leave blank if not) +◇ Configure the import alias for components: @/components/ui +◇ Configure the import alias for utils: @/lib/utils +◇ Would you like to use RSC ? Yes +◇ Write configuration to components.json. Proceed? Yes + + ``` + +### Options + +The `init` command supports the following options: + +```txt +Usage: Ruru-UI init [options] + +initialize your project and install dependencies + +Options: + -y, --yes skip confirmation prompt. (default: false) + -d, --defaults use default configuration. (default: false) + -a, --autodetact autodetact configuration by freamwork. (default: false) + -c, --cwd the working directory. defaults to the current directory. + (default: "D:\\GitHub\\ruru-ui\\apps\\sink") + -h, --help display help for command +``` + + +## add + +Use the `add` command to add components to your project. + +The `add` command adds a component to your project and installs all required dependencies. + + + +```bash +npx ruru-ui-cli@latest add [component] +``` + + +```bash +pnpm dlx ruru-ui-cli@latest add [component] +``` + + +```bash +npx ruru-ui@latest add [component] +``` + + +```bash +bunx --bun ruru-ui@latest add [component] +``` + + + +### Options + +The `add` command supports the following options: + +```txt +Usage: Ruru-UI add [options] [components...] + +add a component to your project + +Arguments: + components the components to add + +Options: + -y, --yes skip confirmation prompt. (default: true) + -o, --overwrite overwrite existing files. (default: false) + -c, --cwd the working directory. defaults to the current + directory. (default: "D:\\GitHub\\ruru-ui\\apps\\sink") + -a, --all add all available components (default: false) + -p, --path the path to add the component to. + -h, --help display help for command +``` + diff --git a/apps/www/content/docs/components/avatar.mdx b/apps/www/content/docs/components/avatar.mdx index cb7df5d..7a0e593 100644 --- a/apps/www/content/docs/components/avatar.mdx +++ b/apps/www/content/docs/components/avatar.mdx @@ -10,6 +10,42 @@ import { AvatarWithBadge, } from "ruru-ui/components/avatar"; import { Tab, Tabs } from "fumadocs-ui/components/tabs"; +import { Tabs as Rutabs, Tab as Rutab } from "ruru-ui/components/tabs"; + +## Installation + + + + + + ```bash + npx ruru-ui-cli@latest add avatar + ``` + + + ```bash + pnpm dlx ruru-ui-cli@latest add avatar + ``` + + + ```bash + npx ruru-ui@latest add avatar + ``` + + + ```bash + bunx --bun ruru-ui@latest add avatar + ``` + + + + + + ```package-install + npm install ruru-ui@latest + ``` + + ## Usage @@ -42,11 +78,11 @@ The `Avatar` component is used to represent a user or entity. return (
diff --git a/apps/www/content/docs/components/badge.mdx b/apps/www/content/docs/components/badge.mdx index 37f310f..b45f31b 100644 --- a/apps/www/content/docs/components/badge.mdx +++ b/apps/www/content/docs/components/badge.mdx @@ -7,6 +7,44 @@ preview: badge import { Badge } from "ruru-ui/components/badge"; import { Tab, Tabs } from "fumadocs-ui/components/tabs"; import { CubeIcon } from "@radix-ui/react-icons"; +import { Tabs as Rutabs, Tab as Rutab } from "ruru-ui/components/tabs"; + +## Installation + + + + + + ```bash + npx ruru-ui-cli@latest add badge + ``` + + + ```bash + pnpm dlx ruru-ui-cli@latest add badge + ``` + + + ```bash + npx ruru-ui@latest add badge + ``` + + + ```bash + bunx --bun ruru-ui@latest add badge + ``` + + + + + + + ```package-install + npm install ruru-ui@latest + ``` + + + ## Usage diff --git a/apps/www/content/docs/components/button.mdx b/apps/www/content/docs/components/button.mdx index 900c81c..3129cc7 100644 --- a/apps/www/content/docs/components/button.mdx +++ b/apps/www/content/docs/components/button.mdx @@ -12,6 +12,44 @@ import { ChevronRightIcon, } from "@radix-ui/react-icons"; import Link from "next/link"; +import { Tabs as Rutabs, Tab as Rutab } from "ruru-ui/components/tabs"; + +## Installation + + + + + + ```bash + npx ruru-ui-cli@latest add button + ``` + + + ```bash + pnpm dlx ruru-ui-cli@latest add button + ``` + + + ```bash + npx ruru-ui@latest add button + ``` + + + ```bash + bunx --bun ruru-ui@latest add button + ``` + + + + + + + ```package-install + npm install ruru-ui@latest + ``` + + + ## Usage @@ -39,13 +77,15 @@ import Link from "next/link"; --- -You can use the `buttonVariants` helper to create a link that looks like a button. +You can use the `buttonVariants` helper to create a link that looks like a button. You can't use buttonVariants in RSC. ```tsx +// [!code word:buttonVariants] import { buttonVariants } from "ruru-ui/components/button"; ``` ```tsx +// [!code word:buttonVariants] Click here @@ -54,6 +94,7 @@ import { buttonVariants } from "ruru-ui/components/button"; Alternatively, you can set the `asChild` parameter and nest the link component. ```tsx +// [!code word:asChild] diff --git a/apps/www/content/docs/components/checkbox.mdx b/apps/www/content/docs/components/checkbox.mdx index 1cc75cf..c9b333e 100644 --- a/apps/www/content/docs/components/checkbox.mdx +++ b/apps/www/content/docs/components/checkbox.mdx @@ -6,6 +6,45 @@ preview: checkbox import { Tab, Tabs } from "fumadocs-ui/components/tabs"; import { Checkbox } from "ruru-ui/components/checkbox"; +import { Tabs as Rutabs, Tab as Rutab } from "ruru-ui/components/tabs"; + +## Installation + + + + + + + ```bash + npx ruru-ui-cli@latest add checkbox + ``` + + + ```bash + pnpm dlx ruru-ui-cli@latest add checkbox + ``` + + + ```bash + npx ruru-ui@latest add checkbox + ``` + + + ```bash + bunx --bun ruru-ui@latest add checkbox + ``` + + + + + + + ```package-install + npm install ruru-ui@latest + ``` + + + ## Usage diff --git a/apps/www/content/docs/components/input.mdx b/apps/www/content/docs/components/input.mdx index e088740..582d4e1 100644 --- a/apps/www/content/docs/components/input.mdx +++ b/apps/www/content/docs/components/input.mdx @@ -6,6 +6,45 @@ preview: input import { Input, SearchInput } from "ruru-ui/components/input"; import { Tab, Tabs } from "fumadocs-ui/components/tabs"; +import { Tabs as Rutabs, Tab as Rutab } from "ruru-ui/components/tabs"; + +## Installation + + + + + + + ```bash + npx ruru-ui-cli@latest add input + ``` + + + ```bash + pnpm dlx ruru-ui-cli@latest add input + ``` + + + ```bash + npx ruru-ui@latest add input + ``` + + + ```bash + bunx --bun ruru-ui@latest add input + ``` + + + + + + + ```package-install + npm install ruru-ui@latest + ``` + + + ## Usage diff --git a/apps/www/content/docs/components/select.mdx b/apps/www/content/docs/components/select.mdx index b53a36a..e3e473c 100644 --- a/apps/www/content/docs/components/select.mdx +++ b/apps/www/content/docs/components/select.mdx @@ -18,6 +18,44 @@ import { SelectScrollUpButton, SelectScrollDownButton, } from "ruru-ui/components/select"; +import { Tabs as Rutabs, Tab as Rutab } from "ruru-ui/components/tabs"; + +## Installation + + + + + + ```bash + npx ruru-ui-cli@latest add select + ``` + + + ```bash + pnpm dlx ruru-ui-cli@latest add select + ``` + + + ```bash + npx ruru-ui@latest add select + ``` + + + ```bash + bunx --bun ruru-ui@latest add select + ``` + + + + + + + ```package-install + npm install ruru-ui@latest + ``` + + + ## Usage diff --git a/apps/www/content/docs/components/spinner.mdx b/apps/www/content/docs/components/spinner.mdx index ddff00d..723d7bf 100644 --- a/apps/www/content/docs/components/spinner.mdx +++ b/apps/www/content/docs/components/spinner.mdx @@ -6,6 +6,44 @@ preview: spinner import { Spinner } from "ruru-ui/components/spinner"; import { Tab, Tabs } from "fumadocs-ui/components/tabs"; +import { Tabs as Rutabs, Tab as Rutab } from "ruru-ui/components/tabs"; + +## Installation + + + + + + ```bash + npx ruru-ui-cli@latest add spinner + ``` + + + ```bash + pnpm dlx ruru-ui-cli@latest add spinner + ``` + + + ```bash + npx ruru-ui@latest add spinner + ``` + + + ```bash + bunx --bun ruru-ui@latest add spinner + ``` + + + + + + + ```package-install + npm install ruru-ui@latest + ``` + + + ## Usage diff --git a/apps/www/content/docs/components/switch.mdx b/apps/www/content/docs/components/switch.mdx index 06aa711..fb25d76 100644 --- a/apps/www/content/docs/components/switch.mdx +++ b/apps/www/content/docs/components/switch.mdx @@ -6,6 +6,45 @@ preview: switch import { Tabs, Tab } from "fumadocs-ui/components/tabs"; import { Switch } from "ruru-ui/components/switch"; +import { Tabs as Rutabs, Tab as Rutab } from "ruru-ui/components/tabs"; + +## Installation + + + + + + + ```bash + npx ruru-ui-cli@latest add switch + ``` + + + ```bash + pnpm dlx ruru-ui-cli@latest add switch + ``` + + + ```bash + npx ruru-ui@latest add switch + ``` + + + ```bash + bunx --bun ruru-ui@latest add switch + ``` + + + + + + + ```package-install + npm install ruru-ui@latest + ``` + + + ## Usage diff --git a/apps/www/content/docs/components/tabs.mdx b/apps/www/content/docs/components/tabs.mdx index 3fcda58..a01d37c 100644 --- a/apps/www/content/docs/components/tabs.mdx +++ b/apps/www/content/docs/components/tabs.mdx @@ -7,6 +7,43 @@ preview: tabs import { Tabs as Rutabs, Tab as Rutab } from "ruru-ui/components/tabs"; import { Tabs, Tab } from "fumadocs-ui/components/tabs"; +## Installation + + + + + + ```bash + npx ruru-ui-cli@latest add tabs + ``` + + + ```bash + pnpm dlx ruru-ui-cli@latest add tabs + ``` + + + ```bash + npx ruru-ui@latest add tabs + ``` + + + ```bash + bunx --bun ruru-ui@latest add tabs + ``` + + + + + + + ```package-install + npm install ruru-ui@latest + ``` + + + + ## Usage diff --git a/apps/www/content/docs/components/textarea.mdx b/apps/www/content/docs/components/textarea.mdx index 0468acb..81daa43 100644 --- a/apps/www/content/docs/components/textarea.mdx +++ b/apps/www/content/docs/components/textarea.mdx @@ -6,6 +6,44 @@ preview: textarea import { Textarea } from "ruru-ui/components/textarea"; import { Tab, Tabs } from "fumadocs-ui/components/tabs"; +import { Tabs as Rutabs, Tab as Rutab } from "ruru-ui/components/tabs"; + +## Installation + + + + + + ```bash + npx ruru-ui-cli@latest add textarea + ``` + + + ```bash + pnpm dlx ruru-ui-cli@latest add textarea + ``` + + + ```bash + npx ruru-ui@latest add textarea + ``` + + + ```bash + bunx --bun ruru-ui@latest add textarea + ``` + + + + + + + ```package-install + npm install ruru-ui@latest + ``` + + + ## Usage diff --git a/apps/www/content/docs/components/tooltip.mdx b/apps/www/content/docs/components/tooltip.mdx index a45c38c..2e047e4 100644 --- a/apps/www/content/docs/components/tooltip.mdx +++ b/apps/www/content/docs/components/tooltip.mdx @@ -12,6 +12,45 @@ import { TooltipTrigger, } from "ruru-ui/components/tooltip"; import { Button } from "ruru-ui/components/button"; +import { Tabs as Rutabs, Tab as Rutab } from "ruru-ui/components/tabs"; + +## Installation + + + + + + + ```bash + npx ruru-ui-cli@latest add tooltip + ``` + + + ```bash + pnpm dlx ruru-ui-cli@latest add tooltip + ``` + + + ```bash + npx ruru-ui@latest add tooltip + ``` + + + ```bash + bunx --bun ruru-ui@latest add tooltip + ``` + + + + + + + ```package-install + npm install ruru-ui@latest + ``` + + + ## Usage @@ -50,7 +89,7 @@ import { Button } from "ruru-ui/components/button"; - + Tooltip content here diff --git a/apps/www/content/docs/index.mdx b/apps/www/content/docs/index.mdx index 8f09202..3c67eed 100644 --- a/apps/www/content/docs/index.mdx +++ b/apps/www/content/docs/index.mdx @@ -1,38 +1,71 @@ --- -title: Introduction -description: Welcome to ruru UI, a modern and flexible UI library designed to help you build beautiful, responsive, and accessible web applications with ease. +title: Quick Start +description: Getting Started with Ruru-UI. --- -# Welcome to ruru UI +import { Accordion, Accordions } from 'fumadocs-ui/components/accordion'; +import Link from 'fumadocs-core/link'; -Welcome to **ruru UI**, a modern and flexible UI library designed to help you build beautiful, responsive, and accessible web applications with ease. +## Introduction -## Why ruru UI? +Welcome to **ruru UI**, a comprehensive UI library and a set of reusable components designed to help you build beautiful and consistent user interfaces with ease. -### **Modern Design** +## Terminology -**ruru UI** offers a sleek and contemporary design that ensures your application looks great on all devices. Our components are crafted with attention to detail, following the latest design trends and best practices. +- **Component**: A reusable piece of UI that can be used across different parts of your application. +- **Props**: Properties passed to components to customize their appearance and behavior. +- **State**: Data managed within a component that affects its rendering and behavior. -### **Developer Friendly** +## FAQ -We believe that building beautiful interfaces should be a joy, not a hassle. **ruru UI** is built with developers in mind, offering a simple API, thorough documentation, and plenty of examples to help you get started quickly. +Some common questions you may encounter: -### **Accessibility First** + + + **ruru UI** is a comprehensive UI library and a set of reusable components designed to help you build beautiful and consistent user interfaces with ease. + + + You can install **ruru UI** via package manager or CLI commands. Check the official documentation for detailed instructions. + installation + + + Import the component and use it in your JSX. + + + You can find detailed documentation for each component on our official documentation site. + + + You can contribute to **ruru UI** by submitting bug reports, feature requests, or pull requests on our GitHub repository. + + + Yes, **ruru UI** is open-source and free to use in any project. You can customize it to fit your needs and contribute back to the community. + + -We prioritize accessibility in all our components, ensuring that your application is usable by everyone, including those with disabilities. Our components are built to follow the latest accessibility standards and guidelines. +## Learn More -### **Performance Optimized** +To learn more about ruru UI, take a look at the following resources: -**ruru UI** is optimized for performance, ensuring that your application remains fast and responsive. Our components are lightweight and designed to minimize the impact on your application's performance. - -## Explore the Library - -Dive into the comprehensive documentation to discover all the components and features **ruru UI** has to offer. From buttons and forms to modals and navigation, you'll find everything you need to build a complete and polished user interface. +- [Official Documentation](/docs) - Learn about all the features and components available in ruru UI. +- [GitHub Discussions](https://github.com/ruru-m07/ruru-ui/discussions). - Join the community and ask questions or share your feedback. ## Join the Community Become a part of the **ruru UI** community! Share your experiences, ask questions, and collaborate with other developers. Together, we can make **ruru UI** even better. [Provide feedback](https://github.com/ruru-m07/ruru-ui/discussions/3). +## License + +**ruru UI** is licensed under the MIT License. You are free to use, modify, and distribute the library as you see fit. For more information, please refer to the [LICENSE](https://github.com/ruru-m07/ruru-ui/blob/main/LICENSE) + +## Thank You + +Thank you for choosing **ruru UI**. We appreciate your support and look forward to seeing the amazing applications you build with our library. + +### Enjoy! + +We hope you enjoy using **ruru UI** to build your applications. Our goal is to provide you with a robust and flexible set of tools to create stunning user interfaces. + --- -Feel free to modify any part of this text to better fit your vision for the documentation landing page. If you have any specific elements or additional information you'd like to include, let me know! +

Ruru UI

+

Built with ❤️ by [Ruru](https://github.com/ruru-m07)

diff --git a/apps/www/content/docs/installation.mdx b/apps/www/content/docs/installation.mdx index 415f758..000a2cb 100644 --- a/apps/www/content/docs/installation.mdx +++ b/apps/www/content/docs/installation.mdx @@ -3,14 +3,130 @@ title: Installation description: To get started with ruru UI, you'll need to install the necessary dependencies and set up your project structure. This guide will walk you through the process step by step. --- -import { Tab, Tabs } from "fumadocs-ui/components/tabs"; +import { Tabs as Rutabs, Tab as Rutab } from "ruru-ui/components/tabs"; +import { Tabs, Tab } from "fumadocs-ui/components/tabs"; +import { Step, Steps } from "fumadocs-ui/components/steps"; + + + + + + ### Run the CLI + + Run the `ruru-ui-cli init` command to setup your project: + + + + ```bash + npx ruru-ui-cli@latest init + ``` + + + ```bash + pnpm dlx ruru-ui-cli@latest init + ``` + + + ```bash + npx ruru-ui@latest init + ``` + + + ```bash + bunx --bun ruru-ui@latest init + ``` + + + + + + + + ### Configure components + + You will need to answer a few questions to configure the `components.json` file: + + ```txt +// [!code word:Yes] +// [!code word:No] +// [!code word:./app/globals.css] +// [!code word:./tailwind.config.js] +// [!code word:(Leave blank if not)] +// [!code word:@/components/ui] +// [!code word:@/lib/utils] +◇ Would you like to use TypeScript (recommended)? Yes +◇ use default configuration. No +◇ Where is your global CSS file? ./app/globals.css +◇ Where is your tailwind.config.js located? ./tailwind.config.js +◇ Would you like to use CSS variables for colors? Yes +◇ Are you using a custom tailwind prefix eg. tw-? (Leave blank if not) +◇ Configure the import alias for components: @/components/ui +◇ Configure the import alias for utils: @/lib/utils +◇ Would you like to use RSC ? Yes +◇ Write configuration to components.json. Proceed? Yes + + ``` + + + + + + ### That's it + + Now you can start adding components + + + + ```bash + npx ruru-ui-cli@latest add button + ``` + + + ```bash + pnpm dlx ruru-ui-cli@latest add button + ``` + + + ```bash + npx ruru-ui@latest add button + ``` + + + ```bash + bunx --bun ruru-ui@latest add button + ``` + + + + +This command adds the `button` component to your project. + + ```tsx title="App.tsx" + // [!code word:Button] + import { Button } from "@/components/ui/button" // [!code highlight] + + export default function App() { + return ( +
+ // [!code highlight] +
+ ) + } + ``` + +
+ +
+
+ + ## Install Dependencies First, you'll need to install **ruru UI** and its peer dependencies. You can do this using npm or yarn: ```package-install -npm i ruru-ui +npm i ruru-ui@latest ``` ## Import Styles @@ -26,15 +142,21 @@ import "ruru-ui/style.css"; Now that you've installed **ruru UI** and imported its styles, you can start using the components in your project. Here's an example of how you can use a button component: ```tsx title="App.tsx" -import { Button } from "ruru-ui/components/button"; +// [!code word:Button] +import { Button } from "ruru-ui/components/button"; // [!code highlight] function App() { - return ; + return ( + // [!code highlight] + ); } ``` That's it! You're now ready to start building beautiful interfaces with **ruru UI**. If you have any questions or need further assistance, feel free to reach out to us on [GitHub Discussions](https://github.com/ruru-m07/ruru-ui/discussions/3). + +
+ ## Next Steps @@ -43,16 +165,17 @@ That's it! You're now ready to start building beautiful interfaces with **ruru U title="Dark Mode" description="Learn how to enable dark mode in your ruru UI app." /> - + + --- diff --git a/apps/www/content/docs/meta.json b/apps/www/content/docs/meta.json index ef2af54..87db49b 100644 --- a/apps/www/content/docs/meta.json +++ b/apps/www/content/docs/meta.json @@ -1,11 +1,11 @@ { "root": true, "pages": [ - "---Getting Started---", + "---Guide---", "index", "installation", + "cli", "dark-mode", - "typography", "changelog", "---Components---", "...components", diff --git a/apps/www/content/docs/typography.mdx b/apps/www/content/docs/typography.mdx deleted file mode 100644 index 27ec489..0000000 --- a/apps/www/content/docs/typography.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: Typography -description: Styles for headings, paragraphs, lists...etc. ---- - -import { Callout } from "fumadocs-ui/components/callout"; - - diff --git a/apps/www/package.json b/apps/www/package.json index f43e7f7..0813ab3 100644 --- a/apps/www/package.json +++ b/apps/www/package.json @@ -3,13 +3,15 @@ "version": "0.0.0", "private": true, "scripts": { - "build": "next build", + "build": "pnpm build:registry && next build", "dev": "next dev", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "build:registry": "tsx --tsconfig ./tsconfig.scripts.json ./scripts/build-registry.mts && prettier --loglevel silent --ignore-path .gitignore --ignore-path .prettierignore --write \"**/*.{ts,tsx,mdx,json}\" --cache" }, "dependencies": { "@radix-ui/react-icons": "^1.3.0", + "fs": "0.0.1-security", "fumadocs-core": "12.4.2", "fumadocs-docgen": "^1.1.0", "fumadocs-mdx": "8.2.33", @@ -17,13 +19,18 @@ "fumadocs-ui": "12.4.2", "geist": "^1.3.1", "next": "^14.2.4", + "os": "^0.1.2", + "path": "^0.12.7", + "process": "^0.11.10", "react": "^18.3.1", "react-dom": "^18.3.1", "rehype-katex": "^7.0.0", "remark-math": "^6.0.0", + "rimraf": "^6.0.1", "ruru-ui": "workspace:*", "tailwind-merge": "^2.4.0", "tailwindcss-animate": "^1.0.7", + "ts-morph": "^23.0.0", "zod": "^3.23.8" }, "devDependencies": { diff --git a/apps/www/public/registry/colors/basecolor.json b/apps/www/public/registry/colors/basecolor.json new file mode 100644 index 0000000..c47c157 --- /dev/null +++ b/apps/www/public/registry/colors/basecolor.json @@ -0,0 +1,102 @@ +{ + "inlineColors": { + "light": { + "background": "white", + "foreground": "neutral-950", + "card": "white", + "card-foreground": "neutral-950", + "popover": "white", + "popover-foreground": "neutral-950", + "primary": "neutral-900", + "primary-foreground": "neutral-50", + "secondary": "neutral-100", + "secondary-foreground": "neutral-900", + "muted": "neutral-100", + "muted-foreground": "neutral-500", + "accent": "neutral-100", + "accent-foreground": "neutral-900", + "destructive": "red-500", + "destructive-foreground": "neutral-50", + "border": "neutral-200", + "input": "neutral-200", + "ring": "neutral-950" + }, + "dark": { + "background": "neutral-950", + "foreground": "neutral-50", + "card": "neutral-950", + "card-foreground": "neutral-50", + "popover": "neutral-950", + "popover-foreground": "neutral-50", + "primary": "neutral-50", + "primary-foreground": "neutral-900", + "secondary": "neutral-800", + "secondary-foreground": "neutral-50", + "muted": "neutral-800", + "muted-foreground": "neutral-400", + "accent": "neutral-800", + "accent-foreground": "neutral-50", + "destructive": "red-900", + "destructive-foreground": "neutral-50", + "border": "neutral-800", + "input": "neutral-800", + "ring": "neutral-300" + } + }, + "cssVars": { + "light": { + "background": "0 0% 100%", + "foreground": "0 0% 3.9%", + "card": "0 0% 100%", + "card-foreground": "0 0% 3.9%", + "popover": "0 0% 100%", + "popover-foreground": "0 0% 3.9%", + "primary": "0 0% 9%", + "primary-foreground": "0 0% 98%", + "secondary": "0 0% 96.1%", + "secondary-foreground": "0 0% 9%", + "muted": "0 0% 96.1%", + "muted-foreground": "0 0% 45.1%", + "accent": "0 0% 96.1%", + "accent-foreground": "0 0% 9%", + "destructive": "0 84.2% 60.2%", + "destructive-foreground": "0 0% 98%", + "border": "0 0% 89.8%", + "input": "0 0% 89.8%", + "ring": "0 0% 3.9%", + "chart-1": "12 76% 61%", + "chart-2": "173 58% 39%", + "chart-3": "197 37% 24%", + "chart-4": "43 74% 66%", + "chart-5": "27 87% 67%" + }, + "dark": { + "background": "0 0% 3.9%", + "foreground": "0 0% 98%", + "card": "0 0% 3.9%", + "card-foreground": "0 0% 98%", + "popover": "0 0% 3.9%", + "popover-foreground": "0 0% 98%", + "primary": "0 0% 98%", + "primary-foreground": "0 0% 9%", + "secondary": "0 0% 14.9%", + "secondary-foreground": "0 0% 98%", + "muted": "0 0% 14.9%", + "muted-foreground": "0 0% 63.9%", + "accent": "0 0% 14.9%", + "accent-foreground": "0 0% 98%", + "destructive": "0 62.8% 30.6%", + "destructive-foreground": "0 0% 98%", + "border": "0 0% 14.9%", + "input": "0 0% 14.9%", + "ring": "0 0% 83.1%", + "chart-1": "220 70% 50%", + "chart-2": "160 60% 45%", + "chart-3": "30 80% 55%", + "chart-4": "280 65% 60%", + "chart-5": "340 75% 55%" + } + }, + "inlineColorsTemplate": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n ", + "cssVarsTemplate": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n@layer base {\n :root {\n --background: 0 0% 100%;\n --foreground: 0 0% 3.9%;\n --card: 0 0% 100%;\n --card-foreground: 0 0% 3.9%;\n --popover: 0 0% 100%;\n --popover-foreground: 0 0% 3.9%;\n --primary: 0 0% 9%;\n --primary-foreground: 0 0% 98%;\n --secondary: 0 0% 96.1%;\n --secondary-foreground: 0 0% 9%;\n --muted: 0 0% 96.1%;\n --muted-foreground: 0 0% 45.1%;\n --accent: 0 0% 96.1%;\n --accent-foreground: 0 0% 9%;\n --destructive: 0 84.2% 60.2%;\n --destructive-foreground: 0 0% 98%;\n --border: 0 0% 89.8%;\n --input: 0 0% 89.8%;\n --ring: 0 0% 3.9%;\n --radius: 0.5rem;\n --chart-1: 12 76% 61%;\n --chart-2: 173 58% 39%;\n --chart-3: 197 37% 24%;\n --chart-4: 43 74% 66%;\n --chart-5: 27 87% 67%;\n }\n\n .dark {\n --background: 0 0% 3.9%;\n --foreground: 0 0% 98%;\n --card: 0 0% 3.9%;\n --card-foreground: 0 0% 98%;\n --popover: 0 0% 3.9%;\n --popover-foreground: 0 0% 98%;\n --primary: 0 0% 98%;\n --primary-foreground: 0 0% 9%;\n --secondary: 0 0% 14.9%;\n --secondary-foreground: 0 0% 98%;\n --muted: 0 0% 14.9%;\n --muted-foreground: 0 0% 63.9%;\n --accent: 0 0% 14.9%;\n --accent-foreground: 0 0% 98%;\n --destructive: 0 62.8% 30.6%;\n --destructive-foreground: 0 0% 98%;\n --border: 0 0% 14.9%;\n --input: 0 0% 14.9%;\n --ring: 0 0% 83.1%;\n --chart-1: 220 70% 50%;\n --chart-2: 160 60% 45%;\n --chart-3: 30 80% 55%;\n --chart-4: 280 65% 60%;\n --chart-5: 340 75% 55%;\n }\n}\n\n@layer base {\n * {\n @apply border-border;\n }\n body {\n @apply bg-background text-foreground;\n }\n}" +} diff --git a/apps/www/public/registry/components/avatar.json b/apps/www/public/registry/components/avatar.json new file mode 100644 index 0000000..4d0f203 --- /dev/null +++ b/apps/www/public/registry/components/avatar.json @@ -0,0 +1,10 @@ +{ + "name": "avatar", + "files": [ + { + "name": "avatar.tsx", + "content": "import * as React from \"react\";\nimport { cn } from \"@/utils/cn\";\ntype AvatarProps = Omit<\n React.ComponentPropsWithoutRef<\"img\">,\n \"src\" | \"alt\"\n> & {\n className?: string;\n size?: number;\n placeholder?: string;\n src: string;\n};\nconst Avatar = React.forwardRef(\n ({ className, size = 30, src, placeholder, ...props }, ref) => {\n return (\n \n );\n },\n);\nAvatar.displayName = \"Avatar\";\ntype AvatarGroupProps = Omit<\n React.ComponentPropsWithoutRef<\"div\">,\n \"children\"\n> & {\n className?: string;\n members: { src: string; alt: string }[];\n size?: number;\n limit?: number;\n aClassName?: string;\n lnClassName?: string;\n};\nconst AvatarGroup = React.forwardRef(\n (\n { className, aClassName, lnClassName, size = 30, members, limit, ...props },\n ref,\n ) => {\n const displayedMembers =\n limit && members.length > limit ? members.slice(0, limit - 1) : members;\n const extraMembersCount =\n limit && members.length > limit ? members.length - limit + 1 : 0;\n return (\n
\n {displayedMembers.map((member, index) => (\n \n ))}\n {extraMembersCount > 0 && (\n \n +{extraMembersCount}\n
\n )}\n
\n );\n },\n);\nAvatarGroup.displayName = \"AvatarGroup\";\ntype AvatarWithBadgeProps = Omit<\n React.ComponentPropsWithoutRef<\"div\">,\n \"children\"\n> & {\n className?: string;\n size?: number;\n src: string;\n placeholder?: string;\n badgeSrc: string;\n iClassName?: string;\n sClassName?: string;\n};\nconst AvatarWithBadge = React.forwardRef(\n (\n {\n className,\n sClassName,\n iClassName,\n size = 30,\n src,\n placeholder,\n badgeSrc,\n ...props\n },\n ref,\n ) => {\n return (\n \n \n \n
\n );\n },\n);\nAvatarWithBadge.displayName = \"AvatarWithBadge\";\nexport { Avatar, AvatarGroup, AvatarWithBadge };\n" + } + ], + "type": "components:ui" +} diff --git a/apps/www/public/registry/components/badge.json b/apps/www/public/registry/components/badge.json new file mode 100644 index 0000000..f38c94b --- /dev/null +++ b/apps/www/public/registry/components/badge.json @@ -0,0 +1,10 @@ +{ + "name": "badge", + "files": [ + { + "name": "badge.tsx", + "content": "import * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"@/utils/cn\";\nconst variants = {\n gray: \"bg-[#8f8f8f] text-white\",\n \"gray-subtle\": \"bg-[#1f1f1f] text-white\",\n blue: \"bg-[#0072f5] text-white\",\n \"blue-subtle\": \"bg-[#10233d] text-[#52a8ff]\",\n purple: \"bg-[#8e4ec6] text-white\",\n \"purple-subtle\": \"bg-[#2e1938] text-[#bf7af0]\",\n amber: \"bg-[#ffb224] text-black\",\n \"amber-subtle\": \"bg-[#331b00] text-[#f2a20d]\",\n red: \"bg-[#e5484d] text-white\",\n \"red-subtle\": \"bg-[#3c1618] text-[#ff6166]\",\n pink: \"bg-[#ea3e83] text-white\",\n \"pink-subtle\": \"bg-[#4f1c31] text-[#f75f8f]\",\n green: \"bg-[#45a557] text-white\",\n \"green-subtle\": \"bg-[#0f2e18] text-[#62c073]\",\n teal: \"bg-[#12a594] text-white\",\n \"teal-subtle\": \"bg-[#083a33] text-[#0ac7b4]\",\n inverted: \"bg-primary text-primary-foreground\",\n};\nconst sizes = {\n sm: \"text-xs px-1.5 py-[1.5px]\",\n md: \"text-sm px-2.5 py-[2px]\",\n lg: \"text-lg px-3 py-[2.5px]\",\n};\nconst badgeVariants = cva(\n \"w-fit h-fit inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 capitalize\",\n {\n variants: {\n variant: {\n ...variants,\n },\n size: {\n ...sizes,\n },\n },\n defaultVariants: {\n variant: \"gray\",\n size: \"md\",\n },\n },\n);\nexport interface BadgeProps\n extends React.HTMLAttributes,\n VariantProps {\n children: React.ReactNode;\n variant: keyof typeof variants;\n size?: \"sm\" | \"md\" | \"lg\";\n icon?: React.ReactNode;\n}\nconst Badge: React.FC = ({\n children,\n className,\n variant,\n size = \"md\",\n icon,\n ...props\n}: BadgeProps): React.ReactElement => {\n return (\n
\n {icon && {icon}}\n {children}\n
\n );\n};\nexport { Badge, badgeVariants };\n" + } + ], + "type": "components:ui" +} diff --git a/apps/www/public/registry/components/button.json b/apps/www/public/registry/components/button.json new file mode 100644 index 0000000..20f05e9 --- /dev/null +++ b/apps/www/public/registry/components/button.json @@ -0,0 +1,12 @@ +{ + "name": "button", + "dependencies": ["@radix-ui/react-slot"], + "files": [ + { + "name": "button.tsx", + "content": "\"use client\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport React from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport { Spinner } from \"./spinner\";\nexport const buttonVariants = cva(\n \"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50\",\n {\n variants: {\n variant: {\n default:\n \"bg-primary text-primary-foreground shadow hover:bg-primary/85 hover:shadow-md\",\n secondary:\n \"border-input border-[1.5px] bg-primary-foreground hover:bg-[#f3f3f3] dark:hover:bg-[#202020]\",\n tertiary: \"text-primary hover:bg-[#f3f3f3] dark:hover:bg-[#202020]\",\n error: \"bg-[#d93036] hover:bg-[#ff6166]\",\n warning: \"bg-[#ff990a] text-primary-foreground hover:bg-[#d27504]\",\n },\n size: {\n default: \"h-9 px-4 py-2\",\n small: \"h-8 rounded-md px-3 text-xs\",\n large: \"h-10 rounded-md px-8\",\n icon: \"size-9\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\nexport interface ButtonProps\n extends Omit<\n React.ButtonHTMLAttributes,\n \"prefix\" | \"suffix\"\n >,\n VariantProps {\n asChild?: boolean;\n prefix?: React.ReactNode;\n suffix?: React.ReactNode;\n disabled?: boolean;\n loading?: boolean;\n}\nexport const Button = React.forwardRef(\n (\n {\n className,\n variant = \"default\",\n size = \"default\",\n asChild = false,\n prefix,\n suffix,\n disabled = false,\n loading = false,\n ...props\n },\n ref,\n ) => {\n const Comp = asChild ? Slot : \"button\";\n return (\n
\n \n {loading ? : null}\n {prefix ? (\n \n {prefix}\n \n ) : null}\n {props.children}\n {suffix ? (\n \n {suffix}\n \n ) : null}\n \n
\n );\n },\n);\nButton.displayName = \"Button\";\n" + } + ], + "type": "components:ui", + "subcategory": ["spinner"] +} diff --git a/apps/www/public/registry/components/checkbox.json b/apps/www/public/registry/components/checkbox.json new file mode 100644 index 0000000..55fc6da --- /dev/null +++ b/apps/www/public/registry/components/checkbox.json @@ -0,0 +1,11 @@ +{ + "name": "checkbox", + "dependencies": ["@radix-ui/react-checkbox"], + "files": [ + { + "name": "checkbox.tsx", + "content": "import * as React from \"react\";\nimport * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\nimport { cn } from \"@/utils/cn\";\ntype CheckboxProps = React.ComponentPropsWithoutRef<\n typeof CheckboxPrimitive.Root\n> & {\n indeterminate?: boolean;\n};\nconst Checkbox = React.forwardRef<\n React.ElementRef,\n CheckboxProps\n>(({ className, indeterminate = false, ...props }, ref) => (\n \n {indeterminate ? (\n \n \n \n ) : (\n \n \n \n \n \n )}\n \n));\nCheckbox.displayName = CheckboxPrimitive.Root.displayName;\nexport { Checkbox };\n" + } + ], + "type": "components:ui" +} diff --git a/apps/www/public/registry/components/input.json b/apps/www/public/registry/components/input.json new file mode 100644 index 0000000..aa72bef --- /dev/null +++ b/apps/www/public/registry/components/input.json @@ -0,0 +1,10 @@ +{ + "name": "input", + "files": [ + { + "name": "input.tsx", + "content": "\"use client\";\nimport * as React from \"react\";\nimport { cn } from \"@/utils/cn\";\nexport interface InputProps\n extends Omit<\n React.InputHTMLAttributes,\n \"children\" | \"prefix\" | \"suffix\"\n > {\n className?: string;\n iclassName?: string;\n prefix?: React.ReactNode | string;\n suffix?: React.ReactNode | string;\n prefixStyling?: boolean;\n label?: string;\n suffixStyling?: boolean;\n error?: string;\n}\nconst Input = React.forwardRef(\n (\n {\n className,\n iclassName,\n prefix,\n suffix,\n prefixStyling = true,\n suffixStyling = true,\n label,\n type,\n error,\n ...props\n },\n ref,\n ) => {\n const prefixRef = React.useRef(null);\n const suffixRef = React.useRef(null);\n const [prefixWidth, setPrefixWidth] = React.useState(0);\n const [suffixWidth, setSuffixWidth] = React.useState(0);\n React.useEffect(() => {\n if (prefixRef.current) {\n setPrefixWidth(prefixRef.current.offsetWidth);\n }\n if (suffixRef.current) {\n setSuffixWidth(suffixRef.current.offsetWidth);\n }\n }, [prefix, suffix]);\n return (\n
\n {label && (\n \n {label}\n \n )}\n {prefix && (\n \n {prefix}\n {prefixStyling &&
}\n
\n )}\n \n {suffix && (\n \n {suffixStyling && (\n
\n )}\n {suffix}\n
\n )}\n {error && (\n \n \n \n \n \n
\n )}\n \n );\n },\n);\nInput.displayName = \"Input\";\nexport interface SearchInputProps\n extends Omit, \"children\"> {\n enablePrefixStyling?: boolean;\n}\nconst SearchInput = React.forwardRef(\n ({ enablePrefixStyling = false, ...props }, ref) => {\n return (\n \n \n \n }\n prefixStyling={enablePrefixStyling}\n className={cn(\"rounded-full\", props.className)}\n ref={ref}\n {...props}\n />\n );\n },\n);\nSearchInput.displayName = \"SearchInput\";\nexport { Input, SearchInput };\n" + } + ], + "type": "components:ui" +} diff --git a/apps/www/public/registry/components/select.json b/apps/www/public/registry/components/select.json new file mode 100644 index 0000000..88f4c64 --- /dev/null +++ b/apps/www/public/registry/components/select.json @@ -0,0 +1,11 @@ +{ + "name": "select", + "dependencies": ["@radix-ui/react-select", "@radix-ui/react-icons"], + "files": [ + { + "name": "select.tsx", + "content": "\"use client\";\nimport * as React from \"react\";\nimport {\n CaretSortIcon,\n CheckIcon,\n ChevronDownIcon,\n ChevronUpIcon,\n} from \"@radix-ui/react-icons\";\nimport * as SelectPrimitive from \"@radix-ui/react-select\";\nimport { cn } from \"@/utils/cn\";\nconst Select = SelectPrimitive.Root;\nconst SelectGroup = SelectPrimitive.Group;\nconst SelectValue = SelectPrimitive.Value;\nconst SelectTrigger = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, children, ...props }, ref) => (\n span]:line-clamp-1\",\n className,\n )}\n {...props}\n >\n {children}\n \n \n \n \n));\nSelectTrigger.displayName = SelectPrimitive.Trigger.displayName;\nconst SelectScrollUpButton = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n \n \n));\nSelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;\nconst SelectScrollDownButton = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n \n \n));\nSelectScrollDownButton.displayName =\n SelectPrimitive.ScrollDownButton.displayName;\nconst SelectContent = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, children, position = \"popper\", ...props }, ref) => (\n \n \n \n \n {children}\n \n \n \n \n));\nSelectContent.displayName = SelectPrimitive.Content.displayName;\nconst SelectLabel = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n));\nSelectLabel.displayName = SelectPrimitive.Label.displayName;\nconst SelectItem = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, children, ...props }, ref) => (\n \n \n \n \n \n \n {children}\n \n));\nSelectItem.displayName = SelectPrimitive.Item.displayName;\nconst SelectSeparator = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n));\nSelectSeparator.displayName = SelectPrimitive.Separator.displayName;\nexport {\n Select,\n SelectGroup,\n SelectValue,\n SelectTrigger,\n SelectContent,\n SelectLabel,\n SelectItem,\n SelectSeparator,\n SelectScrollUpButton,\n SelectScrollDownButton,\n};\n" + } + ], + "type": "components:ui" +} diff --git a/apps/www/public/registry/components/spinner.json b/apps/www/public/registry/components/spinner.json new file mode 100644 index 0000000..44b414d --- /dev/null +++ b/apps/www/public/registry/components/spinner.json @@ -0,0 +1,10 @@ +{ + "name": "spinner", + "files": [ + { + "name": "spinner.tsx", + "content": "import React from \"react\";\nimport { cn } from \"@/utils/cn\";\ntype SpinnerProps = React.ComponentPropsWithoutRef<\"div\"> & {\n className?: string;\n size?: number;\n};\nconst Spinner = React.forwardRef(\n ({ className, size, ...props }, ref) => {\n const computeDelay = (i: number): string => `${-1.2 + i * 0.1}s`;\n const computeRotation = (i: number): string => `${i * 30}deg`;\n return (\n \n
\n {[...Array(12)].map((_, i) => (\n \n ))}\n
\n \n );\n },\n);\nSpinner.displayName = \"Spinner\";\nexport { Spinner };\n" + } + ], + "type": "components:ui" +} diff --git a/apps/www/public/registry/components/switch.json b/apps/www/public/registry/components/switch.json new file mode 100644 index 0000000..5378383 --- /dev/null +++ b/apps/www/public/registry/components/switch.json @@ -0,0 +1,11 @@ +{ + "name": "switch", + "dependencies": ["@radix-ui/react-icons", "@radix-ui/react-select"], + "files": [ + { + "name": "switch.tsx", + "content": "\"use client\";\nimport * as React from \"react\";\nimport * as SwitchPrimitives from \"@radix-ui/react-switch\";\nimport { cn } from \"@/utils/cn\";\nconst Switch = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, ...props }, ref) => (\n \n \n \n));\nSwitch.displayName = SwitchPrimitives.Root.displayName;\nexport { Switch };\n" + } + ], + "type": "components:ui" +} diff --git a/apps/www/public/registry/components/textarea.json b/apps/www/public/registry/components/textarea.json new file mode 100644 index 0000000..e2c7787 --- /dev/null +++ b/apps/www/public/registry/components/textarea.json @@ -0,0 +1,10 @@ +{ + "name": "textarea", + "files": [ + { + "name": "textarea.tsx", + "content": "\"use client\";\nimport * as React from \"react\";\nimport { cn } from \"@/utils/cn\";\nexport interface TextAreaProps\n extends Omit<\n React.InputHTMLAttributes,\n \"children\" | \"prefix\" | \"suffix\"\n > {\n className?: string;\n label?: string;\n error?: string;\n}\nconst Textarea = React.forwardRef(\n ({ className, label, error, ...props }, ref) => {\n return (\n
\n {label && (\n \n {label}\n \n )}\n \n {error && (\n \n \n \n \n \n
\n )}\n \n );\n },\n);\nTextarea.displayName = \"Textarea\";\nexport { Textarea };\n" + } + ], + "type": "components:ui" +} diff --git a/apps/www/public/registry/components/tooltip.json b/apps/www/public/registry/components/tooltip.json new file mode 100644 index 0000000..f75b2a9 --- /dev/null +++ b/apps/www/public/registry/components/tooltip.json @@ -0,0 +1,11 @@ +{ + "name": "tooltip", + "dependencies": ["@radix-ui/react-tooltip"], + "files": [ + { + "name": "tooltip.tsx", + "content": "\"use client\";\nimport * as React from \"react\";\nimport * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport { cn } from \"@/utils/cn\";\nconst TooltipProvider = TooltipPrimitive.Provider;\nconst Tooltip = TooltipPrimitive.Root;\nconst TooltipTrigger = TooltipPrimitive.Trigger;\nconst TooltipContent = React.forwardRef<\n React.ElementRef,\n React.ComponentPropsWithoutRef\n>(({ className, sideOffset = 5, ...props }, ref) => (\n \n {props.children}\n \n \n));\nTooltipContent.displayName = TooltipPrimitive.Content.displayName;\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };\n" + } + ], + "type": "components:ui" +} diff --git a/apps/www/public/registry/index.json b/apps/www/public/registry/index.json new file mode 100644 index 0000000..f101263 --- /dev/null +++ b/apps/www/public/registry/index.json @@ -0,0 +1,58 @@ +[ + { + "name": "avatar", + "files": ["avatar.tsx"], + "type": "components:ui" + }, + { + "name": "badge", + "files": ["badge.tsx"], + "type": "components:ui" + }, + { + "name": "button", + "dependencies": ["@radix-ui/react-slot"], + "files": ["button.tsx"], + "type": "components:ui", + "subcategory": ["spinner"] + }, + { + "name": "checkbox", + "dependencies": ["@radix-ui/react-checkbox"], + "files": ["checkbox.tsx"], + "type": "components:ui" + }, + { + "name": "input", + "files": ["input.tsx"], + "type": "components:ui" + }, + { + "name": "select", + "dependencies": ["@radix-ui/react-select", "@radix-ui/react-icons"], + "files": ["select.tsx"], + "type": "components:ui" + }, + { + "name": "spinner", + "files": ["spinner.tsx"], + "type": "components:ui" + }, + { + "name": "switch", + "dependencies": ["@radix-ui/react-icons", "@radix-ui/react-select"], + "files": ["switch.tsx"], + "type": "components:ui" + }, + { + "name": "textarea", + "files": ["textarea.tsx"], + "type": "components:ui" + }, + { + "name": "tooltip", + "dependencies": ["@radix-ui/react-tooltip"], + "files": ["tooltip.tsx"], + "type": "components:ui" + } +] diff --git a/apps/www/registry/registry.ts b/apps/www/registry/registry.ts new file mode 100644 index 0000000..95bf1e4 --- /dev/null +++ b/apps/www/registry/registry.ts @@ -0,0 +1,4 @@ +import { Registry } from "@/registry/schema"; +import { ui } from "@/registry/ui"; + +export const registry: Registry = [...ui]; diff --git a/apps/www/registry/schema.ts b/apps/www/registry/schema.ts new file mode 100644 index 0000000..fa9a264 --- /dev/null +++ b/apps/www/registry/schema.ts @@ -0,0 +1,34 @@ +import { z } from "zod"; + +export const blockChunkSchema = z.object({ + name: z.string(), + description: z.string(), + component: z.any(), + file: z.string(), + code: z.string().optional(), + container: z + .object({ + className: z.string().nullish(), + }) + .optional(), +}); + +export const registryEntrySchema = z.object({ + name: z.string(), + description: z.string().optional(), + dependencies: z.array(z.string()).optional(), + devDependencies: z.array(z.string()).optional(), + registryDependencies: z.array(z.string()).optional(), + files: z.array(z.string()), + source: z.string().optional(), + type: z.enum(["components:ui", "components:component"]), + category: z.string().optional(), + subcategory: z.array(z.string()).optional(), + chunks: z.array(blockChunkSchema).optional(), +}); + +export const registrySchema = z.array(registryEntrySchema); + +export type RegistryEntry = z.infer; + +export type Registry = z.infer; diff --git a/apps/www/registry/ui.ts b/apps/www/registry/ui.ts new file mode 100644 index 0000000..fd7600a --- /dev/null +++ b/apps/www/registry/ui.ts @@ -0,0 +1,60 @@ +import { Registry } from "@/registry/schema"; + +export const ui: Registry = [ + { + name: "avatar", + type: "components:ui", + files: ["avatar.tsx"], + }, + { + name: "badge", + type: "components:ui", + files: ["badge.tsx"], + }, + { + name: "button", + type: "components:ui", + dependencies: ["@radix-ui/react-slot"], + subcategory: ["spinner"], + files: ["button.tsx"], + }, + { + name: "checkbox", + type: "components:ui", + dependencies: ["@radix-ui/react-checkbox"], + files: ["checkbox.tsx"], + }, + { + name: "input", + type: "components:ui", + files: ["input.tsx"], + }, + { + name: "select", + type: "components:ui", + dependencies: ["@radix-ui/react-select", "@radix-ui/react-icons"], + files: ["select.tsx"], + }, + { + name: "spinner", + type: "components:ui", + files: ["spinner.tsx"], + }, + { + name: "switch", + type: "components:ui", + dependencies: ["@radix-ui/react-icons", "@radix-ui/react-select"], + files: ["switch.tsx"], + }, + { + name: "textarea", + type: "components:ui", + files: ["textarea.tsx"], + }, + { + name: "tooltip", + type: "components:ui", + dependencies: ["@radix-ui/react-tooltip"], + files: ["tooltip.tsx"], + }, +]; diff --git a/apps/www/scripts/build-registry.mts b/apps/www/scripts/build-registry.mts new file mode 100644 index 0000000..9713ff9 --- /dev/null +++ b/apps/www/scripts/build-registry.mts @@ -0,0 +1,147 @@ +// @sts-nocheck +import { existsSync, promises as fs, readFileSync } from "fs"; +import path, { basename } from "path"; +import { rimraf } from "rimraf"; + +import { registry } from "../registry/registry"; +import { Registry, registrySchema } from "../registry/schema"; + +const REGISTRY_PATH = path.join(process.cwd(), "public/registry"); + +// ---------------------------------------------------------------------------- +// Build __registry__/index.tsx. +// ---------------------------------------------------------------------------- +async function buildRegistry(registry: Registry) { + console.log(" ⚒️ Building registry..."); + + let index = `// @ts-nocheck +// This file is autogenerated by scripts/build-registry.ts +// Do not edit this file directly. +import * as React from "react" + +export const Index: Record = { +`; + + index += ` "components": {`; + + // Build style index. + for (const item of registry) { + const resolveFiles = item.files.map( + (file) => `@/../../packages/ui/src/components/${file}`, + ); + + let sourceFilename = ""; + + index += ` + "${item.name}": { + name: "${item.name}", + type: "${item.type}", + registryDependencies: ${JSON.stringify(item.registryDependencies)}, + component: React.lazy(() => import("@/../../packages/ui/src/components/${item.name}")), + source: "${sourceFilename}", + files: [${resolveFiles.map((file) => `"${file}"`)}], + category: "${item.category}", + subcategory: ${JSON.stringify(item.subcategory)} + },`; + } + + index += ` + },`; + + index += ` +} +`; + + // ---------------------------------------------------------------------------- + // Build registry/index.json. + // ---------------------------------------------------------------------------- + const names = registry.filter((item) => item.type === "components:ui"); + const registryJson = JSON.stringify(names, null, 2); + rimraf.sync(path.join(REGISTRY_PATH, "index.json")); + await fs.writeFile( + path.join(REGISTRY_PATH, "index.json"), + registryJson, + "utf8", + ); + + // Write style index. + rimraf.sync(path.join(process.cwd(), "__registry__/index.tsx")); + await fs.writeFile(path.join(process.cwd(), "__registry__/index.tsx"), index); + + console.log("✅ Registry built!"); +} + +// ---------------------------------------------------------------------------- +// Build registry/styles/[style]/[name].json. +// ---------------------------------------------------------------------------- +async function buildStyles(registry: Registry) { + console.log(" ⚒️ Building styles..."); + + const targetPath = path.join(REGISTRY_PATH); + + // Create directory if it doesn't exist. + if (!existsSync(targetPath)) { + await fs.mkdir(targetPath, { recursive: true }); + } + + // Create directory if it doesn't exist. + for (const item of registry) { + console.log(` |- ${item.name} `); + + if (item.type !== "components:ui") { + continue; + } + + const files = item.files?.map((file) => { + let content = readFileSync( + path.join("../../packages/ui/src/components", file), + "utf8", + ); + + // Remove single-line comments + content = content.replace(/\/\/.*$/gm, ""); + + // Remove multi-line comments + content = content.replace(/\/\*[\s\S]*?\*\//gm, ""); + + // ! it also removeing white lines :( , will fix + // Remove lines that are completely empty (after removing comments) + content = content.replace(/^\s*\n/gm, ""); + + return { + name: basename(file), + content, + }; + }); + + const payload = { + ...item, + files, + }; + + await fs.writeFile( + path.join(targetPath, "components", `${item.name}.json`), + JSON.stringify(payload, null, 2), + "utf8", + ); + } + + console.log("✅ Styles built!"); +} + +try { + const result = registrySchema.safeParse(registry); + + if (!result.success) { + console.error(result.error); + process.exit(1); + } + + await buildRegistry(result.data); + await buildStyles(result.data); + + console.log("✅ All done!"); +} catch (error) { + console.error(error); + process.exit(1); +} diff --git a/apps/www/tailwind.config.js b/apps/www/tailwind.config.js index d129deb..b97df53 100644 --- a/apps/www/tailwind.config.js +++ b/apps/www/tailwind.config.js @@ -1,6 +1,7 @@ import { createPreset } from "fumadocs-ui/tailwind-plugin"; /** @type {import('tailwindcss').Config} */ +// eslint-disable-next-line import/no-anonymous-default-export export default { content: [ "./components/**/*.{ts,tsx}", @@ -10,6 +11,19 @@ export default { "./node_modules/fumadocs-ui/dist/**/*.js", "./node_modules/ruru-ui/dist/**/*.js", ], + theme: { + extend: { + keyframes: { + spinner: { + from: { opacity: "1" }, + to: { opacity: "0.15" }, + }, + }, + animation: { + spinner: "spinner 1.2s linear infinite", + }, + }, + }, plugins: [require("tailwindcss-animate")], presets: [createPreset()], }; diff --git a/apps/www/tsconfig.scripts.json b/apps/www/tsconfig.scripts.json new file mode 100644 index 0000000..e81451a --- /dev/null +++ b/apps/www/tsconfig.scripts.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "extends": "./tsconfig.json", + "compilerOptions": { + "target": "es6", + "module": "ESNext", + "moduleResolution": "node", + "esModuleInterop": true, + "isolatedModules": false + }, + "include": ["scripts/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/package.json b/package.json index 7ab2423..d81ef63 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "lint": "turbo run lint", "format": "prettier --write \"**/*.{ts,tsx,md}\"", "lint:prettier": "prettier --cache --check --ignore-path .gitignore --ignore-path .prettierignore .", - "prettier": "prettier --cache --write --list-different --ignore-path .gitignore --ignore-path .prettierignore .", + "prettier": "prettier --loglevel silent --write \"\" --cache", "types:check": "turbo run types:check", "release": "turbo run build --filter=./packages/* && changeset publish", "version": "changeset version && pnpm install --lockfile-only" @@ -32,6 +32,8 @@ }, "dependencies": { "@changesets/cli": "^2.27.7", - "sharp": "^0.33.4" + "sharp": "^0.33.4", + "tsup": "^8.1.1", + "tsx": "^4.17.0" } } diff --git a/packages/cli/.env.example b/packages/cli/.env.example new file mode 100644 index 0000000..dd3726d --- /dev/null +++ b/packages/cli/.env.example @@ -0,0 +1 @@ +NODE_ENV="development" diff --git a/packages/cli/.eslintrc.cjs b/packages/cli/.eslintrc.cjs new file mode 100644 index 0000000..f55c48d --- /dev/null +++ b/packages/cli/.eslintrc.cjs @@ -0,0 +1,17 @@ +module.exports = { + // Exclude this file from ESLint's list of included files + ignorePatterns: [".eslintrc.cjs", "dist"], + plugins: ["@typescript-eslint/eslint-plugin", "eslint-plugin-tsdoc"], + extends: ["plugin:@typescript-eslint/recommended"], + parser: "@typescript-eslint/parser", + parserOptions: { + project: "./tsconfig.json", + tsconfigRootDir: __dirname, + ecmaVersion: 2018, + sourceType: "module", + }, + rules: { + // 'tsdoc/syntax': 'warn' + "import/no-relative-packages": "off", + }, +}; diff --git a/packages/cli/.gitignore b/packages/cli/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/packages/cli/README.md b/packages/cli/README.md new file mode 100644 index 0000000..148a636 --- /dev/null +++ b/packages/cli/README.md @@ -0,0 +1,43 @@ +# ruru-ui-cli + +A CLI for adding components to your project. + +## Usage + +Use the `init` command to initialize dependencies for a new project. + +The `init` command installs dependencies, adds the `cn` util, configures `tailwind.config.js`, and CSS variables for the project. + +```bash +npx ruru-ui-cli init +``` + +## add + +Use the `add` command to add components to your project. + +The `add` command adds a component to your project and installs all required dependencies. + +```bash +npx ruru-ui-cli add [component] +``` + +### Example + +```bash +npx ruru-ui-cli add button +``` + +You can also run the command without any arguments to view a list of all available components: + +```bash +npx ruru-ui-cli add +``` + +## Documentation + +Visit https://ruru-ui.vercel.app/docs/typography/cli to view the documentation. + +## License + +Licensed under the [MIT license](https://github.com/ruru-m07/ruru-ui/blob/main/LICENSE). diff --git a/packages/cli/package.json b/packages/cli/package.json new file mode 100644 index 0000000..c72bdcb --- /dev/null +++ b/packages/cli/package.json @@ -0,0 +1,69 @@ +{ + "name": "ruru-ui-cli", + "version": "0.0.0", + "description": "Ruru UI - CLI - add components and dependencies to your project", + "keywords": [ + "cli", + "ruru-ui", + "ruru-cli", + "ruru-ui - cli" + ], + "homepage": "https://ruru-ui.vercel.app", + "repository": { + "type": "git", + "url": "https://github.com/ruru-m07/ruru-ui.git", + "directory": "packages/cli" + }, + "license": "MIT", + "author": "Ruru", + "type": "module", + "bin": "./dist/index.js", + "files": [ + "dist/*" + ], + "scripts": { + "build": "tsup", + "clean": "rimraf dist", + "dev": "tsup --watch", + "lint": "eslint .", + "types:check": "tsc --noEmit" + }, + "devDependencies": { + "@types/babel__core": "^7.20.5", + "@types/fs-extra": "^11.0.4", + "@types/lodash.template": "^4.5.3", + "tsconfig": "workspace:*" + }, + "engines": { + "node": ">=18.17.0" + }, + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@antfu/ni": "^0.22.1", + "@babel/core": "^7.25.2", + "@babel/parser": "^7.25.3", + "@babel/plugin-transform-typescript": "^7.25.2", + "@clack/prompts": "^0.7.0", + "commander": "^12.1.0", + "cosmiconfig": "^9.0.0", + "cross-spawn": "^7.0.3", + "dotenv": "^16.4.5", + "execa": "^9.3.0", + "fast-glob": "^3.3.2", + "fs-extra": "^11.2.0", + "https-proxy-agent": "^7.0.5", + "lodash": "^4.17.21", + "lodash.template": "^4.5.0", + "node-fetch": "^3.3.2", + "ora": "^8.0.1", + "picocolors": "^1.0.1", + "prompts": "^2.4.2", + "recast": "^0.23.9", + "ts-morph": "^23.0.0", + "tsconfig-paths": "^4.2.0", + "type-fest": "^4.24.0", + "zod": "^3.23.8" + } +} diff --git a/packages/cli/src/commands/add.ts b/packages/cli/src/commands/add.ts new file mode 100644 index 0000000..9853dd8 --- /dev/null +++ b/packages/cli/src/commands/add.ts @@ -0,0 +1,293 @@ +import path from "path"; +import * as z from "zod"; +import pc from "picocolors"; +import { getConfig } from "@/utils/get-config"; +import { + fetchTree, + getItemTargetPath, + getRegistryBaseColor, + getRegistryIndex, + resolveTree, +} from "@/utils/registry"; +import { execa } from "execa"; +import { getPackageManager } from "@/utils/get-package-manager"; +import { existsSync, promises as fs } from "fs"; +import { transform } from "@/utils/transformers"; +import { confirm, group, multiselect } from "@clack/prompts"; +import ora from "ora"; +import { Command } from "commander"; + +const addOptionsSchema = z.object({ + components: z.array(z.string()).optional(), + yes: z.boolean(), + overwrite: z.boolean(), + cwd: z.string(), + all: z.boolean(), + path: z.string().optional(), +}); + +export const add = new Command() + .name("add") + .description("add a component to your project") + .argument("[components...]", "the components to add") + .option("-y, --yes", "skip confirmation prompt.", true) + .option("-o, --overwrite", "overwrite existing files.", false) + .option( + "-c, --cwd ", + "the working directory. defaults to the current directory.", + process.cwd(), + ) + .option("-a, --all", "add all available components", false) + .option("-p, --path ", "the path to add the component to.") + .action(async (components, opts) => { + try { + const options = addOptionsSchema.parse({ + components, + ...opts, + }); + + const cwd = path.resolve(options.cwd); + + if (!existsSync(cwd)) { + pc.red(pc.bold(`The path ${cwd} does not exist. Please try again.`)); + process.exit(1); + } + + const config = await getConfig(cwd); + + if (!config) { + pc.white( + `Configuration is missing. Please run ${pc.green(`init`)} to create a components.json file.`, + ); + process.exit(1); + } + + const registryIndex = await getRegistryIndex(); + + let selectedComponents = options.all + ? registryIndex.map((entry) => entry.name) + : options.components; + if (!options.components?.length && !options.all) { + const { components } = await group({ + components: () => + multiselect({ + message: "Which components would you like to add?", + options: registryIndex.map((entry) => ({ + value: entry.name, + label: entry.name, + selected: options.all + ? true + : options.components?.includes(entry.name), + })), + }), + }); + + selectedComponents = components as string[]; + } + + if (!selectedComponents?.length) { + pc.yellow(`No components selected. Exiting.`); + process.exit(0); + } + + const tree = await resolveTree(registryIndex, selectedComponents); + const payload = await fetchTree(tree); + const baseColor = await getRegistryBaseColor(); + + if (!payload.length) { + pc.yellow(`Selected components not found. Exiting.`); + process.exit(0); + } + + if (!options.yes) { + const { proceed } = await group({ + proceed: () => + confirm({ + message: `Ready to install components and dependencies. Proceed?`, + initialValue: true, + }), + }); + + if (!proceed) { + process.exit(0); + } + } + + const spinner = ora(`Installing components...`).start(); + for (const item of payload) { + spinner.text = `Installing ${item.name}...`; + const targetDir = await getItemTargetPath( + config, + item, + options.path ? path.resolve(cwd, options.path) : undefined, + ); + + if (!targetDir) { + continue; + } + + if (!existsSync(targetDir)) { + await fs.mkdir(targetDir, { recursive: true }); + } + + const existingComponent = item.files.filter((file) => { + existsSync(path.resolve(targetDir, file.name)); + }); + + if (existingComponent.length && !options.overwrite) { + if (selectedComponents.includes(item.name)) { + spinner.stop(); + + const { overwrite } = await group({ + overwrite: () => + confirm({ + message: `Component ${item.name} already exists. Would you like to overwrite?`, + initialValue: false, + }), + }); + + if (!overwrite) { + pc.blue( + `Skipped ${item.name}. To overwrite, run with the -o flag.`, + ); + continue; + } + + spinner.start(`Installing ${item.name}...`); + } else { + continue; + } + } + + for (const file of item.files) { + let filePath = path.resolve(targetDir, file.name); + + // Run transformers. + const content = await transform({ + filename: file.name, + raw: file.content, + config, + baseColor, + }); + + if (!config.tsx) { + filePath = filePath.replace(/\.tsx$/, ".jsx"); + filePath = filePath.replace(/\.ts$/, ".js"); + } + + await fs.writeFile(filePath, content); + } + + const packageManager = await getPackageManager(cwd); + + // Install dependencies. + if (item.dependencies?.length) { + await execa( + packageManager, + [ + packageManager === "npm" ? "install" : "add", + ...item.dependencies, + ], + { + cwd, + }, + ); + } + + // Install devDependencies. + if (item.devDependencies?.length) { + await execa( + packageManager, + [ + packageManager === "npm" ? "install" : "add", + "-D", + ...item.devDependencies, + ], + { + cwd, + }, + ); + } + + // Handle subcategories (e.g., spinner) + if (item.subcategory?.length) { + const subcategoryComponents = item.subcategory; + + const subcategoryTree = await resolveTree( + registryIndex, + subcategoryComponents, + ); + const subcategoryPayload = await fetchTree(subcategoryTree); + + for (const subitem of subcategoryPayload) { + spinner.text = `Installing subcategory component ${subitem.name}...`; + const subTargetDir = await getItemTargetPath( + config, + subitem, + options.path ? path.resolve(cwd, options.path) : undefined, + ); + + if (!subTargetDir) { + continue; + } + + if (!existsSync(subTargetDir)) { + await fs.mkdir(subTargetDir, { recursive: true }); + } + + for (const file of subitem.files) { + let subFilePath = path.resolve(subTargetDir, file.name); + + // Run transformers. + const subContent = await transform({ + filename: file.name, + raw: file.content, + config, + baseColor, + }); + + if (!config.tsx) { + subFilePath = subFilePath.replace(/\.tsx$/, ".jsx"); + subFilePath = subFilePath.replace(/\.ts$/, ".js"); + } + + await fs.writeFile(subFilePath, subContent); + } + + // Install dependencies for subcategory. + if (subitem.dependencies?.length) { + await execa( + packageManager, + [ + packageManager === "npm" ? "install" : "add", + ...subitem.dependencies, + ], + { + cwd, + }, + ); + } + + // Install devDependencies for subcategory. + if (subitem.devDependencies?.length) { + await execa( + packageManager, + [ + packageManager === "npm" ? "install" : "add", + "-D", + ...subitem.devDependencies, + ], + { + cwd, + }, + ); + } + } + } + } + + spinner.succeed(`Done.`); + } catch (error) { + console.log(error); + } + }); diff --git a/packages/cli/src/commands/init.ts b/packages/cli/src/commands/init.ts new file mode 100644 index 0000000..d89bdae --- /dev/null +++ b/packages/cli/src/commands/init.ts @@ -0,0 +1,347 @@ +import { + cancel, + confirm, + group, + intro, + note, + outro, + text, +} from "@clack/prompts"; +import { existsSync, promises as fs } from "fs"; +import * as templates from "../utils/templates"; +import pc from "picocolors"; +import { + getProjectConfig, + isTypeScriptProject, + preFlight, +} from "@/utils/get-project-info"; +import { + Config, + getConfig, + rawConfigSchema, + resolveConfigPaths, +} from "@/utils/get-config"; +import { getPackageManager } from "@/utils/get-package-manager"; +import path from "path"; +import { execa } from "execa"; +import template from "lodash.template"; +import ora from "ora"; +import { applyPrefixesCss } from "@/utils/transformers/transform-tw-prefix"; +import * as z from "zod"; +import { Command } from "commander"; + +const PROJECT_DEPENDENCIES = [ + "tailwindcss-animate", + "class-variance-authority", + "clsx", + "tailwind-merge", +]; + +const initOptionsSchema = z.object({ + defaults: z.boolean().default(false), + autodetact: z.boolean().default(false), + yes: z.boolean(), + cwd: z.string(), +}); + +export const init = new Command() + .name("init") + .description("initialize your project and install dependencies") + .option("-y, --yes", "skip confirmation prompt.", false) + .option("-d, --defaults", "use default configuration.", false) + .option("-a, --autodetact", "autodetact configuration by freamwork.", false) + .option( + "-c, --cwd ", + "the working directory. defaults to the current directory.", + process.cwd(), + ) + .action(async (opts) => { + console.log("\n"); + intro(pc.white(pc.bold(" 🚀 Welcome to the installation wizard! "))); + + const options = initOptionsSchema.parse(opts); + const cwd = options.cwd; + + preFlight(cwd); + + const projectConfig = await getProjectConfig(cwd); + + if (options.autodetact && projectConfig) { + console.log(pc.green(pc.bold("\n config found! \n "))); + + const config = await promptForMinimalConfig( + cwd, + projectConfig, + options.defaults, + ); + await runInit(cwd, config); + } else { + // Read config. + const existingConfig = await getConfig(cwd); + const config = await promptForConfig( + cwd, + existingConfig, + options.defaults, + ); + await runInit(cwd, config); + } + + const nextSteps = `npx ruru-ui-cli add button `; + + note(nextSteps, "Next steps."); + + outro( + `Problems? ${pc.underline(pc.cyan("https://github.com/ruru-m07/ruru-ui/issues"))}`, + ); + + process.exit(0); + }); + +/** + * ! Prompt for minimal configuration. + */ + +export async function runInit(cwd: string, config: Config) { + const spinner = ora(`Initializing project...`)?.start(); + + // Ensure all resolved paths directories exist. + for (const [key, resolvedPath] of Object.entries(config.resolvedPaths)) { + // Determine if the path is a file or directory. + // TODO: is there a better way to do this? + let dirname = path.extname(resolvedPath) + ? path.dirname(resolvedPath) + : resolvedPath; + + // If the utils alias is set to something like "@/lib/utils", + // assume this is a file and remove the "utils" file name. + // TODO: In future releases we should add support for individual utils. + if (key === "utils" && resolvedPath.endsWith("/utils")) { + // Remove /utils at the end. + dirname = dirname.replace(/\/utils$/, ""); + } + + if (!existsSync(dirname)) { + await fs.mkdir(dirname, { recursive: true }); + } + } + + const extension = config.tsx ? "ts" : "js"; + + const tailwindConfigExtension = path.extname( + config.resolvedPaths.tailwindConfig, + ); + + let tailwindConfigTemplate: string; + if (tailwindConfigExtension === ".ts") { + tailwindConfigTemplate = config.tailwind.cssVariables + ? templates.TAILWIND_CONFIG_TS_WITH_VARIABLES + : templates.TAILWIND_CONFIG_TS; + } else { + tailwindConfigTemplate = config.tailwind.cssVariables + ? templates.TAILWIND_CONFIG_WITH_VARIABLES + : templates.TAILWIND_CONFIG; + } + + // Write tailwind config. + await fs.writeFile( + config.resolvedPaths.tailwindConfig, + template(tailwindConfigTemplate)({ + extension, + prefix: config.tailwind.prefix, + }), + "utf8", + ); + + // Write css file. + // const baseColor = await getRegistryBaseColor(config.tailwind.); + // if (baseColor) { + await fs.writeFile( + config.resolvedPaths.tailwindCss, + config.tailwind.cssVariables + ? config.tailwind.prefix + ? applyPrefixesCss(templates.GLOBLES_CSS_FILES, config.tailwind.prefix) + : templates.GLOBLES_CSS_FILES + : templates.GLOBLES_CSS_FILES, + "utf8", + ); + // } + + // Write cn file. + await fs.writeFile( + `${config.resolvedPaths.utils}.${extension}`, + extension === "ts" ? templates.UTILS : templates.UTILS_JS, + "utf8", + ); + + spinner?.succeed(); + + // Install dependencies. + const dependenciesSpinner = ora(`Installing dependencies...`)?.start(); + const packageManager = await getPackageManager(cwd); + + const deps = [...PROJECT_DEPENDENCIES, "@radix-ui/react-icons"]; + + await execa( + packageManager, + [packageManager === "npm" ? "install" : "add", ...deps], + { + cwd, + }, + ); + dependenciesSpinner?.succeed(); +} + +export async function promptForConfig( + cwd: string, + defaultConfig: Config | null = null, + skip = false, +) { + if (defaultConfig) { + null; + } + + const isTsx = await isTypeScriptProject(cwd); + + const options = await group( + { + typescript: () => + confirm({ + message: `Would you like to use ${pc.bold("TypeScript")} (recommended)?`, + initialValue: true, + }), + defaults: () => + confirm({ + message: `use default configuration.`, + initialValue: false, + }), + tailwindCss: () => + text({ + message: `Where is your ${pc.bold("global CSS")} file?`, + placeholder: "./app/globals.css", + initialValue: "./app/globals.css", + validate: (value) => { + if (!value) return "Please enter a path."; + if (value[0] !== ".") return "Please enter a relative path."; + }, + }), + tailwindConfig: () => + text({ + message: `Where is your ${pc.bold("tailwind.config.js")} located?`, + initialValue: isTsx ? "./tailwind.config.ts" : "./tailwind.config.js", + validate: (value) => { + if (!value) return "Please enter a path."; + if (value[0] !== ".") return "Please enter a relative path."; + }, + }), + tailwindCssVariables: () => + confirm({ + message: `Would you like to use ${pc.bold("CSS variables")} for colors?`, + initialValue: true, + }), + tailwindPrefix: () => + text({ + message: `Are you using a custom ${pc.bold("tailwind prefix eg. tw-")}? (Leave blank if not)`, + initialValue: "", + defaultValue: "", + placeholder: "(Leave blank if not)", + }), + components: () => + text({ + message: `Configure the import alias for ${pc.bold("components")}:`, + placeholder: "@/components/ui", + initialValue: "@/components/ui", + }), + utils: () => + text({ + message: `Configure the import alias for ${pc.bold("utils")}:`, + placeholder: "@/lib/utils", + initialValue: "@/lib/utils", + }), + rsc: () => + confirm({ + message: `Would you like to use ${pc.bold("RSC")} ?`, + initialValue: true, + }), + }, + { + onCancel: () => { + cancel("Installation Stopped."); + process.exit(0); + }, + }, + ); + + const config = rawConfigSchema.parse({ + tailwind: { + config: options.tailwindConfig, + css: options.tailwindCss, + cssVariables: options.tailwindCssVariables, + prefix: options.tailwindPrefix, + }, + rsc: options.rsc, + tsx: options.typescript, + aliases: { + components: options.components, + utils: options.utils, + ui: options.components, + }, + }); + + if (!skip) { + const proceed = confirm({ + message: `Write configuration to ${pc.bold("components.json")}. Proceed??`, + initialValue: true, + }); + + if (!proceed) { + process.exit(0); + } + } + + // Write to file. + + const spinner = ora(`Writing components.json...`)?.start(); + const targetPath = path.resolve(cwd, "components.json"); + await fs.writeFile(targetPath, JSON.stringify(config, null, 2), "utf8"); + spinner.succeed(); + + return await resolveConfigPaths(cwd, config); +} + +export async function promptForMinimalConfig( + cwd: string, + defaultConfig: Config, + defaults = false, +) { + let cssVariables = defaultConfig.tailwind.cssVariables; + + if (!defaults) { + const options = await group({ + tailwindCssVariables: () => + confirm({ + message: `Would you like to use ${pc.bold("CSS variables")} for colors?`, + initialValue: true, + }), + }); + + cssVariables = options.tailwindCssVariables; + } + + const config = rawConfigSchema.parse({ + tailwind: { + ...defaultConfig?.tailwind, + cssVariables, + }, + rsc: defaultConfig?.rsc, + tsx: defaultConfig?.tsx, + aliases: defaultConfig?.aliases, + }); + + // Write to file. + const spinner = ora(`Writing components.json...`).start(); + const targetPath = path.resolve(cwd, "components.json"); + await fs.writeFile(targetPath, JSON.stringify(config, null, 2), "utf8"); + spinner.succeed(); + + return await resolveConfigPaths(cwd, config); +} diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts new file mode 100644 index 0000000..9da03ec --- /dev/null +++ b/packages/cli/src/index.ts @@ -0,0 +1,29 @@ +#!/usr/bin/env node + +import "dotenv/config"; +import { Command } from "commander"; +import { getPackageInfo } from "./utils"; +import { init } from "./commands/init"; +import { add } from "./commands/add"; + +async function main(): Promise { + const program = new Command(); + + program + .name("Ruru-UI") + .description("CLI tool to initialize Ruru-UI") + .version( + getPackageInfo().version || "1.0.0", + "-v, --version", + "display the version number", + ); + + program.addCommand(init).addCommand(add); + + program.parse(); +} + +main().catch((e: unknown) => { + console.error(e); + throw e; +}); diff --git a/packages/cli/src/utils/get-config.ts b/packages/cli/src/utils/get-config.ts new file mode 100644 index 0000000..8c7ca01 --- /dev/null +++ b/packages/cli/src/utils/get-config.ts @@ -0,0 +1,100 @@ +import path from "path"; +import { resolveImport } from "@/utils/resolve-import"; +import { cosmiconfig } from "cosmiconfig"; +import { loadConfig } from "tsconfig-paths"; +import { z } from "zod"; + +export const DEFAULT_STYLE = "default"; +export const DEFAULT_COMPONENTS = "@/components/ui"; +export const DEFAULT_UTILS = "@/lib/utils"; +export const DEFAULT_TAILWIND_CSS = "app/globals.css"; +export const DEFAULT_TAILWIND_CONFIG = "tailwind.config.js"; +export const DEFAULT_TAILWIND_BASE_COLOR = "slate"; + +// TODO: Figure out if we want to support all cosmiconfig formats. +// A simple components.json file would be nice. +const explorer = cosmiconfig("components", { + searchPlaces: ["components.json"], +}); + +export const rawConfigSchema = z + .object({ + rsc: z.coerce.boolean().default(false), + tsx: z.coerce.boolean().default(true), + tailwind: z.object({ + config: z.string(), + css: z.string(), + cssVariables: z.boolean().default(true), + prefix: z.string().default("").optional(), + }), + aliases: z.object({ + components: z.string(), + utils: z.string(), + ui: z.string().optional(), + }), + }) + .strict(); + +export type RawConfig = z.infer; + +export const configSchema = rawConfigSchema.extend({ + resolvedPaths: z.object({ + tailwindConfig: z.string(), + tailwindCss: z.string(), + utils: z.string(), + components: z.string(), + ui: z.string(), + }), +}); + +export type Config = z.infer; + +export async function getConfig(cwd: string) { + const config = await getRawConfig(cwd); + + if (!config) { + return null; + } + + return await resolveConfigPaths(cwd, config); +} + +export async function resolveConfigPaths(cwd: string, config: RawConfig) { + // Read tsconfig.json. + const tsConfig = await loadConfig(cwd); + + if (tsConfig.resultType === "failed") { + throw new Error( + `Failed to load ${config.tsx ? "tsconfig" : "jsconfig"}.json. ${ + tsConfig.message ?? "" + }`.trim(), + ); + } + + return configSchema.parse({ + ...config, + resolvedPaths: { + tailwindConfig: path.resolve(cwd, config.tailwind.config), + tailwindCss: path.resolve(cwd, config.tailwind.css), + utils: await resolveImport(config.aliases["utils"], tsConfig), + components: await resolveImport(config.aliases["components"], tsConfig), + ui: config.aliases["ui"] + ? await resolveImport(config.aliases["ui"], tsConfig) + : await resolveImport(config.aliases["components"], tsConfig), + }, + }); +} + +export async function getRawConfig(cwd: string): Promise { + try { + const configResult = await explorer.search(cwd); + + if (!configResult) { + return null; + } + + return rawConfigSchema.parse(configResult.config); + } catch (error) { + throw new Error(`Invalid configuration found in ${cwd}/components.json.`); + } +} diff --git a/packages/cli/src/utils/get-package-manager.ts b/packages/cli/src/utils/get-package-manager.ts new file mode 100644 index 0000000..6afed08 --- /dev/null +++ b/packages/cli/src/utils/get-package-manager.ts @@ -0,0 +1,13 @@ +import { detect } from "@antfu/ni"; + +export async function getPackageManager( + targetDir: string, +): Promise<"yarn" | "pnpm" | "bun" | "npm"> { + const packageManager = await detect({ programmatic: true, cwd: targetDir }); + + if (packageManager === "yarn@berry") return "yarn"; + if (packageManager === "pnpm@6") return "pnpm"; + if (packageManager === "bun") return "bun"; + + return packageManager ?? "npm"; +} diff --git a/packages/cli/src/utils/get-project-info.ts b/packages/cli/src/utils/get-project-info.ts new file mode 100644 index 0000000..e83d7a0 --- /dev/null +++ b/packages/cli/src/utils/get-project-info.ts @@ -0,0 +1,184 @@ +import { existsSync } from "fs"; +import path from "path"; +import { Config, RawConfig, getConfig, resolveConfigPaths } from "./get-config"; +import fg from "fast-glob"; +import fs, { pathExists } from "fs-extra"; +import { loadConfig } from "tsconfig-paths"; + +const PROJECT_TYPES = [ + "next-app", + "next-app-src", + "next-pages", + "next-pages-src", +] as const; + +type ProjectType = (typeof PROJECT_TYPES)[number]; + +const PROJECT_SHARED_IGNORE = [ + "**/node_modules/**", + ".next", + "public", + "dist", + "build", +]; + +export async function getProjectInfo() { + const info = { + tsconfig: null, + srcDir: false, + appDir: false, + srcComponentsUiDir: false, + componentsUiDir: false, + }; + + try { + const tsconfig = await getTsConfig(); + + return { + tsconfig, + srcDir: existsSync(path.resolve("./src")), + appDir: + existsSync(path.resolve("./app")) || + existsSync(path.resolve("./src/app")), + srcComponentsUiDir: existsSync(path.resolve("./src/components/ui")), + componentsUiDir: existsSync(path.resolve("./components/ui")), + }; + } catch (error) { + return info; + } +} + +export async function getTsConfig() { + try { + const tsconfigPath = path.join("tsconfig.json"); + const tsconfig = await fs.readJSON(tsconfigPath); + + if (!tsconfig) { + throw new Error("tsconfig.json is missing"); + } + + return tsconfig; + } catch (error) { + return null; + } +} + +export async function getProjectConfig(cwd: string): Promise { + // Check for existing component config. + const existingConfig = await getConfig(cwd); + if (existingConfig) { + return existingConfig; + } + + const projectType = await getProjectType(cwd); + const tailwindCssFile = await getTailwindCssFile(cwd); + const tsConfigAliasPrefix = await getTsConfigAliasPrefix(cwd); + + if (!projectType || !tailwindCssFile || !tsConfigAliasPrefix) { + return null; + } + + const isTsx = await isTypeScriptProject(cwd); + + const config: RawConfig = { + rsc: ["next-app", "next-app-src"].includes(projectType), + tsx: isTsx, + tailwind: { + config: isTsx ? "tailwind.config.ts" : "tailwind.config.js", + css: tailwindCssFile, + cssVariables: true, + prefix: "", + }, + aliases: { + utils: `${tsConfigAliasPrefix}/lib/utils`, + components: `${tsConfigAliasPrefix}/components`, + }, + }; + + return await resolveConfigPaths(cwd, config); +} + +export async function getProjectType(cwd: string): Promise { + const files = await fg.glob("**/*", { + cwd, + deep: 3, + ignore: PROJECT_SHARED_IGNORE, + }); + + const isNextProject = files.find((file) => file.startsWith("next.config.")); + if (!isNextProject) { + return null; + } + + const isUsingSrcDir = await fs.pathExists(path.resolve(cwd, "src")); + const isUsingAppDir = await fs.pathExists( + path.resolve(cwd, `${isUsingSrcDir ? "src/" : ""}app`), + ); + + if (isUsingAppDir) { + return isUsingSrcDir ? "next-app-src" : "next-app"; + } + + return isUsingSrcDir ? "next-pages-src" : "next-pages"; +} + +export async function getTailwindCssFile(cwd: string) { + const files = await fg.glob("**/*.css", { + cwd, + deep: 3, + ignore: PROJECT_SHARED_IGNORE, + }); + + if (!files.length) { + return null; + } + + for (const file of files) { + const contents = await fs.readFile(path.resolve(cwd, file), "utf8"); + // Assume that if the file contains `@tailwind base` it's the main css file. + if (contents.includes("@tailwind base")) { + return file; + } + } + + return null; +} + +export async function getTsConfigAliasPrefix(cwd: string) { + const tsConfig = await loadConfig(cwd); + + if (tsConfig?.resultType === "failed" || !tsConfig?.paths) { + return null; + } + + // This assume that the first alias is the prefix. + for (const [alias, paths] of Object.entries(tsConfig.paths)) { + if (paths.includes("./*") || paths.includes("./src/*")) { + return alias.at(0); + } + } + + return null; +} + +export async function isTypeScriptProject(cwd: string) { + // Check if cwd has a tsconfig.json file. + return pathExists(path.resolve(cwd, "tsconfig.json")); +} + +export async function preFlight(cwd: string) { + // We need Tailwind CSS to be configured. + const tailwindConfig = await fg.glob("tailwind.config.*", { + cwd, + deep: 3, + ignore: PROJECT_SHARED_IGNORE, + }); + + if (!tailwindConfig.length) { + throw new Error( + "Tailwind CSS is not installed. Visit https://tailwindcss.com/docs/installation to get started.", + ); + } + + return true; +} diff --git a/packages/cli/src/utils/index.ts b/packages/cli/src/utils/index.ts new file mode 100644 index 0000000..a6fd00d --- /dev/null +++ b/packages/cli/src/utils/index.ts @@ -0,0 +1,20 @@ +import path from "path"; +import fs from "fs-extra"; +import { type PackageJson } from "type-fest"; + +export function getPackageInfo() { + const packageJsonPath = path.join("../../package.json"); + + return fs.readJSONSync(packageJsonPath) as PackageJson; +} + +export function config() { + // const baseUrl = "http://localhost:3000"; + + const baseUrl = + process.env.NODE_ENV === "development" + ? "http://localhost:3000" + : "https://ruru-ui.vercel.app"; + + return { baseUrl }; +} diff --git a/packages/cli/src/utils/registry/color.ts b/packages/cli/src/utils/registry/color.ts new file mode 100644 index 0000000..6bbb427 --- /dev/null +++ b/packages/cli/src/utils/registry/color.ts @@ -0,0 +1,104 @@ +export const basecolor = { + inlineColors: { + light: { + background: "white", + foreground: "neutral-950", + card: "white", + "card-foreground": "neutral-950", + popover: "white", + "popover-foreground": "neutral-950", + primary: "neutral-900", + "primary-foreground": "neutral-50", + secondary: "neutral-100", + "secondary-foreground": "neutral-900", + muted: "neutral-100", + "muted-foreground": "neutral-500", + accent: "neutral-100", + "accent-foreground": "neutral-900", + destructive: "red-500", + "destructive-foreground": "neutral-50", + border: "neutral-200", + input: "neutral-200", + ring: "neutral-950", + }, + dark: { + background: "neutral-950", + foreground: "neutral-50", + card: "neutral-950", + "card-foreground": "neutral-50", + popover: "neutral-950", + "popover-foreground": "neutral-50", + primary: "neutral-50", + "primary-foreground": "neutral-900", + secondary: "neutral-800", + "secondary-foreground": "neutral-50", + muted: "neutral-800", + "muted-foreground": "neutral-400", + accent: "neutral-800", + "accent-foreground": "neutral-50", + destructive: "red-900", + "destructive-foreground": "neutral-50", + border: "neutral-800", + input: "neutral-800", + ring: "neutral-300", + }, + }, + cssVars: { + light: { + background: "0 0% 100%", + foreground: "0 0% 3.9%", + card: "0 0% 100%", + "card-foreground": "0 0% 3.9%", + popover: "0 0% 100%", + "popover-foreground": "0 0% 3.9%", + primary: "0 0% 9%", + "primary-foreground": "0 0% 98%", + secondary: "0 0% 96.1%", + "secondary-foreground": "0 0% 9%", + muted: "0 0% 96.1%", + "muted-foreground": "0 0% 45.1%", + accent: "0 0% 96.1%", + "accent-foreground": "0 0% 9%", + destructive: "0 84.2% 60.2%", + "destructive-foreground": "0 0% 98%", + border: "0 0% 89.8%", + input: "0 0% 89.8%", + ring: "0 0% 3.9%", + "chart-1": "12 76% 61%", + "chart-2": "173 58% 39%", + "chart-3": "197 37% 24%", + "chart-4": "43 74% 66%", + "chart-5": "27 87% 67%", + }, + dark: { + background: "0 0% 3.9%", + foreground: "0 0% 98%", + card: "0 0% 3.9%", + "card-foreground": "0 0% 98%", + popover: "0 0% 3.9%", + "popover-foreground": "0 0% 98%", + primary: "0 0% 98%", + "primary-foreground": "0 0% 9%", + secondary: "0 0% 14.9%", + "secondary-foreground": "0 0% 98%", + muted: "0 0% 14.9%", + "muted-foreground": "0 0% 63.9%", + accent: "0 0% 14.9%", + "accent-foreground": "0 0% 98%", + destructive: "0 62.8% 30.6%", + "destructive-foreground": "0 0% 98%", + border: "0 0% 14.9%", + input: "0 0% 14.9%", + ring: "0 0% 83.1%", + "chart-1": "220 70% 50%", + "chart-2": "160 60% 45%", + "chart-3": "30 80% 55%", + "chart-4": "280 65% 60%", + "chart-5": "340 75% 55%", + }, + }, + inlineColorsTemplate: + "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n ", + cssVarsTemplate: + "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n@layer base {\n :root {\n --background: 0 0% 100%;\n --foreground: 0 0% 3.9%;\n --card: 0 0% 100%;\n --card-foreground: 0 0% 3.9%;\n --popover: 0 0% 100%;\n --popover-foreground: 0 0% 3.9%;\n --primary: 0 0% 9%;\n --primary-foreground: 0 0% 98%;\n --secondary: 0 0% 96.1%;\n --secondary-foreground: 0 0% 9%;\n --muted: 0 0% 96.1%;\n --muted-foreground: 0 0% 45.1%;\n --accent: 0 0% 96.1%;\n --accent-foreground: 0 0% 9%;\n --destructive: 0 84.2% 60.2%;\n --destructive-foreground: 0 0% 98%;\n --border: 0 0% 89.8%;\n --input: 0 0% 89.8%;\n --ring: 0 0% 3.9%;\n --radius: 0.5rem;\n --chart-1: 12 76% 61%;\n --chart-2: 173 58% 39%;\n --chart-3: 197 37% 24%;\n --chart-4: 43 74% 66%;\n --chart-5: 27 87% 67%;\n }\n\n .dark {\n --background: 0 0% 3.9%;\n --foreground: 0 0% 98%;\n --card: 0 0% 3.9%;\n --card-foreground: 0 0% 98%;\n --popover: 0 0% 3.9%;\n --popover-foreground: 0 0% 98%;\n --primary: 0 0% 98%;\n --primary-foreground: 0 0% 9%;\n --secondary: 0 0% 14.9%;\n --secondary-foreground: 0 0% 98%;\n --muted: 0 0% 14.9%;\n --muted-foreground: 0 0% 63.9%;\n --accent: 0 0% 14.9%;\n --accent-foreground: 0 0% 98%;\n --destructive: 0 62.8% 30.6%;\n --destructive-foreground: 0 0% 98%;\n --border: 0 0% 14.9%;\n --input: 0 0% 14.9%;\n --ring: 0 0% 83.1%;\n --chart-1: 220 70% 50%;\n --chart-2: 160 60% 45%;\n --chart-3: 30 80% 55%;\n --chart-4: 280 65% 60%;\n --chart-5: 340 75% 55%;\n }\n}\n\n@layer base {\n * {\n @apply border-border;\n }\n body {\n @apply bg-background text-foreground;\n }\n}", +}; diff --git a/packages/cli/src/utils/registry/index.ts b/packages/cli/src/utils/registry/index.ts new file mode 100644 index 0000000..cd29be2 --- /dev/null +++ b/packages/cli/src/utils/registry/index.ts @@ -0,0 +1,154 @@ +import path from "path"; +import { Config } from "@/utils/get-config"; +import { + registryBaseColorSchema, + registryIndexSchema, + registryItemWithContentSchema, + registryWithContentSchema, + stylesSchema, +} from "@/utils/registry/schema"; +import { HttpsProxyAgent } from "https-proxy-agent"; +import fetch from "node-fetch"; +import { z } from "zod"; +import { config } from "@/utils"; + +const { baseUrl } = config(); + +const agent = process.env.https_proxy + ? new HttpsProxyAgent(process.env.https_proxy) + : undefined; + +export async function getRegistryIndex() { + try { + const [result] = await fetchRegistry(["index.json"]); + + return registryIndexSchema.parse(result); + } catch (error) { + throw new Error(`Failed to fetch components from registry.`); + } +} + +export async function getRegistryStyles() { + try { + const [result] = await fetchRegistry(["styles/index.json"]); + + return stylesSchema.parse(result); + } catch (error) { + throw new Error(`Failed to fetch styles from registry.`); + } +} + +export async function getRegistryBaseColors() { + return [ + { + name: "slate", + label: "Slate", + }, + { + name: "gray", + label: "Gray", + }, + { + name: "zinc", + label: "Zinc", + }, + { + name: "neutral", + label: "Neutral", + }, + { + name: "stone", + label: "Stone", + }, + ]; +} + +export async function getRegistryBaseColor() { + try { + const [result] = await fetchRegistry([`colors/basecolor.json`]); + + return registryBaseColorSchema.parse(result); + } catch (error) { + throw new Error(`Failed to fetch base color from registry.`); + } +} + +export async function resolveTree( + index: z.infer, + names: string[], +) { + const tree: z.infer = []; + + for (const name of names) { + const entry = index.find((entry) => entry.name === name); + + if (!entry) { + continue; + } + + tree.push(entry); + + if (entry.registryDependencies) { + const dependencies = await resolveTree(index, entry.registryDependencies); + tree.push(...dependencies); + } + } + + return tree.filter( + (component, index, self) => + self.findIndex((c) => c.name === component.name) === index, + ); +} + +export async function fetchTree(tree: z.infer) { + try { + const paths = tree.map((item) => `components/${item.name}.json`); + const result = await fetchRegistry(paths); + + return registryWithContentSchema.parse(result); + } catch (error) { + throw new Error(`Failed to fetch tree from registry.`); + } +} + +export async function getItemTargetPath( + config: Config, + item: Pick, "type">, + override?: string, +) { + if (override) { + return override; + } + + if (item.type === "components:ui" && config.aliases.ui) { + return config.resolvedPaths.ui; + } + + const [parent, type] = item.type.split(":"); + if (!(parent in config.resolvedPaths)) { + return null; + } + + return path.join( + config.resolvedPaths[parent as keyof typeof config.resolvedPaths], + type, + ); +} + +async function fetchRegistry(paths: string[]) { + try { + const results = await Promise.all( + paths.map(async (path) => { + const response = await fetch(`${baseUrl}/registry/${path}`, { + agent, + }); + return await response.json(); + }), + ); + + return results; + } catch (error) { + console.log(error); + throw new Error(`Failed to fetch registry from ${baseUrl}.`); + } +} diff --git a/packages/cli/src/utils/registry/schema.ts b/packages/cli/src/utils/registry/schema.ts new file mode 100644 index 0000000..0586de2 --- /dev/null +++ b/packages/cli/src/utils/registry/schema.ts @@ -0,0 +1,45 @@ +import { z } from "zod"; + +// TODO: Extract this to a shared package. +export const registryItemSchema = z.object({ + name: z.string(), + dependencies: z.array(z.string()).optional(), + devDependencies: z.array(z.string()).optional(), + registryDependencies: z.array(z.string()).optional(), + files: z.array(z.string()), + subcategory: z.array(z.string()).optional(), + type: z.enum(["components:ui", "components:component", "components:example"]), +}); + +export const registryIndexSchema = z.array(registryItemSchema); + +export const registryItemWithContentSchema = registryItemSchema.extend({ + files: z.array( + z.object({ + name: z.string(), + content: z.string(), + }), + ), +}); + +export const registryWithContentSchema = z.array(registryItemWithContentSchema); + +export const stylesSchema = z.array( + z.object({ + name: z.string(), + label: z.string(), + }), +); + +export const registryBaseColorSchema = z.object({ + inlineColors: z.object({ + light: z.record(z.string(), z.string()), + dark: z.record(z.string(), z.string()), + }), + cssVars: z.object({ + light: z.record(z.string(), z.string()), + dark: z.record(z.string(), z.string()), + }), + inlineColorsTemplate: z.string(), + cssVarsTemplate: z.string(), +}); diff --git a/packages/cli/src/utils/resolve-import.ts b/packages/cli/src/utils/resolve-import.ts new file mode 100644 index 0000000..18ac294 --- /dev/null +++ b/packages/cli/src/utils/resolve-import.ts @@ -0,0 +1,16 @@ +import { + createMatchPath, + type ConfigLoaderSuccessResult, +} from "tsconfig-paths"; + +export async function resolveImport( + importPath: string, + config: Pick, +) { + return createMatchPath(config.absoluteBaseUrl, config.paths)( + importPath, + undefined, + () => true, + [".ts", ".tsx"], + ); +} diff --git a/packages/cli/src/utils/templates.ts b/packages/cli/src/utils/templates.ts new file mode 100644 index 0000000..4163f95 --- /dev/null +++ b/packages/cli/src/utils/templates.ts @@ -0,0 +1,327 @@ +export const UTILS = `import { ClassNameValue, twMerge } from "tailwind-merge"; + +export const cn: (...classLists: ClassNameValue[]) => string = twMerge; +`; + +export const UTILS_JS = `import { ClassNameValue, twMerge } from "tailwind-merge"; + +export const cn = twMerge; +`; + +export const TAILWIND_CONFIG = `/** @type {import('tailwindcss').Config} */ +module.exports = { + darkMode: ["class"], + content: [ + "./pages/**/*.{<%- extension %>,<%- extension %>x}", + "./components/**/*.{<%- extension %>,<%- extension %>x}", + "./app/**/*.{<%- extension %>,<%- extension %>x}", + "./src/**/*.{<%- extension %>,<%- extension %>x}", + ], + prefix: "<%- prefix %>", + theme: { + container: { + center: true, + padding: "2rem", + screens: { + "2xl": "1400px", + }, + }, + extend: { + keyframes: { + "accordion-down": { + from: { height: "0" }, + to: { height: "var(--radix-accordion-content-height)" }, + }, + "accordion-up": { + from: { height: "var(--radix-accordion-content-height)" }, + to: { height: "0" }, + }, + spinner: { + from: { opacity: "1" }, + to: { opacity: "0.15" }, + }, + }, + animation: { + "accordion-down": "accordion-down 0.2s ease-out", + "accordion-up": "accordion-up 0.2s ease-out", + spinner: "spinner 1.2s linear infinite", + }, + }, + }, + plugins: [require("tailwindcss-animate")], +}; +`; + +export const TAILWIND_CONFIG_WITH_VARIABLES = `/** @type {import('tailwindcss').Config} */ +module.exports = { + darkMode: ["class"], + content: [ + './pages/**/*.{<%- extension %>,<%- extension %>x}', + './components/**/*.{<%- extension %>,<%- extension %>x}', + './app/**/*.{<%- extension %>,<%- extension %>x}', + './src/**/*.{<%- extension %>,<%- extension %>x}', + ], + prefix: "<%- prefix %>", + theme: { + container: { + center: true, + padding: "2rem", + screens: { + "2xl": "1400px", + }, + }, + extend: { + colors: { + border: "hsl(var(--border))", + input: "hsl(var(--input))", + ring: "hsl(var(--ring))", + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", + primary: { + DEFAULT: "hsl(var(--primary))", + foreground: "hsl(var(--primary-foreground))", + }, + secondary: { + DEFAULT: "hsl(var(--secondary))", + foreground: "hsl(var(--secondary-foreground))", + }, + destructive: { + DEFAULT: "hsl(var(--destructive))", + foreground: "hsl(var(--destructive-foreground))", + }, + muted: { + DEFAULT: "hsl(var(--muted))", + foreground: "hsl(var(--muted-foreground))", + }, + accent: { + DEFAULT: "hsl(var(--accent))", + foreground: "hsl(var(--accent-foreground))", + }, + popover: { + DEFAULT: "hsl(var(--popover))", + foreground: "hsl(var(--popover-foreground))", + }, + card: { + DEFAULT: "hsl(var(--card))", + foreground: "hsl(var(--card-foreground))", + }, + }, + borderRadius: { + lg: "var(--radius)", + md: "calc(var(--radius) - 2px)", + sm: "calc(var(--radius) - 4px)", + }, + keyframes: { + "accordion-down": { + from: { height: "0" }, + to: { height: "var(--radix-accordion-content-height)" }, + }, + "accordion-up": { + from: { height: "var(--radix-accordion-content-height)" }, + to: { height: "0" }, + }, + }, + animation: { + "accordion-down": "accordion-down 0.2s ease-out", + "accordion-up": "accordion-up 0.2s ease-out", + }, + }, + }, + plugins: [require("tailwindcss-animate")], +}`; + +export const TAILWIND_CONFIG_TS = `/** @type {import('tailwindcss').Config} */ +module.exports = { + darkMode: ["class"], + content: [ + "./pages/**/*.{<%- extension %>,<%- extension %>x}", + "./components/**/*.{<%- extension %>,<%- extension %>x}", + "./app/**/*.{<%- extension %>,<%- extension %>x}", + "./src/**/*.{<%- extension %>,<%- extension %>x}", + ], + prefix: "<%- prefix %>", + theme: { + container: { + center: true, + padding: "2rem", + screens: { + "2xl": "1400px", + }, + }, + extend: { + keyframes: { + "accordion-down": { + from: { height: "0" }, + to: { height: "var(--radix-accordion-content-height)" }, + }, + "accordion-up": { + from: { height: "var(--radix-accordion-content-height)" }, + to: { height: "0" }, + }, + spinner: { + from: { opacity: "1" }, + to: { opacity: "0.15" }, + }, + }, + animation: { + "accordion-down": "accordion-down 0.2s ease-out", + "accordion-up": "accordion-up 0.2s ease-out", + spinner: "spinner 1.2s linear infinite", + }, + }, + }, + plugins: [require("tailwindcss-animate")], +}; +`; + +export const TAILWIND_CONFIG_TS_WITH_VARIABLES = `import type { Config } from "tailwindcss" + +const config = { + darkMode: ["class"], + content: [ + './pages/**/*.{<%- extension %>,<%- extension %>x}', + './components/**/*.{<%- extension %>,<%- extension %>x}', + './app/**/*.{<%- extension %>,<%- extension %>x}', + './src/**/*.{<%- extension %>,<%- extension %>x}', + ], + prefix: "<%- prefix %>", + theme: { + container: { + center: true, + padding: "2rem", + screens: { + "2xl": "1400px", + }, + }, + extend: { + colors: { + border: "hsl(var(--border))", + input: "hsl(var(--input))", + ring: "hsl(var(--ring))", + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", + primary: { + DEFAULT: "hsl(var(--primary))", + foreground: "hsl(var(--primary-foreground))", + }, + secondary: { + DEFAULT: "hsl(var(--secondary))", + foreground: "hsl(var(--secondary-foreground))", + }, + destructive: { + DEFAULT: "hsl(var(--destructive))", + foreground: "hsl(var(--destructive-foreground))", + }, + muted: { + DEFAULT: "hsl(var(--muted))", + foreground: "hsl(var(--muted-foreground))", + }, + accent: { + DEFAULT: "hsl(var(--accent))", + foreground: "hsl(var(--accent-foreground))", + }, + popover: { + DEFAULT: "hsl(var(--popover))", + foreground: "hsl(var(--popover-foreground))", + }, + card: { + DEFAULT: "hsl(var(--card))", + foreground: "hsl(var(--card-foreground))", + }, + }, + borderRadius: { + lg: "var(--radius)", + md: "calc(var(--radius) - 2px)", + sm: "calc(var(--radius) - 4px)", + }, + keyframes: { + "accordion-down": { + from: { height: "0" }, + to: { height: "var(--radix-accordion-content-height)" }, + }, + "accordion-up": { + from: { height: "var(--radix-accordion-content-height)" }, + to: { height: "0" }, + }, + }, + animation: { + "accordion-down": "accordion-down 0.2s ease-out", + "accordion-up": "accordion-up 0.2s ease-out", + }, + }, + }, + plugins: [require("tailwindcss-animate")], +} satisfies Config + +export default config`; + +export const GLOBLES_CSS_FILES = `@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + --card: 0 0% 100%; + --card-foreground: 222.2 84% 4.9%; + --popover: 0 0% 100%; + --popover-foreground: 222.2 84% 4.9%; + --primary: 222.2 47.4% 11.2%; + --primary-foreground: 210 40% 98%; + --secondary: 210 40% 96.1%; + --secondary-foreground: 222.2 47.4% 11.2%; + --muted: 210 40% 96.1%; + --muted-foreground: 215.4 16.3% 46.9%; + --accent: 210 40% 96.1%; + --accent-foreground: 222.2 47.4% 11.2%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 210 40% 98%; + --border: 214.3 31.8% 91.4%; + --input: 214.3 31.8% 91.4%; + --ring: 222.2 84% 4.9%; + --radius: 0.5rem; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + } + + .dark { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + --card: 222.2 84% 4.9%; + --card-foreground: 210 40% 98%; + --popover: 222.2 84% 4.9%; + --popover-foreground: 210 40% 98%; + --primary: 210 40% 98%; + --primary-foreground: 222.2 47.4% 11.2%; + --secondary: 217.2 32.6% 17.5%; + --secondary-foreground: 210 40% 98%; + --muted: 217.2 32.6% 17.5%; + --muted-foreground: 215 20.2% 65.1%; + --accent: 217.2 32.6% 17.5%; + --accent-foreground: 210 40% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 40% 98%; + --border: 217.2 32.6% 17.5%; + --input: 217.2 32.6% 17.5%; + --ring: 212.7 26.8% 83.9%; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} +`; diff --git a/packages/cli/src/utils/transformers/index.ts b/packages/cli/src/utils/transformers/index.ts new file mode 100644 index 0000000..5db5da0 --- /dev/null +++ b/packages/cli/src/utils/transformers/index.ts @@ -0,0 +1,58 @@ +import { promises as fs } from "fs"; +import { tmpdir } from "os"; +import path from "path"; +import { Config } from "@/utils/get-config"; +import { registryBaseColorSchema } from "@/utils/registry/schema"; +import { transformCssVars } from "@/utils/transformers/transform-css-vars"; +import { transformImport } from "@/utils/transformers/transform-import"; +import { transformJsx } from "@/utils/transformers/transform-jsx"; +import { transformRsc } from "@/utils/transformers/transform-rsc"; +import { Project, ScriptKind, type SourceFile } from "ts-morph"; +import { z } from "zod"; + +import { transformTwPrefixes } from "./transform-tw-prefix"; + +export type TransformOpts = { + filename: string; + raw: string; + config: Config; + baseColor?: z.infer; +}; + +export type Transformer = ( + opts: TransformOpts & { + sourceFile: SourceFile; + }, +) => Promise; + +const transformers: Transformer[] = [ + transformImport, + transformRsc, + transformCssVars, + transformTwPrefixes, +]; + +const project = new Project({ + compilerOptions: {}, +}); + +async function createTempSourceFile(filename: string) { + const dir = await fs.mkdtemp(path.join(tmpdir(), "ruru-")); + return path.join(dir, filename); +} + +export async function transform(opts: TransformOpts) { + const tempFile = await createTempSourceFile(opts.filename); + const sourceFile = project.createSourceFile(tempFile, opts.raw, { + scriptKind: ScriptKind.TSX, + }); + + for (const transformer of transformers) { + transformer({ sourceFile, ...opts }); + } + + return await transformJsx({ + sourceFile, + ...opts, + }); +} diff --git a/packages/cli/src/utils/transformers/transform-css-vars.ts b/packages/cli/src/utils/transformers/transform-css-vars.ts new file mode 100644 index 0000000..a367f29 --- /dev/null +++ b/packages/cli/src/utils/transformers/transform-css-vars.ts @@ -0,0 +1,108 @@ +import { registryBaseColorSchema } from "@/utils/registry/schema"; +import { Transformer } from "@/utils/transformers"; +import { SyntaxKind } from "ts-morph"; +import { z } from "zod"; + +export const transformCssVars: Transformer = async ({ + sourceFile, + config, + baseColor, +}) => { + // No transform if using css variables. + if (config.tailwind?.cssVariables || !baseColor?.inlineColors) { + return sourceFile; + } + + sourceFile.getDescendantsOfKind(SyntaxKind.StringLiteral).forEach((node) => { + const value = node.getText(); + if (value) { + const valueWithColorMapping = applyColorMapping( + value.replace(/"/g, ""), + baseColor.inlineColors, + ); + node.replaceWithText(`"${valueWithColorMapping.trim()}"`); + } + }); + + return sourceFile; +}; + +// Splits a className into variant-name-alpha. +// eg. hover:bg-primary-100 -> [hover, bg-primary, 100] +export function splitClassName(className: string): (string | null)[] { + if (!className.includes("/") && !className.includes(":")) { + return [null, className, null]; + } + + const parts: (string | null)[] = []; + // First we split to find the alpha. + const [rest, alpha] = className.split("/"); + + // Check if rest has a colon. + if (!rest.includes(":")) { + return [null, rest, alpha]; + } + + // Next we split the rest by the colon. + const split = rest.split(":"); + + // We take the last item from the split as the name. + const name = split.pop(); + + // We glue back the rest of the split. + const variant = split.join(":"); + + // Finally we push the variant, name and alpha. + parts.push(variant ?? null, name ?? null, alpha ?? null); + + return parts; +} + +const PREFIXES = ["bg-", "text-", "border-", "ring-offset-", "ring-"]; + +export function applyColorMapping( + input: string, + mapping: z.infer["inlineColors"], +) { + // Handle border classes. + if (input.includes(" border ")) { + input = input.replace(" border ", " border border-border "); + } + + // Build color mappings. + const classNames = input.split(" "); + const lightMode = new Set(); + const darkMode = new Set(); + for (const className of classNames) { + const [variant, value, modifier] = splitClassName(className); + const prefix = PREFIXES.find((prefix) => value?.startsWith(prefix)); + if (!prefix) { + if (!lightMode.has(className)) { + lightMode.add(className); + } + continue; + } + + const needle = value?.replace(prefix, ""); + if (needle && needle in mapping.light) { + lightMode.add( + [variant, `${prefix}${mapping.light[needle]}`] + .filter(Boolean) + .join(":") + (modifier ? `/${modifier}` : ""), + ); + + darkMode.add( + ["dark", variant, `${prefix}${mapping.dark[needle]}`] + .filter(Boolean) + .join(":") + (modifier ? `/${modifier}` : ""), + ); + continue; + } + + if (!lightMode.has(className)) { + lightMode.add(className); + } + } + + return [...Array.from(lightMode), ...Array.from(darkMode)].join(" ").trim(); +} diff --git a/packages/cli/src/utils/transformers/transform-import.ts b/packages/cli/src/utils/transformers/transform-import.ts new file mode 100644 index 0000000..d989e89 --- /dev/null +++ b/packages/cli/src/utils/transformers/transform-import.ts @@ -0,0 +1,39 @@ +import { Transformer } from "@/utils/transformers"; + +export const transformImport: Transformer = async ({ sourceFile, config }) => { + const importDeclarations = sourceFile.getImportDeclarations(); + + for (const importDeclaration of importDeclarations) { + const moduleSpecifier = importDeclaration.getModuleSpecifierValue(); + + // Replace @/registry/[style] with the components alias. + // if (moduleSpecifier.startsWith("@/registry/")) { + // if (config.aliases.ui) { + // importDeclaration.setModuleSpecifier( + // moduleSpecifier.replace(/^@\/registry\/[^/]+\/ui/, config.aliases.ui) + // ); + // } else { + // importDeclaration.setModuleSpecifier( + // moduleSpecifier.replace( + // /^@\/registry\/[^/]+/, + // config.aliases.components + // ) + // ); + // } + // } + + // Replace `import { cn } from "@/utils/cn";` + if (moduleSpecifier == "@/utils/cn") { + const namedImports = importDeclaration.getNamedImports(); + const cnImport = namedImports.find((i) => i.getName() === "cn"); + + if (cnImport) { + importDeclaration.setModuleSpecifier( + moduleSpecifier.replace(/^@\/utils\/cn/, config.aliases.utils), + ); + } + } + } + + return sourceFile; +}; diff --git a/packages/cli/src/utils/transformers/transform-jsx.ts b/packages/cli/src/utils/transformers/transform-jsx.ts new file mode 100644 index 0000000..5c95165 --- /dev/null +++ b/packages/cli/src/utils/transformers/transform-jsx.ts @@ -0,0 +1,97 @@ +import { type Transformer } from "@/utils/transformers"; +import { transformFromAstSync } from "@babel/core"; +import { ParserOptions, parse } from "@babel/parser"; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-expect-error +import transformTypescript from "@babel/plugin-transform-typescript"; +import * as recast from "recast"; + +// TODO. +// I'm using recast for the AST here. +// Figure out if ts-morph AST is compatible with Babel. + +// This is a copy of the babel options from recast/parser. +// The goal here is to tolerate as much syntax as possible. +// We want to be able to parse any valid tsx code. +// See https://github.com/benjamn/recast/blob/master/parsers/_babel_options.ts. +const PARSE_OPTIONS: ParserOptions = { + sourceType: "module", + allowImportExportEverywhere: true, + allowReturnOutsideFunction: true, + startLine: 1, + tokens: true, + plugins: [ + "asyncGenerators", + "bigInt", + "classPrivateMethods", + "classPrivateProperties", + "classProperties", + "classStaticBlock", + "decimal", + "decorators-legacy", + "doExpressions", + "dynamicImport", + "exportDefaultFrom", + "exportNamespaceFrom", + "functionBind", + "functionSent", + "importAssertions", + "importMeta", + "nullishCoalescingOperator", + "numericSeparator", + "objectRestSpread", + "optionalCatchBinding", + "optionalChaining", + [ + "pipelineOperator", + { + proposal: "minimal", + }, + ], + [ + "recordAndTuple", + { + syntaxType: "hash", + }, + ], + "throwExpressions", + "topLevelAwait", + "v8intrinsic", + "typescript", + "jsx", + ], +}; + +// eslint-disable-next-line @typescript-eslint/ban-types +export const transformJsx: Transformer = async ({ + sourceFile, + config, +}) => { + const output = sourceFile.getFullText(); + + if (config.tsx) { + return output; + } + + const ast = recast.parse(output, { + parser: { + parse: (code: string) => { + return parse(code, PARSE_OPTIONS); + }, + }, + }); + + const result = transformFromAstSync(ast, output, { + cloneInputAst: false, + code: false, + ast: true, + plugins: [transformTypescript], + configFile: false, + }); + + if (!result || !result.ast) { + throw new Error("Failed to transform JSX"); + } + + return recast.print(result.ast).code; +}; diff --git a/packages/cli/src/utils/transformers/transform-rsc.ts b/packages/cli/src/utils/transformers/transform-rsc.ts new file mode 100644 index 0000000..347c67c --- /dev/null +++ b/packages/cli/src/utils/transformers/transform-rsc.ts @@ -0,0 +1,16 @@ +import { Transformer } from "@/utils/transformers"; +import { SyntaxKind } from "ts-morph"; + +export const transformRsc: Transformer = async ({ sourceFile, config }) => { + if (config.rsc) { + return sourceFile; + } + + // Remove "use client" from the top of the file. + const first = sourceFile.getFirstChildByKind(SyntaxKind.ExpressionStatement); + if (first?.getText() === `"use client"`) { + first.remove(); + } + + return sourceFile; +}; diff --git a/packages/cli/src/utils/transformers/transform-tw-prefix.ts b/packages/cli/src/utils/transformers/transform-tw-prefix.ts new file mode 100644 index 0000000..4920559 --- /dev/null +++ b/packages/cli/src/utils/transformers/transform-tw-prefix.ts @@ -0,0 +1,203 @@ +import { Transformer } from "@/utils/transformers"; +import { SyntaxKind } from "ts-morph"; + +import { splitClassName } from "./transform-css-vars"; + +export const transformTwPrefixes: Transformer = async ({ + sourceFile, + config, +}) => { + if (!config.tailwind?.prefix) { + return sourceFile; + } + + // Find the cva function calls. + sourceFile + .getDescendantsOfKind(SyntaxKind.CallExpression) + .filter((node) => node.getExpression().getText() === "cva") + .forEach((node) => { + // cva(base, ...) + if (node.getArguments()[0]?.isKind(SyntaxKind.StringLiteral)) { + const defaultClassNames = node.getArguments()[0]; + if (defaultClassNames) { + defaultClassNames.replaceWithText( + `"${applyPrefix( + defaultClassNames.getText()?.replace(/"/g, ""), + config.tailwind.prefix, + )}"`, + ); + } + } + + // cva(..., { variants: { ... } }) + if (node.getArguments()[1]?.isKind(SyntaxKind.ObjectLiteralExpression)) { + node + .getArguments()[1] + ?.getDescendantsOfKind(SyntaxKind.PropertyAssignment) + .find((node) => node.getName() === "variants") + ?.getDescendantsOfKind(SyntaxKind.PropertyAssignment) + .forEach((node) => { + node + .getDescendantsOfKind(SyntaxKind.PropertyAssignment) + .forEach((node) => { + const classNames = node.getInitializerIfKind( + SyntaxKind.StringLiteral, + ); + if (classNames) { + classNames?.replaceWithText( + `"${applyPrefix( + classNames.getText()?.replace(/"/g, ""), + config.tailwind.prefix, + )}"`, + ); + } + }); + }); + } + }); + + // Find all jsx attributes with the name className. + sourceFile.getDescendantsOfKind(SyntaxKind.JsxAttribute).forEach((node) => { + // @ts-expect-error - TS doesn't know that getName() returns a string. + if (node.getName() === "className") { + // className="..." + if (node.getInitializer()?.isKind(SyntaxKind.StringLiteral)) { + const value = node.getInitializer(); + if (value) { + value.replaceWithText( + `"${applyPrefix( + value.getText()?.replace(/"/g, ""), + config.tailwind.prefix, + )}"`, + ); + } + } + + // className={...} + if (node.getInitializer()?.isKind(SyntaxKind.JsxExpression)) { + // Check if it's a call to cn(). + const callExpression = node + .getInitializer() + ?.getDescendantsOfKind(SyntaxKind.CallExpression) + .find((node) => node.getExpression().getText() === "cn"); + if (callExpression) { + // Loop through the arguments. + callExpression.getArguments().forEach((node) => { + if ( + node.isKind(SyntaxKind.ConditionalExpression) || + node.isKind(SyntaxKind.BinaryExpression) + ) { + node + .getChildrenOfKind(SyntaxKind.StringLiteral) + .forEach((node) => { + node.replaceWithText( + `"${applyPrefix( + node.getText()?.replace(/"/g, ""), + config.tailwind.prefix, + )}"`, + ); + }); + } + + if (node.isKind(SyntaxKind.StringLiteral)) { + node.replaceWithText( + `"${applyPrefix( + node.getText()?.replace(/"/g, ""), + config.tailwind.prefix, + )}"`, + ); + } + }); + } + } + } + + // classNames={...} + // @ts-expect-error - TS doesn't know that getName() returns a string. + if (node.getName() === "classNames") { + if (node.getInitializer()?.isKind(SyntaxKind.JsxExpression)) { + node + .getDescendantsOfKind(SyntaxKind.PropertyAssignment) + .forEach((node) => { + if (node.getInitializer()?.isKind(SyntaxKind.CallExpression)) { + const callExpression = node.getInitializerIfKind( + SyntaxKind.CallExpression, + ); + if (callExpression) { + // Loop through the arguments. + callExpression.getArguments().forEach((arg) => { + if (arg.isKind(SyntaxKind.ConditionalExpression)) { + arg + .getChildrenOfKind(SyntaxKind.StringLiteral) + .forEach((node) => { + node.replaceWithText( + `"${applyPrefix( + node.getText()?.replace(/"/g, ""), + config.tailwind.prefix, + )}"`, + ); + }); + } + + if (arg.isKind(SyntaxKind.StringLiteral)) { + arg.replaceWithText( + `"${applyPrefix( + arg.getText()?.replace(/"/g, ""), + config.tailwind.prefix, + )}"`, + ); + } + }); + } + } + + if (node.getInitializer()?.isKind(SyntaxKind.StringLiteral)) { + if (node.getName() !== "variant") { + const classNames = node.getInitializer(); + if (classNames) { + classNames.replaceWithText( + `"${applyPrefix( + classNames.getText()?.replace(/"/g, ""), + config.tailwind.prefix, + )}"`, + ); + } + } + } + }); + } + } + }); + + return sourceFile; +}; + +export function applyPrefix(input: string, prefix: string = "") { + const classNames = input.split(" "); + const prefixed: string[] = []; + for (const className of classNames) { + const [variant, value, modifier] = splitClassName(className); + if (variant) { + modifier + ? prefixed.push(`${variant}:${prefix}${value}/${modifier}`) + : prefixed.push(`${variant}:${prefix}${value}`); + } else { + modifier + ? prefixed.push(`${prefix}${value}/${modifier}`) + : prefixed.push(`${prefix}${value}`); + } + } + return prefixed.join(" "); +} + +export function applyPrefixesCss(css: string, prefix: string) { + const lines = css.split("\n"); + for (const line of lines) { + if (line.includes("@apply")) { + const originalTWCls = line.replace("@apply", "").trim(); + const prefixedTwCls = applyPrefix(originalTWCls, prefix); + css = css.replace(originalTWCls, prefixedTwCls); + } + } + return css; +} diff --git a/packages/cli/tsconfig.json b/packages/cli/tsconfig.json new file mode 100644 index 0000000..e91af62 --- /dev/null +++ b/packages/cli/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "tsconfig/base.json", + "compilerOptions": { + "module": "ESNext", + "paths": { + "@/*": ["./src/*"] + } + }, + "exclude": ["node_modules", "template", "dist", "scripts"] +} diff --git a/packages/cli/tsup.config.ts b/packages/cli/tsup.config.ts new file mode 100644 index 0000000..32d8fa3 --- /dev/null +++ b/packages/cli/tsup.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["./src/index.ts", "./src/create-app.ts"], + format: "esm", + target: "node18", +}); diff --git a/packages/ui/package.json b/packages/ui/package.json index 1f60c9d..a58eee7 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -87,6 +87,7 @@ "dependencies": { "@radix-ui/react-checkbox": "^1.1.1", "@radix-ui/react-direction": "^1.1.0", + "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-select": "^2.1.1", "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-switch": "^1.1.0", @@ -100,6 +101,7 @@ "react": "^18.2.0", "tailwind-merge": "^2.4.0", "tailwindcss-animate": "^1.0.7", - "tsup": "^8.1.1" + "tsup": "^8.1.1", + "zod": "^3.23.8" } } diff --git a/packages/ui/src/components/button.tsx b/packages/ui/src/components/button.tsx index 0c791ab..6c191b9 100644 --- a/packages/ui/src/components/button.tsx +++ b/packages/ui/src/components/button.tsx @@ -3,7 +3,7 @@ import { Slot } from "@radix-ui/react-slot"; import { cva, type VariantProps } from "class-variance-authority"; import React from "react"; -import { cn } from "../utils/cn"; +import { cn } from "@/utils/cn"; import { Spinner } from "./spinner"; export const buttonVariants = cva( diff --git a/packages/ui/src/components/input.tsx b/packages/ui/src/components/input.tsx index afcd7f1..52f481c 100644 --- a/packages/ui/src/components/input.tsx +++ b/packages/ui/src/components/input.tsx @@ -228,7 +228,7 @@ const Input = React.forwardRef( , + React.ComponentPropsWithoutRef +>((props, ref) => { + return ( + + ); +}); + +TabsPrimitiveRoot.displayName = "TabsPrimitiveRoot"; + +const TabsList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>((props, ref) => ( + +)); +TabsList.displayName = "TabsList"; + +const TabsTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>((props, ref) => ( + +)); +TabsTrigger.displayName = "TabsTrigger"; + +const TabsContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>((props, ref) => ( + +)); +TabsContent.displayName = "TabsContent"; type ChangeListener = (v: string) => void; const listeners = new Map(); @@ -104,21 +159,21 @@ export function Tabs({ ); return ( - - + {values.map((v, i) => ( - + {items[i]} - + ))} - + {props.children} - + ); } @@ -132,7 +187,7 @@ export function Tab({ ...props }: TabsContentProps): React.ReactElement { return ( - figure:only-child]:-m-4 [&>figure:only-child]:rounded-none [&>figure:only-child]:border-none", @@ -142,3 +197,5 @@ export function Tab({ /> ); } + +export { TabsList, TabsTrigger, TabsContent }; diff --git a/packages/ui/src/components/textarea.tsx b/packages/ui/src/components/textarea.tsx index 182f1f8..176adf3 100644 --- a/packages/ui/src/components/textarea.tsx +++ b/packages/ui/src/components/textarea.tsx @@ -89,7 +89,7 @@ const Textarea = React.forwardRef( , - React.ComponentPropsWithoutRef ->((props, ref) => { - return ( - - ); -}); - -Tabs.displayName = "Tabs"; - -const TabsList = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->((props, ref) => ( - -)); -TabsList.displayName = "TabsList"; - -const TabsTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->((props, ref) => ( - -)); -TabsTrigger.displayName = "TabsTrigger"; - -const TabsContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->((props, ref) => ( - -)); -TabsContent.displayName = "TabsContent"; - -export { Tabs, TabsList, TabsTrigger, TabsContent }; diff --git a/packages/ui/src/icons/CaretSortIcon.tsx b/packages/ui/src/icons/CaretSortIcon.tsx deleted file mode 100644 index 7d9a23e..0000000 --- a/packages/ui/src/icons/CaretSortIcon.tsx +++ /dev/null @@ -1,17 +0,0 @@ -export const CaretSortIcon = ({ className }: { className?: string }) => ( - - - -); diff --git a/packages/ui/src/icons/CheckIcon.tsx b/packages/ui/src/icons/CheckIcon.tsx deleted file mode 100644 index 13ba11d..0000000 --- a/packages/ui/src/icons/CheckIcon.tsx +++ /dev/null @@ -1,17 +0,0 @@ -export const CheckIcon = ({ className }: { className?: string }) => ( - - - -); diff --git a/packages/ui/src/icons/ChevronDownIcon.tsx b/packages/ui/src/icons/ChevronDownIcon.tsx deleted file mode 100644 index 3a2ee3f..0000000 --- a/packages/ui/src/icons/ChevronDownIcon.tsx +++ /dev/null @@ -1,17 +0,0 @@ -export const ChevronDownIcon = ({ className }: { className?: string }) => ( - - - -); diff --git a/packages/ui/src/icons/ChevronUpIcon.tsx b/packages/ui/src/icons/ChevronUpIcon.tsx deleted file mode 100644 index d8dd285..0000000 --- a/packages/ui/src/icons/ChevronUpIcon.tsx +++ /dev/null @@ -1,17 +0,0 @@ -export const ChevronUpIcon = ({ className }: { className?: string }) => ( - - - -); diff --git a/packages/ui/src/icons/index.ts b/packages/ui/src/icons/index.ts deleted file mode 100644 index e7afda1..0000000 --- a/packages/ui/src/icons/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { CaretSortIcon } from "./CaretSortIcon"; -export { CheckIcon } from "./CheckIcon"; -export { ChevronDownIcon } from "./ChevronDownIcon"; -export { ChevronUpIcon } from "./ChevronUpIcon"; diff --git a/packages/ui/src/utils/cn.ts b/packages/ui/src/utils/cn.ts index cfe9a8a..264616e 100644 --- a/packages/ui/src/utils/cn.ts +++ b/packages/ui/src/utils/cn.ts @@ -1,11 +1,11 @@ -import { twMerge } from "tailwind-merge"; +import { ClassNameValue, twMerge } from "tailwind-merge"; /** * Utility function to merge Tailwind CSS class names. * Uses `twMerge` from `tailwind-merge` to handle class name conflicts and ensure * the final output is a valid set of Tailwind CSS classes. * - * @param {...string[]} classNames - The class names to merge. + * @param {...string[]} classLists - The class names to merge. * @returns {string} - The merged class names. */ -export const cn = twMerge; +export const cn: (...classLists: ClassNameValue[]) => string = twMerge; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bb01fc5..cafd083 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,12 @@ importers: sharp: specifier: ^0.33.4 version: 0.33.4 + tsup: + specifier: ^8.1.1 + version: 8.1.1(tsx@4.17.0)(typescript@5.4.5) + tsx: + specifier: ^4.17.0 + version: 4.17.0 devDependencies: '@typescript-eslint/eslint-plugin': specifier: ^7.16.1 @@ -48,9 +54,24 @@ importers: apps/sink: dependencies: + '@radix-ui/react-checkbox': + specifier: ^1.1.1 + version: 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-icons': specifier: ^1.3.0 version: 1.3.0(react@18.3.1) + '@radix-ui/react-select': + specifier: ^2.1.1 + version: 2.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': + specifier: ^1.1.0 + version: 1.1.0(@types/react@18.3.3)(react@18.3.1) + class-variance-authority: + specifier: ^0.7.0 + version: 0.7.0 + clsx: + specifier: ^2.1.1 + version: 2.1.1 geist: specifier: ^1.3.1 version: 1.3.1(next@14.2.5) @@ -69,6 +90,12 @@ importers: ruru-ui: specifier: workspace:* version: link:../../packages/ui + tailwind-merge: + specifier: ^2.4.0 + version: 2.4.0 + tailwindcss-animate: + specifier: ^1.0.7 + version: 1.0.7(tailwindcss@3.4.4) devDependencies: '@types/node': specifier: ^20 @@ -100,6 +127,9 @@ importers: '@radix-ui/react-icons': specifier: ^1.3.0 version: 1.3.0(react@18.3.1) + fs: + specifier: 0.0.1-security + version: 0.0.1-security fumadocs-core: specifier: 12.4.2 version: 12.4.2(@types/react@18.3.3)(next@14.2.5)(react-dom@18.3.1)(react@18.3.1) @@ -121,6 +151,13 @@ importers: next: specifier: ^14.2.4 version: 14.2.5(@babel/core@7.24.9)(react-dom@18.3.1)(react@18.3.1) + os: {specifier: ^0.1.2, version: 0.1.2} + path: + specifier: ^0.12.7 + version: 0.12.7 + process: + specifier: ^0.11.10 + version: 0.11.10 react: specifier: ^18.3.1 version: 18.3.1 @@ -133,6 +170,9 @@ importers: remark-math: specifier: ^6.0.0 version: 6.0.0 + rimraf: + specifier: ^6.0.1 + version: 6.0.1 ruru-ui: specifier: workspace:* version: link:../../packages/ui @@ -142,6 +182,9 @@ importers: tailwindcss-animate: specifier: ^1.0.7 version: 1.0.7(tailwindcss@3.4.4) + ts-morph: + specifier: ^23.0.0 + version: 23.0.0 zod: specifier: ^3.23.8 version: 3.23.8 @@ -174,6 +217,94 @@ importers: specifier: ^5.5.0 version: 5.5.3 + packages/cli: + dependencies: + '@antfu/ni': + specifier: ^0.22.1 + version: 0.22.1 + '@babel/core': + specifier: ^7.25.2 + version: 7.25.2 + '@babel/parser': + specifier: ^7.25.3 + version: 7.25.3 + '@babel/plugin-transform-typescript': + specifier: ^7.25.2 + version: 7.25.2(@babel/core@7.25.2) + '@clack/prompts': + specifier: ^0.7.0 + version: 0.7.0 + commander: + specifier: ^12.1.0 + version: 12.1.0 + cosmiconfig: + specifier: ^9.0.0 + version: 9.0.0(typescript@5.4.5) + cross-spawn: + specifier: ^7.0.3 + version: 7.0.3 + dotenv: + specifier: ^16.4.5 + version: 16.4.5 + execa: + specifier: ^9.3.0 + version: 9.3.0 + fast-glob: + specifier: ^3.3.2 + version: 3.3.2 + fs-extra: + specifier: ^11.2.0 + version: 11.2.0 + https-proxy-agent: + specifier: ^7.0.5 + version: 7.0.5 + lodash: + specifier: ^4.17.21 + version: 4.17.21 + lodash.template: + specifier: ^4.5.0 + version: 4.5.0 + node-fetch: + specifier: ^3.3.2 + version: 3.3.2 + ora: + specifier: ^8.0.1 + version: 8.0.1 + picocolors: + specifier: ^1.0.1 + version: 1.0.1 + prompts: + specifier: ^2.4.2 + version: 2.4.2 + recast: + specifier: ^0.23.9 + version: 0.23.9 + ts-morph: + specifier: ^23.0.0 + version: 23.0.0 + tsconfig-paths: + specifier: ^4.2.0 + version: 4.2.0 + type-fest: + specifier: ^4.24.0 + version: 4.24.0 + zod: + specifier: ^3.23.8 + version: 3.23.8 + devDependencies: + '@types/babel__core': + specifier: ^7.20.5 + version: 7.20.5 + '@types/fs-extra': + specifier: ^11.0.4 + version: 11.0.4 + '@types/lodash.template': + specifier: ^4.5.3 + version: 4.5.3 + tsconfig: + specifier: workspace:* + version: link:../tsconfig + packages/tsconfig: {} packages/ui: @@ -184,6 +315,9 @@ importers: '@radix-ui/react-direction': specifier: ^1.1.0 version: 1.1.0(@types/react@18.3.3)(react@18.3.1) + '@radix-ui/react-icons': + specifier: ^1.3.0 + version: 1.3.0(react@18.3.1) '@radix-ui/react-select': specifier: ^2.1.1 version: 2.1.1(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1)(react@18.3.1) @@ -225,7 +359,10 @@ importers: version: 1.0.7(tailwindcss@3.4.4) tsup: specifier: ^8.1.1 - version: 8.1.1(@swc/core@1.6.13)(postcss@8.4.39)(typescript@5.5.3) + version: 8.1.1(@swc/core@1.6.13)(postcss@8.4.39)(tsx@4.17.0)(typescript@5.5.3) + zod: + specifier: ^3.23.8 + version: 3.23.8 devDependencies: '@turbo/gen': specifier: ^1.12.4 @@ -253,7 +390,7 @@ importers: version: 8.4.39 postcss-cli: specifier: ^11.0.0 - version: 11.0.0(postcss@8.4.39) + version: 11.0.0(postcss@8.4.39)(tsx@4.17.0) postcss-lightningcss: specifier: ^1.0.0 version: 1.0.0(postcss@8.4.39) @@ -280,6 +417,11 @@ packages: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 + /@antfu/ni@0.22.1: + resolution: {integrity: sha512-5STu7QHsLYWpt+K/+zRcMOIUnG51lOhnqPInImXGyC6PMHtkrZQjbqZ/R3GW8XdTYOnKiT77+R09Tl4fzuFK5w==} + hasBin: true + dev: false + /@babel/code-frame@7.24.7: resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} engines: {node: '>=6.9.0'} @@ -291,6 +433,11 @@ packages: resolution: {integrity: sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==} engines: {node: '>=6.9.0'} + /@babel/compat-data@7.25.2: + resolution: {integrity: sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==} + engines: {node: '>=6.9.0'} + dev: false + /@babel/core@7.24.9: resolution: {integrity: sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==} engines: {node: '>=6.9.0'} @@ -313,6 +460,29 @@ packages: transitivePeerDependencies: - supports-color + /@babel/core@7.25.2: + resolution: {integrity: sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.25.0 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2) + '@babel/helpers': 7.25.0 + '@babel/parser': 7.25.3 + '@babel/template': 7.25.0 + '@babel/traverse': 7.25.3 + '@babel/types': 7.25.2 + convert-source-map: 2.0.0 + debug: 4.3.5 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: false + /@babel/eslint-parser@7.24.8(@babel/core@7.24.9)(eslint@8.57.0): resolution: {integrity: sha512-nYAikI4XTGokU2QX7Jx+v4rxZKhKivaQaREZjuW3mrJrbdWJ5yUfohnoUULge+zEEaKjPYNxhoRgUKktjXtbwA==} engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0} @@ -336,6 +506,23 @@ packages: '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 + /@babel/generator@7.25.0: + resolution: {integrity: sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.25.2 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 2.5.2 + dev: false + + /@babel/helper-annotate-as-pure@7.24.7: + resolution: {integrity: sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.25.2 + dev: false + /@babel/helper-compilation-targets@7.24.8: resolution: {integrity: sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==} engines: {node: '>=6.9.0'} @@ -346,6 +533,35 @@ packages: lru-cache: 5.1.1 semver: 6.3.1 + /@babel/helper-compilation-targets@7.25.2: + resolution: {integrity: sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': 7.25.2 + '@babel/helper-validator-option': 7.24.8 + browserslist: 4.23.2 + lru-cache: 5.1.1 + semver: 6.3.1 + dev: false + + /@babel/helper-create-class-features-plugin@7.25.0(@babel/core@7.25.2): + resolution: {integrity: sha512-GYM6BxeQsETc9mnct+nIIpf63SAyzvyYN7UB/IlTyd+MBg06afFGp0mIeUqGyWgS2mxad6vqbMrHVlaL3m70sQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-member-expression-to-functions': 7.24.8 + '@babel/helper-optimise-call-expression': 7.24.7 + '@babel/helper-replace-supers': 7.25.0(@babel/core@7.25.2) + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + '@babel/traverse': 7.25.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: false + /@babel/helper-environment-visitor@7.24.7: resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==} engines: {node: '>=6.9.0'} @@ -365,6 +581,16 @@ packages: dependencies: '@babel/types': 7.24.9 + /@babel/helper-member-expression-to-functions@7.24.8: + resolution: {integrity: sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.25.3 + '@babel/types': 7.25.2 + transitivePeerDependencies: + - supports-color + dev: false + /@babel/helper-module-imports@7.24.7: resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==} engines: {node: '>=6.9.0'} @@ -389,6 +615,47 @@ packages: transitivePeerDependencies: - supports-color + /@babel/helper-module-transforms@7.25.2(@babel/core@7.25.2): + resolution: {integrity: sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + '@babel/traverse': 7.25.3 + transitivePeerDependencies: + - supports-color + dev: false + + /@babel/helper-optimise-call-expression@7.24.7: + resolution: {integrity: sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.25.2 + dev: false + + /@babel/helper-plugin-utils@7.24.8: + resolution: {integrity: sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==} + engines: {node: '>=6.9.0'} + dev: false + + /@babel/helper-replace-supers@7.25.0(@babel/core@7.25.2): + resolution: {integrity: sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-member-expression-to-functions': 7.24.8 + '@babel/helper-optimise-call-expression': 7.24.7 + '@babel/traverse': 7.25.3 + transitivePeerDependencies: + - supports-color + dev: false + /@babel/helper-simple-access@7.24.7: resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==} engines: {node: '>=6.9.0'} @@ -398,6 +665,16 @@ packages: transitivePeerDependencies: - supports-color + /@babel/helper-skip-transparent-expression-wrappers@7.24.7: + resolution: {integrity: sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.25.3 + '@babel/types': 7.25.2 + transitivePeerDependencies: + - supports-color + dev: false + /@babel/helper-split-export-declaration@7.24.7: resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==} engines: {node: '>=6.9.0'} @@ -423,6 +700,14 @@ packages: '@babel/template': 7.24.7 '@babel/types': 7.24.9 + /@babel/helpers@7.25.0: + resolution: {integrity: sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.25.0 + '@babel/types': 7.25.2 + dev: false + /@babel/highlight@7.24.7: resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} engines: {node: '>=6.9.0'} @@ -439,6 +724,39 @@ packages: dependencies: '@babel/types': 7.24.9 + /@babel/parser@7.25.3: + resolution: {integrity: sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.25.2 + + /@babel/plugin-syntax-typescript@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: false + + /@babel/plugin-transform-typescript@7.25.2(@babel/core@7.25.2): + resolution: {integrity: sha512-lBwRvjSmqiMYe/pS0+1gggjJleUJi7NzjvQ1Fkqtt69hBa/0t1YuW/MLQMAPixfwaQOHUXsd6jeU3Z+vdGv3+A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-create-class-features-plugin': 7.25.0(@babel/core@7.25.2) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + '@babel/plugin-syntax-typescript': 7.24.7(@babel/core@7.25.2) + transitivePeerDependencies: + - supports-color + dev: false + /@babel/runtime-corejs3@7.24.8: resolution: {integrity: sha512-DXG/BhegtMHhnN7YPIvxWd303/9aXvYFD1TjNL3CD6tUrhI2LVsg3Lck0aql5TRH29n4sj3emcROypkZVUfSuA==} engines: {node: '>=6.9.0'} @@ -462,6 +780,15 @@ packages: '@babel/parser': 7.24.8 '@babel/types': 7.24.9 + /@babel/template@7.25.0: + resolution: {integrity: sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/parser': 7.25.3 + '@babel/types': 7.25.2 + dev: false + /@babel/traverse@7.24.8: resolution: {integrity: sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==} engines: {node: '>=6.9.0'} @@ -479,6 +806,21 @@ packages: transitivePeerDependencies: - supports-color + /@babel/traverse@7.25.3: + resolution: {integrity: sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.25.0 + '@babel/parser': 7.25.3 + '@babel/template': 7.25.0 + '@babel/types': 7.25.2 + debug: 4.3.5 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: false + /@babel/types@7.24.9: resolution: {integrity: sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==} engines: {node: '>=6.9.0'} @@ -487,6 +829,14 @@ packages: '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 + /@babel/types@7.25.2: + resolution: {integrity: sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.24.8 + '@babel/helper-validator-identifier': 7.24.7 + to-fast-properties: 2.0.0 + /@changesets/apply-release-plan@7.0.4: resolution: {integrity: sha512-HLFwhKWayKinWAul0Vj+76jVx1Pc2v55MGPVjZ924Y/ROeSsBMFutv9heHmCUj48lJyRfOTJG5+ar+29FUky/A==} dependencies: @@ -680,6 +1030,23 @@ packages: prettier: 2.8.8 dev: false + /@clack/core@0.3.4: + resolution: {integrity: sha512-H4hxZDXgHtWTwV3RAVenqcC4VbJZNegbBjlPvzOzCouXtS2y3sDvlO3IsbrPNWuLWPPlYVYPghQdSF64683Ldw==} + dependencies: + picocolors: 1.0.1 + sisteransi: 1.0.5 + dev: false + + /@clack/prompts@0.7.0: + resolution: {integrity: sha512-0MhX9/B4iL6Re04jPrttDm+BsP8y6mS7byuv0BvXgdXhbV5PdlsHt55dvNsuBCPZ7xq1oTAOOuotR9NFbQyMSA==} + dependencies: + '@clack/core': 0.3.4 + picocolors: 1.0.1 + sisteransi: 1.0.5 + dev: false + bundledDependencies: + - is-unicode-supported + /@cspotcode/source-map-support@0.8.1: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} @@ -701,7 +1068,6 @@ packages: cpu: [ppc64] os: [aix] requiresBuild: true - dev: false optional: true /@esbuild/android-arm64@0.23.0: @@ -710,7 +1076,6 @@ packages: cpu: [arm64] os: [android] requiresBuild: true - dev: false optional: true /@esbuild/android-arm@0.23.0: @@ -719,7 +1084,6 @@ packages: cpu: [arm] os: [android] requiresBuild: true - dev: false optional: true /@esbuild/android-x64@0.23.0: @@ -728,7 +1092,6 @@ packages: cpu: [x64] os: [android] requiresBuild: true - dev: false optional: true /@esbuild/darwin-arm64@0.23.0: @@ -737,7 +1100,6 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true - dev: false optional: true /@esbuild/darwin-x64@0.23.0: @@ -746,7 +1108,6 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true - dev: false optional: true /@esbuild/freebsd-arm64@0.23.0: @@ -755,7 +1116,6 @@ packages: cpu: [arm64] os: [freebsd] requiresBuild: true - dev: false optional: true /@esbuild/freebsd-x64@0.23.0: @@ -764,7 +1124,6 @@ packages: cpu: [x64] os: [freebsd] requiresBuild: true - dev: false optional: true /@esbuild/linux-arm64@0.23.0: @@ -773,7 +1132,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: false optional: true /@esbuild/linux-arm@0.23.0: @@ -782,7 +1140,6 @@ packages: cpu: [arm] os: [linux] requiresBuild: true - dev: false optional: true /@esbuild/linux-ia32@0.23.0: @@ -791,7 +1148,6 @@ packages: cpu: [ia32] os: [linux] requiresBuild: true - dev: false optional: true /@esbuild/linux-loong64@0.23.0: @@ -800,7 +1156,6 @@ packages: cpu: [loong64] os: [linux] requiresBuild: true - dev: false optional: true /@esbuild/linux-mips64el@0.23.0: @@ -809,7 +1164,6 @@ packages: cpu: [mips64el] os: [linux] requiresBuild: true - dev: false optional: true /@esbuild/linux-ppc64@0.23.0: @@ -818,7 +1172,6 @@ packages: cpu: [ppc64] os: [linux] requiresBuild: true - dev: false optional: true /@esbuild/linux-riscv64@0.23.0: @@ -827,7 +1180,6 @@ packages: cpu: [riscv64] os: [linux] requiresBuild: true - dev: false optional: true /@esbuild/linux-s390x@0.23.0: @@ -836,7 +1188,6 @@ packages: cpu: [s390x] os: [linux] requiresBuild: true - dev: false optional: true /@esbuild/linux-x64@0.23.0: @@ -845,7 +1196,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: false optional: true /@esbuild/netbsd-x64@0.23.0: @@ -854,7 +1204,6 @@ packages: cpu: [x64] os: [netbsd] requiresBuild: true - dev: false optional: true /@esbuild/openbsd-arm64@0.23.0: @@ -863,7 +1212,6 @@ packages: cpu: [arm64] os: [openbsd] requiresBuild: true - dev: false optional: true /@esbuild/openbsd-x64@0.23.0: @@ -872,7 +1220,6 @@ packages: cpu: [x64] os: [openbsd] requiresBuild: true - dev: false optional: true /@esbuild/sunos-x64@0.23.0: @@ -881,7 +1228,6 @@ packages: cpu: [x64] os: [sunos] requiresBuild: true - dev: false optional: true /@esbuild/win32-arm64@0.23.0: @@ -890,7 +1236,6 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true - dev: false optional: true /@esbuild/win32-ia32@0.23.0: @@ -899,7 +1244,6 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true - dev: false optional: true /@esbuild/win32-x64@0.23.0: @@ -908,7 +1252,6 @@ packages: cpu: [x64] os: [win32] requiresBuild: true - dev: false optional: true /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): @@ -988,7 +1331,7 @@ packages: deprecated: Use @eslint/config-array instead dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.4 + debug: 4.3.5 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -2575,6 +2918,10 @@ packages: resolution: {integrity: sha512-qC/xYId4NMebE6w/V33Fh9gWxLgURiNYgVNObbJl2LZv0GUUItCcCqC5axQSwRaAgaxl2mELq1rMzlswaQ0Zxg==} dev: true + /@sec-ant/readable-stream@0.4.1: + resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + dev: false + /@shikijs/core@1.10.3: resolution: {integrity: sha512-D45PMaBaeDHxww+EkcDQtDAtzv00Gcsp72ukBtaLSmqRvh0WgGMq3Al0rl1QQBZfuneO75NXMIzEZGFitThWbg==} dependencies: @@ -2617,6 +2964,11 @@ packages: engines: {node: '>=18'} dev: true + /@sindresorhus/merge-streams@4.0.0: + resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} + engines: {node: '>=18'} + dev: false + /@swc/core-darwin-arm64@1.6.13: resolution: {integrity: sha512-SOF4buAis72K22BGJ3N8y88mLNfxLNprTuJUpzikyMGrvkuBFNcxYtMhmomO0XHsgLDzOJ+hWzcgjRNzjMsUcQ==} engines: {node: '>=10'} @@ -2752,6 +3104,15 @@ packages: resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} dev: true + /@ts-morph/common@0.24.0: + resolution: {integrity: sha512-c1xMmNHWpNselmpIqursHeOHHBTIsJLbB+NuovbTTRCNiTLEr/U9dbJ8qy0jd/O2x5pc3seWuOUN5R2IoOTp8A==} + dependencies: + fast-glob: 3.3.2 + minimatch: 9.0.5 + mkdirp: 3.0.1 + path-browserify: 1.0.1 + dev: false + /@tsconfig/node10@1.0.11: resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} dev: true @@ -2815,6 +3176,35 @@ packages: '@types/estree': 1.0.5 dev: false + /@types/babel__core@7.20.5: + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + dependencies: + '@babel/parser': 7.25.3 + '@babel/types': 7.25.2 + '@types/babel__generator': 7.6.8 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.6 + dev: true + + /@types/babel__generator@7.6.8: + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + dependencies: + '@babel/types': 7.25.2 + dev: true + + /@types/babel__template@7.4.4: + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + dependencies: + '@babel/parser': 7.25.3 + '@babel/types': 7.25.2 + dev: true + + /@types/babel__traverse@7.20.6: + resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} + dependencies: + '@babel/types': 7.25.2 + dev: true + /@types/debug@4.1.12: resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} dependencies: @@ -2837,6 +3227,13 @@ packages: /@types/estree@1.0.5: resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + /@types/fs-extra@11.0.4: + resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} + dependencies: + '@types/jsonfile': 6.1.4 + '@types/node': 20.14.10 + dev: true + /@types/glob@7.2.0: resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} dependencies: @@ -2865,10 +3262,26 @@ packages: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true + /@types/jsonfile@6.1.4: + resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} + dependencies: + '@types/node': 20.14.10 + dev: true + /@types/katex@0.16.7: resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==} dev: false + /@types/lodash.template@4.5.3: + resolution: {integrity: sha512-Mo0UYKLu1oXgkV9TVoXZLlXXjyIXlW7ZQRxi/4gQJmzJr63dmicE8gG0OkPjYTKBrBic852q0JzqrtNUWLBIyA==} + dependencies: + '@types/lodash': 4.17.7 + dev: true + + /@types/lodash@4.17.7: + resolution: {integrity: sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==} + dev: true + /@types/mdast@4.0.4: resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} dependencies: @@ -3227,7 +3640,7 @@ packages: eslint-import-resolver-alias: 1.1.2(eslint-plugin-import@2.29.1) eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.16.1)(eslint-plugin-import@2.29.1)(eslint@8.57.0) eslint-plugin-eslint-comments: 3.2.0(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.16.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.16.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-jest: 27.9.0(@typescript-eslint/eslint-plugin@7.16.1)(eslint@8.57.0)(typescript@5.4.5) eslint-plugin-jsx-a11y: 6.9.0(eslint@8.57.0) eslint-plugin-playwright: 1.6.2(eslint-plugin-jest@27.9.0)(eslint@8.57.0) @@ -3286,10 +3699,9 @@ packages: resolution: {integrity: sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==} engines: {node: '>= 14'} dependencies: - debug: 4.3.4 + debug: 4.3.5 transitivePeerDependencies: - supports-color - dev: true /aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} @@ -3378,7 +3790,6 @@ packages: /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: true /aria-hidden@1.2.4: resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==} @@ -3506,6 +3917,13 @@ packages: tslib: 2.6.2 dev: true + /ast-types@0.16.1: + resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} + engines: {node: '>=4'} + dependencies: + tslib: 2.6.2 + dev: false + /astring@1.8.6: resolution: {integrity: sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==} hasBin: true @@ -3592,12 +4010,6 @@ packages: dependencies: balanced-match: 1.0.2 - /braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} - dependencies: - fill-range: 7.0.1 - /braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -3662,7 +4074,6 @@ packages: /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - dev: true /camel-case@3.0.0: resolution: {integrity: sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==} @@ -3706,6 +4117,11 @@ packages: supports-color: 7.2.0 dev: true + /chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: false + /change-case@3.1.0: resolution: {integrity: sha512-2AZp7uJZbYEzRPsFoa+ijKdvp9zsrnnt6+yFokfwEpeJm0xuJDVoxiRCAaTzyJND8GJkofo2IcKWaUZ/OECVzw==} dependencies: @@ -3797,10 +4213,16 @@ packages: restore-cursor: 3.1.0 dev: true + /cli-cursor@4.0.0: + resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + restore-cursor: 4.0.0 + dev: false + /cli-spinners@2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} - dev: true /cli-width@3.0.0: resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} @@ -3850,6 +4272,10 @@ packages: - '@types/react-dom' dev: false + /code-block-writer@13.0.2: + resolution: {integrity: sha512-XfXzAGiStXSmCIwrkdfvc7FS5Dtj8yelCtyOf2p2skCAfvLd6zu0rGzuS9NSCO3bq1JKpFZ7tbKdKlcd5occQA==} + dev: false + /collapse-white-space@2.1.0: resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} dev: false @@ -3895,6 +4321,11 @@ packages: engines: {node: '>=14'} dev: true + /commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + dev: false + /commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -3938,6 +4369,22 @@ packages: requiresBuild: true dev: true + /cosmiconfig@9.0.0(typescript@5.4.5): + resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + typescript: 5.4.5 + dev: false + /create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} dev: true @@ -3970,6 +4417,11 @@ packages: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} dev: true + /data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + dev: false + /data-uri-to-buffer@6.0.2: resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} engines: {node: '>= 14'} @@ -4013,18 +4465,6 @@ packages: ms: 2.1.2 dev: true - /debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.2 - dev: true - /debug@4.3.5: resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} engines: {node: '>=6.0'} @@ -4205,12 +4645,21 @@ packages: no-case: 2.3.2 dev: true + /dotenv@16.4.5: + resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} + engines: {node: '>=12'} + dev: false + /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} /electron-to-chromium@1.4.827: resolution: {integrity: sha512-VY+J0e4SFcNfQy19MEoMdaIcZLmDCprqvBtkii1WTCTQHpRvf5N8+3kTYCgL/PcntvwQvmMJWTuDPsq+IlhWKQ==} + /emoji-regex@10.3.0: + resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==} + dev: false + /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -4238,11 +4687,15 @@ packages: engines: {node: '>=0.12'} dev: false + /env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + dev: false + /error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: is-arrayish: 0.2.1 - dev: true /es-abstract@1.23.3: resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} @@ -4403,7 +4856,6 @@ packages: '@esbuild/win32-arm64': 0.23.0 '@esbuild/win32-ia32': 0.23.0 '@esbuild/win32-x64': 0.23.0 - dev: false /escalade@3.1.2: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} @@ -4450,7 +4902,7 @@ packages: eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.2.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.16.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.16.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.9.0(eslint@8.57.0) eslint-plugin-react: 7.34.4(eslint@8.57.0) eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0) @@ -4475,7 +4927,7 @@ packages: peerDependencies: eslint-plugin-import: '>=1.4.0' dependencies: - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.16.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.16.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) dev: true /eslint-import-resolver-node@0.3.9: @@ -4498,8 +4950,8 @@ packages: debug: 4.3.5 enhanced-resolve: 5.17.0 eslint: 8.57.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.16.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.16.1)(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.16.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.16.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.7.5 is-core-module: 2.13.1 @@ -4522,7 +4974,7 @@ packages: enhanced-resolve: 5.17.0 eslint: 8.57.0 eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.16.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.16.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.7.5 is-core-module: 2.13.1 @@ -4534,7 +4986,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.1(@typescript-eslint/parser@7.16.1)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): + /eslint-module-utils@2.8.1(@typescript-eslint/parser@7.16.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==} engines: {node: '>=4'} peerDependencies: @@ -4559,34 +5011,6 @@ packages: debug: 3.2.7 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - transitivePeerDependencies: - - supports-color - dev: true - - /eslint-module-utils@2.8.1(@typescript-eslint/parser@7.16.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): - resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - dependencies: - '@typescript-eslint/parser': 7.16.1(eslint@8.57.0)(typescript@5.4.5) - debug: 3.2.7 - eslint: 8.57.0 eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.16.1)(eslint-plugin-import@2.29.1)(eslint@8.57.0) transitivePeerDependencies: - supports-color @@ -4633,7 +5057,7 @@ packages: ignore: 5.3.1 dev: true - /eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.16.1)(eslint@8.57.0): + /eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.16.1)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} engines: {node: '>=4'} peerDependencies: @@ -4652,7 +5076,7 @@ packages: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.16.1)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.16.1)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -5028,6 +5452,24 @@ packages: signal-exit: 3.0.7 strip-final-newline: 2.0.0 + /execa@9.3.0: + resolution: {integrity: sha512-l6JFbqnHEadBoVAVpN5dl2yCyfX28WoBAGaoQcNmLLSedOxTxcn2Qa83s8I/PA5i56vWru2OHOtrwF7Om2vqlg==} + engines: {node: ^18.19.0 || >=20.5.0} + dependencies: + '@sindresorhus/merge-streams': 4.0.0 + cross-spawn: 7.0.3 + figures: 6.1.0 + get-stream: 9.0.1 + human-signals: 7.0.0 + is-plain-obj: 4.1.0 + is-stream: 4.0.1 + npm-run-path: 5.3.0 + pretty-ms: 9.1.0 + signal-exit: 4.1.0 + strip-final-newline: 4.0.0 + yoctocolors: 2.1.1 + dev: false + /extend-shallow@2.0.1: resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} engines: {node: '>=0.10.0'} @@ -5063,7 +5505,7 @@ packages: '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.5 + micromatch: 4.0.7 /fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -5078,6 +5520,14 @@ packages: dependencies: reusify: 1.0.4 + /fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + dev: false + /figures@3.2.0: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} @@ -5085,6 +5535,13 @@ packages: escape-string-regexp: 1.0.5 dev: true + /figures@6.1.0: + resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} + engines: {node: '>=18'} + dependencies: + is-unicode-supported: 2.0.0 + dev: false + /file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -5092,12 +5549,6 @@ packages: flat-cache: 3.2.0 dev: true - /fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} - engines: {node: '>=8'} - dependencies: - to-regex-range: 5.0.1 - /fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -5155,6 +5606,13 @@ packages: cross-spawn: 7.0.3 signal-exit: 4.1.0 + /formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + dependencies: + fetch-blob: 3.2.0 + dev: false + /fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} dev: true @@ -5175,7 +5633,6 @@ packages: graceful-fs: 4.2.11 jsonfile: 6.1.0 universalify: 2.0.1 - dev: true /fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} @@ -5199,6 +5656,10 @@ packages: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} dev: true + /fs@0.0.1-security: + resolution: {integrity: sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==} + dev: false + /fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -5361,6 +5822,11 @@ packages: engines: {node: 6.* || 8.* || >= 10.*} dev: true + /get-east-asian-width@1.2.0: + resolution: {integrity: sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==} + engines: {node: '>=18'} + dev: false + /get-intrinsic@1.2.4: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} @@ -5386,6 +5852,14 @@ packages: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} + /get-stream@9.0.1: + resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} + engines: {node: '>=18'} + dependencies: + '@sec-ant/readable-stream': 0.4.1 + is-stream: 4.0.1 + dev: false + /get-symbol-description@1.0.2: resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} engines: {node: '>= 0.4'} @@ -5399,7 +5873,6 @@ packages: resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==} dependencies: resolve-pkg-maps: 1.0.0 - dev: true /get-uri@6.0.3: resolution: {integrity: sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==} @@ -5444,6 +5917,19 @@ packages: minipass: 7.0.4 path-scurry: 1.10.1 + /glob@11.0.0: + resolution: {integrity: sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==} + engines: {node: 20 || >=22} + hasBin: true + dependencies: + foreground-child: 3.1.1 + jackspeak: 4.0.1 + minimatch: 10.0.1 + minipass: 7.1.2 + package-json-from-dist: 1.0.0 + path-scurry: 2.0.0 + dev: false + /glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported @@ -5761,7 +6247,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.1 - debug: 4.3.4 + debug: 4.3.5 transitivePeerDependencies: - supports-color dev: true @@ -5771,10 +6257,9 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.1 - debug: 4.3.4 + debug: 4.3.5 transitivePeerDependencies: - supports-color - dev: true /human-id@1.0.2: resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} @@ -5784,6 +6269,11 @@ packages: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} + /human-signals@7.0.0: + resolution: {integrity: sha512-74kytxOUSvNbjrT9KisAbaTZ/eJwD/LrbM/kh5j0IhPuJzwuA19dWvniFGwBzN9rVjg+O/e+F310PjObDXS+9Q==} + engines: {node: '>=18.18.0'} + dev: false + /husky@9.1.4: resolution: {integrity: sha512-bho94YyReb4JV7LYWRWxZ/xr6TtOTt8cMfmQ39MQYJ7f/YE268s3GdghGwi+y4zAeqewE5zYLvuhV0M0ijsDEA==} engines: {node: '>=18'} @@ -5810,7 +6300,6 @@ packages: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 - dev: true /imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} @@ -5830,6 +6319,10 @@ packages: wrappy: 1.0.2 dev: true + /inherits@2.0.3: + resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} + dev: false + /inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} dev: true @@ -5938,7 +6431,6 @@ packages: /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - dev: true /is-arrayish@0.3.2: resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} @@ -6047,6 +6539,11 @@ packages: engines: {node: '>=8'} dev: true + /is-interactive@2.0.0: + resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} + engines: {node: '>=12'} + dev: false + /is-lower-case@1.1.3: resolution: {integrity: sha512-+5A1e/WJpLLXZEDlgz4G//WYSHyQBD32qa4Jd3Lw06qQlv3fJHnp3YIHjTQSGzHMgzmVKz2ZP3rBxTHkPw/lxA==} dependencies: @@ -6118,6 +6615,11 @@ packages: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} + /is-stream@4.0.1: + resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} + engines: {node: '>=18'} + dev: false + /is-string@1.0.7: resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} engines: {node: '>= 0.4'} @@ -6151,6 +6653,16 @@ packages: engines: {node: '>=10'} dev: true + /is-unicode-supported@1.3.0: + resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} + engines: {node: '>=12'} + dev: false + + /is-unicode-supported@2.0.0: + resolution: {integrity: sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q==} + engines: {node: '>=18'} + dev: false + /is-upper-case@1.1.2: resolution: {integrity: sha512-GQYSJMgfeAmVwh9ixyk888l7OIhNAGKtY6QA+IrWlu9MDTCaXmeozOZ2S9Knj7bQwBO/H6J2kb+pbyTUiMNbsw==} dependencies: @@ -6211,6 +6723,15 @@ packages: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + /jackspeak@4.0.1: + resolution: {integrity: sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==} + engines: {node: 20 || >=22} + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + dev: false + /jiti@1.21.6: resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} hasBin: true @@ -6240,7 +6761,6 @@ packages: hasBin: true dependencies: argparse: 2.0.1 - dev: true /jsbn@1.1.0: resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} @@ -6268,7 +6788,6 @@ packages: /json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - dev: true /json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -6306,7 +6825,6 @@ packages: universalify: 2.0.1 optionalDependencies: graceful-fs: 4.2.11 - dev: true /jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} @@ -6336,6 +6854,11 @@ packages: engines: {node: '>=0.10.0'} dev: false + /kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + dev: false + /language-subtag-registry@0.3.23: resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} dev: true @@ -6491,6 +7014,10 @@ packages: dependencies: p-locate: 5.0.0 + /lodash._reinterpolate@3.0.0: + resolution: {integrity: sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==} + dev: false + /lodash.castarray@4.4.0: resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==} dev: false @@ -6514,9 +7041,21 @@ packages: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} dev: false + /lodash.template@4.5.0: + resolution: {integrity: sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==} + dependencies: + lodash._reinterpolate: 3.0.0 + lodash.templatesettings: 4.2.0 + dev: false + + /lodash.templatesettings@4.2.0: + resolution: {integrity: sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==} + dependencies: + lodash._reinterpolate: 3.0.0 + dev: false + /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - dev: true /log-symbols@3.0.0: resolution: {integrity: sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==} @@ -6533,6 +7072,14 @@ packages: is-unicode-supported: 0.1.0 dev: true + /log-symbols@6.0.0: + resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} + engines: {node: '>=18'} + dependencies: + chalk: 5.3.0 + is-unicode-supported: 1.3.0 + dev: false + /longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} dev: false @@ -6557,6 +7104,11 @@ packages: resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} engines: {node: 14 || >=16.14} + /lru-cache@11.0.0: + resolution: {integrity: sha512-Qv32eSV1RSCfhY3fpPE2GNZ8jgM9X7rdAfemLWqTUxwiyIC4jJ6Sy0fZ8H+oLWevO6i4/bizg7c8d8i6bxrzbA==} + engines: {node: 20 || >=22} + dev: false + /lru-cache@4.1.5: resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} dependencies: @@ -7157,13 +7709,6 @@ packages: - supports-color dev: false - /micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} - dependencies: - braces: 3.0.2 - picomatch: 2.3.1 - /micromatch@4.0.7: resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} engines: {node: '>=8.6'} @@ -7180,6 +7725,13 @@ packages: engines: {node: '>=4'} dev: true + /minimatch@10.0.1: + resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} + engines: {node: 20 || >=22} + dependencies: + brace-expansion: 2.0.1 + dev: false + /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: @@ -7201,12 +7753,16 @@ packages: /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: true /minipass@7.0.4: resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} engines: {node: '>=16 || 14 >=14.17'} + /minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + dev: false + /mkdirp@0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true @@ -7214,6 +7770,12 @@ packages: minimist: 1.2.8 dev: true + /mkdirp@3.0.1: + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} + hasBin: true + dev: false + /mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} @@ -7314,6 +7876,20 @@ packages: lower-case: 1.1.4 dev: true + /node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + dev: false + + /node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + dev: false + /node-plop@0.26.3: resolution: {integrity: sha512-Cov028YhBZ5aB7MdMWJEmwyBig43aGL5WT4vdoB28Oitau1zZAcHUn8Sgfk9HM33TqhtLJ9PlM/O0Mv+QpV/4Q==} engines: {node: '>=8.9.4'} @@ -7358,6 +7934,13 @@ packages: dependencies: path-key: 3.1.1 + /npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + path-key: 4.0.0 + dev: false + /npm-to-yarn@2.2.1: resolution: {integrity: sha512-O/j/ROyX0KGLG7O6Ieut/seQ0oiTpHF2tXAcFbpdTLQFiaNtkyTXXocM1fwpaa60dg1qpWj0nHlbNhx6qwuENQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -7489,10 +8072,29 @@ packages: wcwidth: 1.0.1 dev: true + /ora@8.0.1: + resolution: {integrity: sha512-ANIvzobt1rls2BDny5fWZ3ZVKyD6nscLvfFRpQgfWsythlcsVUC9kL0zq6j2Z5z9wwp1kd7wpsD/T9qNPVLCaQ==} + engines: {node: '>=18'} + dependencies: + chalk: 5.3.0 + cli-cursor: 4.0.0 + cli-spinners: 2.9.2 + is-interactive: 2.0.0 + is-unicode-supported: 2.0.0 + log-symbols: 6.0.0 + stdin-discarder: 0.2.2 + string-width: 7.2.0 + strip-ansi: 7.1.0 + dev: false + /os-tmpdir@1.0.2: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} + /os@0.1.2: + resolution: {integrity: sha512-ZoXJkvAnljwvc56MbvhtKVWmSkzV712k42Is2mA0+0KTSRakq5XXuXpjZjgAt9ctzl51ojhQWakQQpmOvXWfjQ==} + dev: false + /outdent@0.5.0: resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} dev: false @@ -7550,7 +8152,7 @@ packages: dependencies: '@tootallnate/quickjs-emscripten': 0.23.0 agent-base: 7.1.1 - debug: 4.3.4 + debug: 4.3.5 get-uri: 6.0.3 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.5 @@ -7568,6 +8170,10 @@ packages: netmask: 2.0.2 dev: true + /package-json-from-dist@1.0.0: + resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==} + dev: false + /param-case@2.1.1: resolution: {integrity: sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==} dependencies: @@ -7579,7 +8185,6 @@ packages: engines: {node: '>=6'} dependencies: callsites: 3.1.0 - dev: true /parse-entities@4.0.1: resolution: {integrity: sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==} @@ -7602,7 +8207,11 @@ packages: error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - dev: true + + /parse-ms@4.0.0: + resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} + engines: {node: '>=18'} + dev: false /parse5@7.1.2: resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} @@ -7617,6 +8226,10 @@ packages: upper-case-first: 1.1.2 dev: true + /path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + dev: false + /path-case@2.1.1: resolution: {integrity: sha512-Ou0N05MioItesaLr9q8TtHVWmJ6fxWdqKB2RohFmNWVyJ+2zeKIeDNWAN6B/Pe7wpzWChhZX6nONYmOnMeJQ/Q==} dependencies: @@ -7636,6 +8249,11 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + /path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + dev: false + /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} @@ -7646,6 +8264,14 @@ packages: lru-cache: 10.2.0 minipass: 7.0.4 + /path-scurry@2.0.0: + resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} + engines: {node: 20 || >=22} + dependencies: + lru-cache: 11.0.0 + minipass: 7.1.2 + dev: false + /path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -7655,6 +8281,13 @@ packages: engines: {node: '>=12'} dev: true + /path@0.12.7: + resolution: {integrity: sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==} + dependencies: + process: 0.11.10 + util: 0.10.4 + dev: false + /periscopic@3.1.0: resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} dependencies: @@ -7700,7 +8333,7 @@ packages: engines: {node: '>= 0.4'} dev: true - /postcss-cli@11.0.0(postcss@8.4.39): + /postcss-cli@11.0.0(postcss@8.4.39)(tsx@4.17.0): resolution: {integrity: sha512-xMITAI7M0u1yolVcXJ9XTZiO9aO49mcoKQy6pCDFdMh9kGqhzLVpWxeD/32M/QBmkhcGypZFFOLNLmIW4Pg4RA==} engines: {node: '>=18'} hasBin: true @@ -7714,7 +8347,7 @@ packages: globby: 14.0.2 picocolors: 1.0.1 postcss: 8.4.39 - postcss-load-config: 5.1.0(postcss@8.4.39) + postcss-load-config: 5.1.0(postcss@8.4.39)(tsx@4.17.0) postcss-reporter: 7.1.0(postcss@8.4.39) pretty-hrtime: 1.0.3 read-cache: 1.0.0 @@ -7772,7 +8405,7 @@ packages: postcss: 8.4.39 yaml: 2.4.5 - /postcss-load-config@5.1.0(postcss@8.4.39): + /postcss-load-config@5.1.0(postcss@8.4.39)(tsx@4.17.0): resolution: {integrity: sha512-G5AJ+IX0aD0dygOE0yFZQ/huFFMSNneyfp0e3/bT05a8OfPC5FUoZRPfGijUdGOJNMewJiwzcHJXFafFzeKFVA==} engines: {node: '>= 18'} peerDependencies: @@ -7789,10 +8422,11 @@ packages: dependencies: lilconfig: 3.1.2 postcss: 8.4.39 + tsx: 4.17.0 yaml: 2.4.5 dev: true - /postcss-load-config@6.0.1(postcss@8.4.39): + /postcss-load-config@6.0.1(postcss@8.4.39)(tsx@4.17.0): resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} engines: {node: '>= 18'} peerDependencies: @@ -7812,6 +8446,7 @@ packages: dependencies: lilconfig: 3.1.2 postcss: 8.4.39 + tsx: 4.17.0 dev: false /postcss-nested@6.0.1(postcss@8.4.39): @@ -7914,6 +8549,26 @@ packages: engines: {node: '>= 0.8'} dev: true + /pretty-ms@9.1.0: + resolution: {integrity: sha512-o1piW0n3tgKIKCwk2vpM/vOV13zjJzvP37Ioze54YlTHE06m4tjEbzg9WsKkvTuyYln2DHjo5pY4qrZGI0otpw==} + engines: {node: '>=18'} + dependencies: + parse-ms: 4.0.0 + dev: false + + /process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + dev: false + + /prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + dev: false + /prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} dependencies: @@ -7931,7 +8586,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.1 - debug: 4.3.4 + debug: 4.3.5 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.5 lru-cache: 7.18.3 @@ -8137,6 +8792,17 @@ packages: dependencies: picomatch: 2.3.1 + /recast@0.23.9: + resolution: {integrity: sha512-Hx/BGIbwj+Des3+xy5uAtAbdCyqK9y9wbBcDFDYanLS9JnMqf7OeF87HQwUimE87OEc72mr6tkKUKMBBL+hF9Q==} + engines: {node: '>= 4'} + dependencies: + ast-types: 0.16.1 + esprima: 4.0.1 + source-map: 0.6.1 + tiny-invariant: 1.3.3 + tslib: 2.6.2 + dev: false + /reflect.getprototypeof@1.0.6: resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} engines: {node: '>= 0.4'} @@ -8287,7 +8953,6 @@ packages: /resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} - dev: true /resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} @@ -8296,7 +8961,6 @@ packages: /resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - dev: true /resolve@1.19.0: resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==} @@ -8330,6 +8994,14 @@ packages: signal-exit: 3.0.7 dev: true + /restore-cursor@4.0.0: + resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + dev: false + /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -8342,6 +9014,15 @@ packages: glob: 7.2.3 dev: true + /rimraf@6.0.1: + resolution: {integrity: sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==} + engines: {node: 20 || >=22} + hasBin: true + dependencies: + glob: 11.0.0 + package-json-from-dist: 1.0.0 + dev: false + /rollup@4.18.1: resolution: {integrity: sha512-Elx2UT8lzxxOXMpy5HWQGZqkrQOtrVDDa/bm9l10+U4rQnVzbL/LgZ4NOM1MPIDyHk69W4InuYDF5dzRh4Kw1A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -8568,6 +9249,10 @@ packages: is-arrayish: 0.3.2 dev: false + /sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + dev: false + /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -8598,7 +9283,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.1 - debug: 4.3.4 + debug: 4.3.5 socks: 2.8.3 transitivePeerDependencies: - supports-color @@ -8637,7 +9322,6 @@ packages: /source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - dev: true /source-map@0.7.4: resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} @@ -8692,6 +9376,11 @@ packages: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} dev: true + /stdin-discarder@0.2.2: + resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} + engines: {node: '>=18'} + dev: false + /stop-iteration-iterator@1.0.0: resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} engines: {node: '>= 0.4'} @@ -8720,6 +9409,15 @@ packages: emoji-regex: 9.2.2 strip-ansi: 7.1.0 + /string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + dependencies: + emoji-regex: 10.3.0 + get-east-asian-width: 1.2.0 + strip-ansi: 7.1.0 + dev: false + /string.prototype.includes@2.0.0: resolution: {integrity: sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==} dependencies: @@ -8817,6 +9515,11 @@ packages: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} + /strip-final-newline@4.0.0: + resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} + engines: {node: '>=18'} + dev: false + /strip-indent@3.0.0: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} @@ -8994,6 +9697,10 @@ packages: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} dev: true + /tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + dev: false + /tinycolor2@1.6.0: resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} dev: true @@ -9068,6 +9775,13 @@ packages: /ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + /ts-morph@23.0.0: + resolution: {integrity: sha512-FcvFx7a9E8TUe6T3ShihXJLiJOiqyafzFKUO4aqIHDUCIvADdGNShcbc2W5PMr3LerXRv7mafvFZ9lRENxJmug==} + dependencies: + '@ts-morph/common': 0.24.0 + code-block-writer: 13.0.2 + dev: false + /ts-node@10.9.2(@swc/core@1.6.13)(@types/node@20.14.10)(typescript@5.5.3): resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true @@ -9109,6 +9823,15 @@ packages: strip-bom: 3.0.0 dev: true + /tsconfig-paths@4.2.0: + resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} + engines: {node: '>=6'} + dependencies: + json5: 2.2.3 + minimist: 1.2.8 + strip-bom: 3.0.0 + dev: false + /tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} dev: true @@ -9116,7 +9839,7 @@ packages: /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - /tsup@8.1.1(@swc/core@1.6.13)(postcss@8.4.39)(typescript@5.5.3): + /tsup@8.1.1(@swc/core@1.6.13)(postcss@8.4.39)(tsx@4.17.0)(typescript@5.5.3): resolution: {integrity: sha512-lLXP3BshJ6y/32b3tPZUB2siD2mkJ6mLzhbPOShfjogSc3aRw8MhbBV4cPKbqkbXuhsJR+c9B0W9RHMbtbXLMQ==} engines: {node: '>=18'} hasBin: true @@ -9146,7 +9869,7 @@ packages: globby: 11.1.0 joycon: 3.1.1 postcss: 8.4.39 - postcss-load-config: 6.0.1(postcss@8.4.39) + postcss-load-config: 6.0.1(postcss@8.4.39)(tsx@4.17.0) resolve-from: 5.0.0 rollup: 4.18.1 source-map: 0.8.0-beta.0 @@ -9160,6 +9883,48 @@ packages: - yaml dev: false + /tsup@8.1.1(tsx@4.17.0)(typescript@5.4.5): + resolution: {integrity: sha512-lLXP3BshJ6y/32b3tPZUB2siD2mkJ6mLzhbPOShfjogSc3aRw8MhbBV4cPKbqkbXuhsJR+c9B0W9RHMbtbXLMQ==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + '@microsoft/api-extractor': ^7.36.0 + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.5.0' + peerDependenciesMeta: + '@microsoft/api-extractor': + optional: true + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + dependencies: + bundle-require: 5.0.0(esbuild@0.23.0) + cac: 6.7.14 + chokidar: 3.6.0 + consola: 3.2.3 + debug: 4.3.5 + esbuild: 0.23.0 + execa: 5.1.1 + globby: 11.1.0 + joycon: 3.1.1 + postcss-load-config: 6.0.1(postcss@8.4.39)(tsx@4.17.0) + resolve-from: 5.0.0 + rollup: 4.18.1 + source-map: 0.8.0-beta.0 + sucrase: 3.35.0 + tree-kill: 1.2.2 + typescript: 5.4.5 + transitivePeerDependencies: + - jiti + - supports-color + - tsx + - yaml + dev: false + /tsutils@3.21.0(typescript@5.4.5): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} @@ -9170,6 +9935,16 @@ packages: typescript: 5.4.5 dev: true + /tsx@4.17.0: + resolution: {integrity: sha512-eN4mnDA5UMKDt4YZixo9tBioibaMBpoxBkD+rIPAjVmYERSG0/dWEY1CEFuV89CgASlKL499q8AhmkMnnjtOJg==} + engines: {node: '>=18.0.0'} + hasBin: true + dependencies: + esbuild: 0.23.0 + get-tsconfig: 4.7.5 + optionalDependencies: + fsevents: 2.3.3 + /turbo-darwin-64@2.0.9: resolution: {integrity: sha512-owlGsOaExuVGBUfrnJwjkL1BWlvefjSKczEAcpLx4BI7Oh6ttakOi+JyomkPkFlYElRpjbvlR2gP8WIn6M/+xQ==} cpu: [x64] @@ -9273,6 +10048,11 @@ packages: engines: {node: '>=8'} dev: true + /type-fest@4.24.0: + resolution: {integrity: sha512-spAaHzc6qre0TlZQQ2aA/nGMe+2Z/wyGk5Z+Ru2VUfdNwT6kWO6TjevOlpebsATEG1EIQ2sOiDszud3lO5mt/Q==} + engines: {node: '>=16'} + dev: false + /typed-array-buffer@1.0.2: resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} engines: {node: '>= 0.4'} @@ -9320,7 +10100,6 @@ packages: /typescript@5.4.5: resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} engines: {node: '>=14.17'} - dev: true /typescript@5.5.3: resolution: {integrity: sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==} @@ -9426,7 +10205,6 @@ packages: /universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} - dev: true /update-browserslist-db@1.1.0(browserslist@4.23.2): resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==} @@ -9503,6 +10281,12 @@ packages: /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + /util@0.10.4: + resolution: {integrity: sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==} + dependencies: + inherits: 2.0.3 + dev: false + /v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} dev: true @@ -9551,6 +10335,11 @@ packages: resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} dev: false + /web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + dev: false + /webidl-conversions@4.0.2: resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} dev: false @@ -9716,6 +10505,11 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + /yoctocolors@2.1.1: + resolution: {integrity: sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==} + engines: {node: '>=18'} + dev: false + /zod@3.23.8: resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} dev: false