From 6cbdafeedca4663ec6ebe8c732a96f8073269089 Mon Sep 17 00:00:00 2001 From: Kai <4711233+kaiiiiiiiii@users.noreply.github.com> Date: Thu, 25 Sep 2025 11:12:44 +0000 Subject: [PATCH 1/2] feat: add support for oxlint toolchain in cli and project templates --- cli/create-start-app/README.md | 4 +- cli/create-tanstack-app/README.md | 4 +- cli/create-tanstack/README.md | 4 +- cli/create-tsrouter-app/README.md | 4 +- cli/ts-create-start/README.md | 4 +- .../react-cra/project/base/README.md.ejs | 5 +- .../base/_dot_vscode/settings.json.ejs | 21 +++ .../react-cra/project/base/tsconfig.json.ejs | 1 + .../snapshots/react-cra/fr-ts-biome-npm.json | 2 +- .../toolchains/oxlint/assets/.oxlintrc.json | 142 ++++++++++++++++++ .../oxlint/assets/_dot_prettierignore | 3 + .../oxlint/assets/prettier.config.js | 10 ++ .../react-cra/toolchains/oxlint/info.json | 8 + .../react-cra/toolchains/oxlint/package.json | 11 ++ .../toolchains/oxlint/small-logo.svg | 14 ++ frameworks/solid/project/base/README.md.ejs | 5 +- .../base/_dot_vscode/settings.json.ejs | 21 +++ .../solid/project/base/tsconfig.json.ejs | 1 + .../toolchains/oxlint/assets/.oxlintrc.json | 142 ++++++++++++++++++ .../oxlint/assets/_dot_prettierignore | 3 + .../oxlint/assets/prettier.config.js | 10 ++ frameworks/solid/toolchains/oxlint/info.json | 8 + .../solid/toolchains/oxlint/package.json | 11 ++ .../solid/toolchains/oxlint/small-logo.svg | 14 ++ packages/cta-cli/tests/options.test.ts | 18 +++ 25 files changed, 462 insertions(+), 8 deletions(-) create mode 100644 frameworks/react-cra/toolchains/oxlint/assets/.oxlintrc.json create mode 100644 frameworks/react-cra/toolchains/oxlint/assets/_dot_prettierignore create mode 100644 frameworks/react-cra/toolchains/oxlint/assets/prettier.config.js create mode 100644 frameworks/react-cra/toolchains/oxlint/info.json create mode 100644 frameworks/react-cra/toolchains/oxlint/package.json create mode 100644 frameworks/react-cra/toolchains/oxlint/small-logo.svg create mode 100644 frameworks/solid/toolchains/oxlint/assets/.oxlintrc.json create mode 100644 frameworks/solid/toolchains/oxlint/assets/_dot_prettierignore create mode 100644 frameworks/solid/toolchains/oxlint/assets/prettier.config.js create mode 100644 frameworks/solid/toolchains/oxlint/info.json create mode 100644 frameworks/solid/toolchains/oxlint/package.json create mode 100644 frameworks/solid/toolchains/oxlint/small-logo.svg diff --git a/cli/create-start-app/README.md b/cli/create-start-app/README.md index 9b4b54e2..0406fa59 100644 --- a/cli/create-start-app/README.md +++ b/cli/create-start-app/README.md @@ -37,7 +37,7 @@ pnpx create-start-app@latest my-app --tailwind --package-manager pnpm Available options: - `--package-manager`: Specify your preferred package manager (`npm`, `yarn`, `pnpm`, `bun`, or `deno`) -- `--toolchain`: Specify your toolchain solution for formatting/linting (`biome`, `eslint+prettier`) +- `--toolchain`: Specify your toolchain solution for formatting/linting (`biome`, `eslint+prettier`, `oxlint`) - `--no-git`: Do not initialize a git repository - `--add-ons`: Enable add-on selection or specify add-ons to install @@ -65,6 +65,8 @@ Setting this flag to `biome` will configure it as your toolchain of choice, addi Setting this flag to `eslint+prettier` will configure it as your toolchain of choice, adding an `eslint.config.js` and `prettier.config.js` to the root of the project, as well as a `.prettierignore` file. Consult the [eslint documentation](https://eslint.org/docs/latest/) and [prettier documentation](https://prettier.io/docs/) for further customization. +Setting this flag to `oxlint` will configure it as your toolchain of choice, adding a `.oxlintrc.json`, `prettier.config.js`, and `.prettierignore` to the root of the project. Consult the [oxlint documentation](https://oxc.rs/docs/guide/usage/linter.html) and [prettier documentation](https://prettier.io/docs/) for further customization. + ## Add-ons (experimental) You can enable add-on selection: diff --git a/cli/create-tanstack-app/README.md b/cli/create-tanstack-app/README.md index d7e43ff9..d1f884c4 100644 --- a/cli/create-tanstack-app/README.md +++ b/cli/create-tanstack-app/README.md @@ -46,7 +46,7 @@ Available options: - `--template `: Choose between `file-router`, `typescript`, or `javascript` - `--tailwind`: Enable Tailwind CSS - `--package-manager`: Specify your preferred package manager (`npm`, `yarn`, `pnpm`, `bun`, or `deno`) -- `--toolchain`: Specify your toolchain solution for formatting/linting (`biome`, `eslint+prettier`) +- `--toolchain`: Specify your toolchain solution for formatting/linting (`biome`, `eslint+prettier`, `oxlint`) - `--no-git`: Do not initialize a git repository - `--add-ons`: Enable add-on selection or specify add-ons to install @@ -104,6 +104,8 @@ Setting this flag to `biome` will configure it as your toolchain of choice, addi Setting this flag to `eslint+prettier` will configure it as your toolchain of choice, adding an `eslint.config.js` and `prettier.config.js` to the root of the project, as well as a `.prettierignore` file. Consult the [eslint documentation](https://eslint.org/docs/latest/) and [prettier documentation](https://prettier.io/docs/) for further customization. +Setting this flag to `oxlint` will configure it as your toolchain of choice, adding a `.oxlintrc.json`, `prettier.config.js`, and `.prettierignore` to the root of the project. Consult the [oxlint documentation](https://oxc.rs/docs/guide/usage/linter.html) and [prettier documentation](https://prettier.io/docs/) for further customization. + ## Add-ons (experimental) You can enable add-on selection: diff --git a/cli/create-tanstack/README.md b/cli/create-tanstack/README.md index 3f8092e5..da8da8e4 100644 --- a/cli/create-tanstack/README.md +++ b/cli/create-tanstack/README.md @@ -46,7 +46,7 @@ Available options: - `--template `: Choose between `file-router`, `typescript`, or `javascript` - `--tailwind`: Enable Tailwind CSS - `--package-manager`: Specify your preferred package manager (`npm`, `yarn`, `pnpm`, `bun`, or `deno`) -- `--toolchain`: Specify your toolchain solution for formatting/linting (`biome`, `eslint+prettier`) +- `--toolchain`: Specify your toolchain solution for formatting/linting (`biome`, `eslint+prettier`, `oxlint`) - `--no-git`: Do not initialize a git repository - `--add-ons`: Enable add-on selection or specify add-ons to install @@ -104,6 +104,8 @@ Setting this flag to `biome` will configure it as your toolchain of choice, addi Setting this flag to `eslint+prettier` will configure it as your toolchain of choice, adding an `eslint.config.js` and `prettier.config.js` to the root of the project, as well as a `.prettierignore` file. Consult the [eslint documentation](https://eslint.org/docs/latest/) and [prettier documentation](https://prettier.io/docs/) for further customization. +Setting this flag to `oxlint` will configure it as your toolchain of choice, adding a `.oxlintrc.json`, `prettier.config.js`, and `.prettierignore` to the root of the project. Consult the [oxlint documentation](https://oxc.rs/docs/guide/usage/linter.html) and [prettier documentation](https://prettier.io/docs/) for further customization. + ## Add-ons (experimental) You can enable add-on selection: diff --git a/cli/create-tsrouter-app/README.md b/cli/create-tsrouter-app/README.md index a26b16f0..47917b62 100644 --- a/cli/create-tsrouter-app/README.md +++ b/cli/create-tsrouter-app/README.md @@ -46,7 +46,7 @@ Available options: - `--template `: Choose between `file-router`, `typescript`, or `javascript` - `--tailwind`: Enable Tailwind CSS - `--package-manager`: Specify your preferred package manager (`npm`, `yarn`, `pnpm`, `bun`, or `deno`) -- `--toolchain`: Specify your toolchain solution for formatting/linting (`biome`, `eslint+prettier`) +- `--toolchain`: Specify your toolchain solution for formatting/linting (`biome`, `eslint+prettier`, `oxlint`) - `--no-git`: Do not initialize a git repository - `--add-ons`: Enable add-on selection or specify add-ons to install @@ -104,6 +104,8 @@ Setting this flag to `biome` will configure it as your toolchain of choice, addi Setting this flag to `eslint+prettier` will configure it as your toolchain of choice, adding an `eslint.config.js` and `prettier.config.js` to the root of the project, as well as a `.prettierignore` file. Consult the [eslint documentation](https://eslint.org/docs/latest/) and [prettier documentation](https://prettier.io/docs/) for further customization. +Setting this flag to `oxlint` will configure it as your toolchain of choice, adding a `.oxlintrc.json`, `prettier.config.js`, and `.prettierignore` to the root of the project. Consult the [oxlint documentation](https://oxc.rs/docs/guide/usage/linter.html) and [prettier documentation](https://prettier.io/docs/) for further customization. + ## Add-ons (experimental) You can enable add-on selection: diff --git a/cli/ts-create-start/README.md b/cli/ts-create-start/README.md index 3998aacd..248295f9 100644 --- a/cli/ts-create-start/README.md +++ b/cli/ts-create-start/README.md @@ -37,7 +37,7 @@ pnpm create @tanstack/start@latest my-app --tailwind --package-manager pnpm Available options: - `--package-manager`: Specify your preferred package manager (`npm`, `yarn`, `pnpm`, `bun`, or `deno`) -- `--toolchain`: Specify your toolchain solution for formatting/linting (`biome`, `eslint+prettier`) +- `--toolchain`: Specify your toolchain solution for formatting/linting (`biome`, `eslint+prettier`, `oxlint`) - `--no-git`: Do not initialize a git repository - `--add-ons`: Enable add-on selection or specify add-ons to install @@ -65,6 +65,8 @@ Setting this flag to `biome` will configure it as your toolchain of choice, addi Setting this flag to `eslint+prettier` will configure it as your toolchain of choice, adding an `eslint.config.js` and `prettier.config.js` to the root of the project, as well as a `.prettierignore` file. Consult the [eslint documentation](https://eslint.org/docs/latest/) and [prettier documentation](https://prettier.io/docs/) for further customization. +Setting this flag to `oxlint` will configure it as your toolchain of choice, adding a `.oxlintrc.json`, `prettier.config.js`, and `.prettierignore` to the root of the project. Consult the [oxlint documentation](https://oxc.rs/docs/guide/usage/linter.html) and [prettier documentation](https://prettier.io/docs/) for further customization. + ## Add-ons (experimental) You can enable add-on selection: diff --git a/frameworks/react-cra/project/base/README.md.ejs b/frameworks/react-cra/project/base/README.md.ejs index 95c3caa0..f90fa755 100644 --- a/frameworks/react-cra/project/base/README.md.ejs +++ b/frameworks/react-cra/project/base/README.md.ejs @@ -31,7 +31,7 @@ This project uses [Tailwind CSS](https://tailwindcss.com/) for styling. <% } else { %> This project uses CSS for styling. <% } %> -<% if (addOnEnabled.biome || addOnEnabled.eslint) { %> +<% if (addOnEnabled.biome || addOnEnabled.eslint || addOnEnabled.oxlint) { %> ## Linting & Formatting <% if (addOnEnabled.biome) { %> This project uses [Biome](https://biomejs.dev/) for linting and formatting. The following scripts are available: @@ -39,6 +39,9 @@ This project uses [Biome](https://biomejs.dev/) for linting and formatting. The <% if (addOnEnabled.eslint) { %> This project uses [eslint](https://eslint.org/) and [prettier](https://prettier.io/) for linting and formatting. Eslint is configured using [tanstack/eslint-config](https://tanstack.com/config/latest/docs/eslint). The following scripts are available: <% } %> +<% if (addOnEnabled.oxlint) { %> +This project uses [Oxlint](https://oxc.rs/docs/guide/usage/linter.html) and [prettier](https://prettier.io/) for linting and formatting. The following scripts are available: +<% } %> ```bash <%= getPackageManagerRunScript('lint') %> <%= getPackageManagerRunScript('format') %> diff --git a/frameworks/react-cra/project/base/_dot_vscode/settings.json.ejs b/frameworks/react-cra/project/base/_dot_vscode/settings.json.ejs index a429a12b..6e038364 100644 --- a/frameworks/react-cra/project/base/_dot_vscode/settings.json.ejs +++ b/frameworks/react-cra/project/base/_dot_vscode/settings.json.ejs @@ -31,5 +31,26 @@ }, "editor.codeActionsOnSave": { "source.organizeImports.biome": "explicit" + }<% } %><% if (addOnEnabled.oxlint) { %>, + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[javascriptreact]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[typescriptreact]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[jsonc]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[css]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" }<% } %> } diff --git a/frameworks/react-cra/project/base/tsconfig.json.ejs b/frameworks/react-cra/project/base/tsconfig.json.ejs index 8a820527..74c6af0d 100644 --- a/frameworks/react-cra/project/base/tsconfig.json.ejs +++ b/frameworks/react-cra/project/base/tsconfig.json.ejs @@ -1,5 +1,6 @@ <% if (!typescript) { ignoreFile() } %>{ <% if (addOnEnabled.eslint) { %>"include": ["**/*.ts", "**/*.tsx", "eslint.config.js", "prettier.config.js", "vite.config.js"], + <% } else if (addOnEnabled.oxlint) { %>"include": ["**/*.ts", "**/*.tsx", ".oxlintrc.json", "prettier.config.js", "vite.config.js"], <% } else { %>"include": ["**/*.ts", "**/*.tsx"],<% } %> "compilerOptions": { "target": "ES2022", diff --git a/frameworks/react-cra/tests/snapshots/react-cra/fr-ts-biome-npm.json b/frameworks/react-cra/tests/snapshots/react-cra/fr-ts-biome-npm.json index 1c8b98ba..c40ddd3e 100644 --- a/frameworks/react-cra/tests/snapshots/react-cra/fr-ts-biome-npm.json +++ b/frameworks/react-cra/tests/snapshots/react-cra/fr-ts-biome-npm.json @@ -12,7 +12,7 @@ "/src/routes/__root.tsx": "import { Outlet, createRootRoute } from '@tanstack/react-router'\nimport { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'\nimport { TanstackDevtools } from '@tanstack/react-devtools'\n\nimport Header from '../components/Header'\n\nexport const Route = createRootRoute({\n component: () => (\n <>\n
\n \n ,\n },\n ]}\n />\n \n ),\n})\n", "/src/routes/index.tsx": "import { createFileRoute } from '@tanstack/react-router'\nimport logo from '../logo.svg'\nimport '../App.css'\n\nexport const Route = createFileRoute('/')({\n component: App,\n})\n\nfunction App() {\n return (\n
\n
\n \"logo\"\n

\n Edit src/routes/index.tsx and save to reload.\n

\n \n Learn React\n \n \n Learn TanStack\n \n
\n
\n )\n}\n", "/src/styles.css": "\nbody {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\",\n \"Ubuntu\", \"Cantarell\", \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\n sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, \"Courier New\",\n monospace;\n}\n", - "README.md": "Welcome to your new TanStack app! \n\n# Getting Started\n\nTo run this application:\n\n```bash\nnpm install\nnpm run start\n```\n\n# Building For Production\n\nTo build this application for production:\n\n```bash\nnpm run build\n```\n\n## Testing\n\nThis project uses [Vitest](https://vitest.dev/) for testing. You can run the tests with:\n\n```bash\nnpm run test\n```\n\n## Styling\n\nThis project uses CSS for styling.\n\n\n## Linting & Formatting\n\nThis project uses [Biome](https://biomejs.dev/) for linting and formatting. The following scripts are available:\n\n\n```bash\nnpm run lint\nnpm run format\nnpm run check\n```\n\n\n\n## Routing\nThis project uses [TanStack Router](https://tanstack.com/router). The initial setup is a file based router. Which means that the routes are managed as files in `src/routes`.\n\n### Adding A Route\n\nTo add a new route to your application just add another a new file in the `./src/routes` directory.\n\nTanStack will automatically generate the content of the route file for you.\n\nNow that you have two routes you can use a `Link` component to navigate between them.\n\n### Adding Links\n\nTo use SPA (Single Page Application) navigation you will need to import the `Link` component from `@tanstack/react-router`.\n\n```tsx\nimport { Link } from \"@tanstack/react-router\";\n```\n\nThen anywhere in your JSX you can use it like so:\n\n```tsx\nAbout\n```\n\nThis will create a link that will navigate to the `/about` route.\n\nMore information on the `Link` component can be found in the [Link documentation](https://tanstack.com/router/v1/docs/framework/react/api/router/linkComponent).\n\n### Using A Layout\n\nIn the File Based Routing setup the layout is located in `src/routes/__root.tsx`. Anything you add to the root route will appear in all the routes. The route content will appear in the JSX where you use the `` component.\n\nHere is an example layout that includes a header:\n\n```tsx\nimport { Outlet, createRootRoute } from '@tanstack/react-router'\nimport { TanStackRouterDevtools } from '@tanstack/react-router-devtools'\n\nimport { Link } from \"@tanstack/react-router\";\n\nexport const Route = createRootRoute({\n component: () => (\n <>\n
\n \n
\n \n \n \n ),\n})\n```\n\nThe `` component is not required so you can remove it if you don't want it in your layout.\n\nMore information on layouts can be found in the [Layouts documentation](https://tanstack.com/router/latest/docs/framework/react/guide/routing-concepts#layouts).\n\n\n## Data Fetching\n\nThere are multiple ways to fetch data in your application. You can use TanStack Query to fetch data from a server. But you can also use the `loader` functionality built into TanStack Router to load the data for a route before it's rendered.\n\nFor example:\n\n```tsx\nconst peopleRoute = createRoute({\n getParentRoute: () => rootRoute,\n path: \"/people\",\n loader: async () => {\n const response = await fetch(\"https://swapi.dev/api/people\");\n return response.json() as Promise<{\n results: {\n name: string;\n }[];\n }>;\n },\n component: () => {\n const data = peopleRoute.useLoaderData();\n return (\n
    \n {data.results.map((person) => (\n
  • {person.name}
  • \n ))}\n
\n );\n },\n});\n```\n\nLoaders simplify your data fetching logic dramatically. Check out more information in the [Loader documentation](https://tanstack.com/router/latest/docs/framework/react/guide/data-loading#loader-parameters).\n\n### React-Query\n\nReact-Query is an excellent addition or alternative to route loading and integrating it into you application is a breeze.\n\nFirst add your dependencies:\n\n```bash\nnpm install @tanstack/react-query @tanstack/react-query-devtools\n```\n\nNext we'll need to create a query client and provider. We recommend putting those in `main.tsx`.\n\n```tsx\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\n\n// ...\n\nconst queryClient = new QueryClient();\n\n// ...\n\nif (!rootElement.innerHTML) {\n const root = ReactDOM.createRoot(rootElement);\n\n root.render(\n \n \n \n );\n}\n```\n\nYou can also add TanStack Query Devtools to the root route (optional).\n\n```tsx\nimport { ReactQueryDevtools } from \"@tanstack/react-query-devtools\";\n\nconst rootRoute = createRootRoute({\n component: () => (\n <>\n \n \n \n \n ),\n});\n```\n\nNow you can use `useQuery` to fetch your data.\n\n```tsx\nimport { useQuery } from \"@tanstack/react-query\";\n\nimport \"./App.css\";\n\nfunction App() {\n const { data } = useQuery({\n queryKey: [\"people\"],\n queryFn: () =>\n fetch(\"https://swapi.dev/api/people\")\n .then((res) => res.json())\n .then((data) => data.results as { name: string }[]),\n initialData: [],\n });\n\n return (\n
\n
    \n {data.map((person) => (\n
  • {person.name}
  • \n ))}\n
\n
\n );\n}\n\nexport default App;\n```\n\nYou can find out everything you need to know on how to use React-Query in the [React-Query documentation](https://tanstack.com/query/latest/docs/framework/react/overview).\n\n## State Management\n\nAnother common requirement for React applications is state management. There are many options for state management in React. TanStack Store provides a great starting point for your project.\n\nFirst you need to add TanStack Store as a dependency:\n\n```bash\nnpm install @tanstack/store\n```\n\nNow let's create a simple counter in the `src/App.tsx` file as a demonstration.\n\n```tsx\nimport { useStore } from \"@tanstack/react-store\";\nimport { Store } from \"@tanstack/store\";\nimport \"./App.css\";\n\nconst countStore = new Store(0);\n\nfunction App() {\n const count = useStore(countStore);\n return (\n
\n \n
\n );\n}\n\nexport default App;\n```\n\nOne of the many nice features of TanStack Store is the ability to derive state from other state. That derived state will update when the base state updates.\n\nLet's check this out by doubling the count using derived state.\n\n```tsx\nimport { useStore } from \"@tanstack/react-store\";\nimport { Store, Derived } from \"@tanstack/store\";\nimport \"./App.css\";\n\nconst countStore = new Store(0);\n\nconst doubledStore = new Derived({\n fn: () => countStore.state * 2,\n deps: [countStore],\n});\ndoubledStore.mount();\n\nfunction App() {\n const count = useStore(countStore);\n const doubledCount = useStore(doubledStore);\n\n return (\n
\n \n
Doubled - {doubledCount}
\n
\n );\n}\n\nexport default App;\n```\n\nWe use the `Derived` class to create a new store that is derived from another store. The `Derived` class has a `mount` method that will start the derived store updating.\n\nOnce we've created the derived store we can use it in the `App` component just like we would any other store using the `useStore` hook.\n\nYou can find out everything you need to know on how to use TanStack Store in the [TanStack Store documentation](https://tanstack.com/store/latest).\n\n# Demo files\n\nFiles prefixed with `demo` can be safely deleted. They are there to provide a starting point for you to play around with the features you've installed.\n\n# Learn More\n\nYou can learn more about all of the offerings from TanStack in the [TanStack documentation](https://tanstack.com).\n", + "README.md": "Welcome to your new TanStack app! \n\n# Getting Started\n\nTo run this application:\n\n```bash\nnpm install\nnpm run start\n```\n\n# Building For Production\n\nTo build this application for production:\n\n```bash\nnpm run build\n```\n\n## Testing\n\nThis project uses [Vitest](https://vitest.dev/) for testing. You can run the tests with:\n\n```bash\nnpm run test\n```\n\n## Styling\n\nThis project uses CSS for styling.\n\n\n## Linting & Formatting\n\nThis project uses [Biome](https://biomejs.dev/) for linting and formatting. The following scripts are available:\n\n\n\n```bash\nnpm run lint\nnpm run format\nnpm run check\n```\n\n\n\n## Routing\nThis project uses [TanStack Router](https://tanstack.com/router). The initial setup is a file based router. Which means that the routes are managed as files in `src/routes`.\n\n### Adding A Route\n\nTo add a new route to your application just add another a new file in the `./src/routes` directory.\n\nTanStack will automatically generate the content of the route file for you.\n\nNow that you have two routes you can use a `Link` component to navigate between them.\n\n### Adding Links\n\nTo use SPA (Single Page Application) navigation you will need to import the `Link` component from `@tanstack/react-router`.\n\n```tsx\nimport { Link } from \"@tanstack/react-router\";\n```\n\nThen anywhere in your JSX you can use it like so:\n\n```tsx\nAbout\n```\n\nThis will create a link that will navigate to the `/about` route.\n\nMore information on the `Link` component can be found in the [Link documentation](https://tanstack.com/router/v1/docs/framework/react/api/router/linkComponent).\n\n### Using A Layout\n\nIn the File Based Routing setup the layout is located in `src/routes/__root.tsx`. Anything you add to the root route will appear in all the routes. The route content will appear in the JSX where you use the `` component.\n\nHere is an example layout that includes a header:\n\n```tsx\nimport { Outlet, createRootRoute } from '@tanstack/react-router'\nimport { TanStackRouterDevtools } from '@tanstack/react-router-devtools'\n\nimport { Link } from \"@tanstack/react-router\";\n\nexport const Route = createRootRoute({\n component: () => (\n <>\n
\n \n
\n \n \n \n ),\n})\n```\n\nThe `` component is not required so you can remove it if you don't want it in your layout.\n\nMore information on layouts can be found in the [Layouts documentation](https://tanstack.com/router/latest/docs/framework/react/guide/routing-concepts#layouts).\n\n\n## Data Fetching\n\nThere are multiple ways to fetch data in your application. You can use TanStack Query to fetch data from a server. But you can also use the `loader` functionality built into TanStack Router to load the data for a route before it's rendered.\n\nFor example:\n\n```tsx\nconst peopleRoute = createRoute({\n getParentRoute: () => rootRoute,\n path: \"/people\",\n loader: async () => {\n const response = await fetch(\"https://swapi.dev/api/people\");\n return response.json() as Promise<{\n results: {\n name: string;\n }[];\n }>;\n },\n component: () => {\n const data = peopleRoute.useLoaderData();\n return (\n
    \n {data.results.map((person) => (\n
  • {person.name}
  • \n ))}\n
\n );\n },\n});\n```\n\nLoaders simplify your data fetching logic dramatically. Check out more information in the [Loader documentation](https://tanstack.com/router/latest/docs/framework/react/guide/data-loading#loader-parameters).\n\n### React-Query\n\nReact-Query is an excellent addition or alternative to route loading and integrating it into you application is a breeze.\n\nFirst add your dependencies:\n\n```bash\nnpm install @tanstack/react-query @tanstack/react-query-devtools\n```\n\nNext we'll need to create a query client and provider. We recommend putting those in `main.tsx`.\n\n```tsx\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\n\n// ...\n\nconst queryClient = new QueryClient();\n\n// ...\n\nif (!rootElement.innerHTML) {\n const root = ReactDOM.createRoot(rootElement);\n\n root.render(\n \n \n \n );\n}\n```\n\nYou can also add TanStack Query Devtools to the root route (optional).\n\n```tsx\nimport { ReactQueryDevtools } from \"@tanstack/react-query-devtools\";\n\nconst rootRoute = createRootRoute({\n component: () => (\n <>\n \n \n \n \n ),\n});\n```\n\nNow you can use `useQuery` to fetch your data.\n\n```tsx\nimport { useQuery } from \"@tanstack/react-query\";\n\nimport \"./App.css\";\n\nfunction App() {\n const { data } = useQuery({\n queryKey: [\"people\"],\n queryFn: () =>\n fetch(\"https://swapi.dev/api/people\")\n .then((res) => res.json())\n .then((data) => data.results as { name: string }[]),\n initialData: [],\n });\n\n return (\n
\n
    \n {data.map((person) => (\n
  • {person.name}
  • \n ))}\n
\n
\n );\n}\n\nexport default App;\n```\n\nYou can find out everything you need to know on how to use React-Query in the [React-Query documentation](https://tanstack.com/query/latest/docs/framework/react/overview).\n\n## State Management\n\nAnother common requirement for React applications is state management. There are many options for state management in React. TanStack Store provides a great starting point for your project.\n\nFirst you need to add TanStack Store as a dependency:\n\n```bash\nnpm install @tanstack/store\n```\n\nNow let's create a simple counter in the `src/App.tsx` file as a demonstration.\n\n```tsx\nimport { useStore } from \"@tanstack/react-store\";\nimport { Store } from \"@tanstack/store\";\nimport \"./App.css\";\n\nconst countStore = new Store(0);\n\nfunction App() {\n const count = useStore(countStore);\n return (\n
\n \n
\n );\n}\n\nexport default App;\n```\n\nOne of the many nice features of TanStack Store is the ability to derive state from other state. That derived state will update when the base state updates.\n\nLet's check this out by doubling the count using derived state.\n\n```tsx\nimport { useStore } from \"@tanstack/react-store\";\nimport { Store, Derived } from \"@tanstack/store\";\nimport \"./App.css\";\n\nconst countStore = new Store(0);\n\nconst doubledStore = new Derived({\n fn: () => countStore.state * 2,\n deps: [countStore],\n});\ndoubledStore.mount();\n\nfunction App() {\n const count = useStore(countStore);\n const doubledCount = useStore(doubledStore);\n\n return (\n
\n \n
Doubled - {doubledCount}
\n
\n );\n}\n\nexport default App;\n```\n\nWe use the `Derived` class to create a new store that is derived from another store. The `Derived` class has a `mount` method that will start the derived store updating.\n\nOnce we've created the derived store we can use it in the `App` component just like we would any other store using the `useStore` hook.\n\nYou can find out everything you need to know on how to use TanStack Store in the [TanStack Store documentation](https://tanstack.com/store/latest).\n\n# Demo files\n\nFiles prefixed with `demo` can be safely deleted. They are there to provide a starting point for you to play around with the features you've installed.\n\n# Learn More\n\nYou can learn more about all of the offerings from TanStack in the [TanStack documentation](https://tanstack.com).\n", "biome.json": "{\n \"$schema\": \"https://biomejs.dev/schemas/1.9.4/schema.json\",\n \"vcs\": {\n \"enabled\": false,\n \"clientKind\": \"git\",\n \"useIgnoreFile\": false\n },\n \"files\": {\n \"ignoreUnknown\": false,\n \"ignore\": [\"src/routeTree.gen.ts\"],\n \"include\": [\"src/*\", \".vscode/*\", \"index.html\", \"vite.config.js\"]\n },\n \"formatter\": {\n \"enabled\": true,\n \"indentStyle\": \"tab\"\n },\n \"organizeImports\": {\n \"enabled\": true\n },\n \"linter\": {\n \"enabled\": true,\n \"rules\": {\n \"recommended\": true\n }\n },\n \"javascript\": {\n \"formatter\": {\n \"quoteStyle\": \"double\"\n }\n }\n}\n", "index.html": "\n\n \n \n \n \n \n \n \n \n Create TanStack App - TEST\n \n \n
\n \n \n\n", "package.json": "{\n \"name\": \"TEST\",\n \"private\": true,\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite --port 3000\",\n \"start\": \"vite --port 3000\",\n \"build\": \"vite build && tsc\",\n \"serve\": \"vite preview\",\n \"test\": \"vitest run\",\n \"format\": \"biome format\",\n \"lint\": \"biome lint\",\n \"check\": \"biome check\"\n },\n \"dependencies\": {\n \"@tanstack/react-devtools\": \"^0.2.2\",\n \"@tanstack/react-router\": \"^1.132.0\",\n \"@tanstack/react-router-devtools\": \"^1.132.0\",\n \"@tanstack/router-plugin\": \"^1.132.0\",\n \"react\": \"^19.0.0\",\n \"react-dom\": \"^19.0.0\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"1.9.4\",\n \"@testing-library/dom\": \"^10.4.0\",\n \"@testing-library/react\": \"^16.2.0\",\n \"@types/node\": \"^22.10.2\",\n \"@types/react\": \"^19.0.8\",\n \"@types/react-dom\": \"^19.0.3\",\n \"@vitejs/plugin-react\": \"^4.3.4\",\n \"jsdom\": \"^26.0.0\",\n \"typescript\": \"^5.7.2\",\n \"vite\": \"^6.3.5\",\n \"vitest\": \"^3.0.5\",\n \"web-vitals\": \"^4.2.4\"\n }\n}", diff --git a/frameworks/react-cra/toolchains/oxlint/assets/.oxlintrc.json b/frameworks/react-cra/toolchains/oxlint/assets/.oxlintrc.json new file mode 100644 index 00000000..c819e5fd --- /dev/null +++ b/frameworks/react-cra/toolchains/oxlint/assets/.oxlintrc.json @@ -0,0 +1,142 @@ +{ + "$schema": "./node_modules/oxlint/configuration_schema.json", + "plugins": [ + "unicorn", + "typescript", + "oxc" + ], + "categories": {}, + "rules": { + "for-direction": "warn", + "no-async-promise-executor": "warn", + "no-caller": "warn", + "no-class-assign": "warn", + "no-compare-neg-zero": "warn", + "no-cond-assign": "warn", + "no-const-assign": "warn", + "no-constant-binary-expression": "warn", + "no-constant-condition": "warn", + "no-control-regex": "warn", + "no-debugger": "warn", + "no-delete-var": "warn", + "no-dupe-class-members": "warn", + "no-dupe-else-if": "warn", + "no-dupe-keys": "warn", + "no-duplicate-case": "warn", + "no-empty-character-class": "warn", + "no-empty-pattern": "warn", + "no-empty-static-block": "warn", + "no-eval": "warn", + "no-ex-assign": "warn", + "no-extra-boolean-cast": "warn", + "no-func-assign": "warn", + "no-global-assign": "warn", + "no-import-assign": "warn", + "no-invalid-regexp": "warn", + "no-irregular-whitespace": "warn", + "no-loss-of-precision": "warn", + "no-new-native-nonconstructor": "warn", + "no-nonoctal-decimal-escape": "warn", + "no-obj-calls": "warn", + "no-self-assign": "warn", + "no-setter-return": "warn", + "no-shadow-restricted-names": "warn", + "no-sparse-arrays": "warn", + "no-this-before-super": "warn", + "no-unassigned-vars": "warn", + "no-unsafe-finally": "warn", + "no-unsafe-negation": "warn", + "no-unsafe-optional-chaining": "warn", + "no-unused-labels": "warn", + "no-unused-private-class-members": "warn", + "no-unused-vars": "warn", + "no-useless-backreference": "warn", + "no-useless-catch": "warn", + "no-useless-escape": "warn", + "no-useless-rename": "warn", + "no-with": "warn", + "require-yield": "warn", + "use-isnan": "warn", + "valid-typeof": "warn", + "oxc/bad-array-method-on-arguments": "warn", + "oxc/bad-char-at-comparison": "warn", + "oxc/bad-comparison-sequence": "warn", + "oxc/bad-min-max-func": "warn", + "oxc/bad-object-literal-comparison": "warn", + "oxc/bad-replace-all-arg": "warn", + "oxc/const-comparisons": "warn", + "oxc/double-comparisons": "warn", + "oxc/erasing-op": "warn", + "oxc/missing-throw": "warn", + "oxc/number-arg-out-of-range": "warn", + "oxc/only-used-in-recursion": "warn", + "oxc/uninvoked-array-callback": "warn", + "typescript/await-thenable": "warn", + "typescript/no-array-delete": "warn", + "typescript/no-base-to-string": "warn", + "typescript/no-duplicate-enum-values": "warn", + "typescript/no-duplicate-type-constituents": "warn", + "typescript/no-extra-non-null-assertion": "warn", + "typescript/no-floating-promises": "warn", + "typescript/no-for-in-array": "warn", + "typescript/no-implied-eval": "warn", + "typescript/no-meaningless-void-operator": "warn", + "typescript/no-misused-new": "warn", + "typescript/no-misused-spread": "warn", + "typescript/no-non-null-asserted-optional-chain": "warn", + "typescript/no-redundant-type-constituents": "warn", + "typescript/no-this-alias": "warn", + "typescript/no-unnecessary-parameter-property-assignment": "warn", + "typescript/no-unsafe-declaration-merging": "warn", + "typescript/no-unsafe-unary-minus": "warn", + "typescript/no-useless-empty-export": "warn", + "typescript/no-wrapper-object-types": "warn", + "typescript/prefer-as-const": "warn", + "typescript/require-array-sort-compare": "warn", + "typescript/restrict-template-expressions": "warn", + "typescript/triple-slash-reference": "warn", + "typescript/unbound-method": "warn", + "unicorn/no-await-in-promise-methods": "warn", + "unicorn/no-empty-file": "warn", + "unicorn/no-invalid-fetch-options": "warn", + "unicorn/no-invalid-remove-event-listener": "warn", + "unicorn/no-new-array": "warn", + "unicorn/no-single-promise-in-promise-methods": "warn", + "unicorn/no-thenable": "warn", + "unicorn/no-unnecessary-await": "warn", + "unicorn/no-useless-fallback-in-spread": "warn", + "unicorn/no-useless-length-check": "warn", + "unicorn/no-useless-spread": "warn", + "unicorn/prefer-set-size": "warn", + "unicorn/prefer-string-starts-ends-with": "warn" + }, + "settings": { + "jsx-a11y": { + "polymorphicPropName": null, + "components": {}, + "attributes": {} + }, + "next": { + "rootDir": [] + }, + "react": { + "formComponents": [], + "linkComponents": [] + }, + "jsdoc": { + "ignorePrivate": false, + "ignoreInternal": false, + "ignoreReplacesDocs": true, + "overrideReplacesDocs": true, + "augmentsExtendsReplacesDocs": false, + "implementsReplacesDocs": false, + "exemptDestructuredRootsFromChecks": false, + "tagNamePreference": {} + } + }, + "env": { + "builtin": true + }, + "globals": {}, + "ignorePatterns": [] +} \ No newline at end of file diff --git a/frameworks/react-cra/toolchains/oxlint/assets/_dot_prettierignore b/frameworks/react-cra/toolchains/oxlint/assets/_dot_prettierignore new file mode 100644 index 00000000..5322d7fe --- /dev/null +++ b/frameworks/react-cra/toolchains/oxlint/assets/_dot_prettierignore @@ -0,0 +1,3 @@ +package-lock.json +pnpm-lock.yaml +yarn.lock \ No newline at end of file diff --git a/frameworks/react-cra/toolchains/oxlint/assets/prettier.config.js b/frameworks/react-cra/toolchains/oxlint/assets/prettier.config.js new file mode 100644 index 00000000..aea1c480 --- /dev/null +++ b/frameworks/react-cra/toolchains/oxlint/assets/prettier.config.js @@ -0,0 +1,10 @@ +// @ts-check + +/** @type {import('prettier').Config} */ +const config = { + semi: false, + singleQuote: true, + trailingComma: "all", +}; + +export default config; diff --git a/frameworks/react-cra/toolchains/oxlint/info.json b/frameworks/react-cra/toolchains/oxlint/info.json new file mode 100644 index 00000000..4d65baa4 --- /dev/null +++ b/frameworks/react-cra/toolchains/oxlint/info.json @@ -0,0 +1,8 @@ +{ + "name": "Oxlint", + "description": "Oxlint linter + Prettier toolchain support.", + "phase": "setup", + "type": "toolchain", + "modes": ["code-router", "file-router"], + "link": "https://oxc.rs/docs/guide/usage/linter" +} diff --git a/frameworks/react-cra/toolchains/oxlint/package.json b/frameworks/react-cra/toolchains/oxlint/package.json new file mode 100644 index 00000000..3844353e --- /dev/null +++ b/frameworks/react-cra/toolchains/oxlint/package.json @@ -0,0 +1,11 @@ +{ + "scripts": { + "lint": "oxlint", + "format": "prettier", + "check": "prettier --write . && oxlint --fix" + }, + "devDependencies": { + "oxlint": "^1.18.0", + "prettier": "^3.5.3" + } +} diff --git a/frameworks/react-cra/toolchains/oxlint/small-logo.svg b/frameworks/react-cra/toolchains/oxlint/small-logo.svg new file mode 100644 index 00000000..fb3e2a86 --- /dev/null +++ b/frameworks/react-cra/toolchains/oxlint/small-logo.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/frameworks/solid/project/base/README.md.ejs b/frameworks/solid/project/base/README.md.ejs index 2bab1ff0..ffb3c98f 100644 --- a/frameworks/solid/project/base/README.md.ejs +++ b/frameworks/solid/project/base/README.md.ejs @@ -195,7 +195,7 @@ Loaders simplify your data fetching logic dramatically. Check out more informati Files prefixed with `demo` can be safely deleted. They are there to provide a starting point for you to play around with the features you've installed. -<% if (addOnEnabled.biome || addOnEnabled.eslint) { %> +<% if (addOnEnabled.biome || addOnEnabled.eslint || addOnEnabled.oxlint) { %> ## Linting & Formatting <% if (addOnEnabled.biome) { %> This project uses [Biome](https://biomejs.dev/) for linting and formatting. The following scripts are available: @@ -203,6 +203,9 @@ This project uses [Biome](https://biomejs.dev/) for linting and formatting. The <% if (addOnEnabled.eslint) { %> This project uses [eslint](https://eslint.org/) and [prettier](https://prettier.io/) for linting and formatting. Eslint is configured using [tanstack/eslint-config](https://tanstack.com/config/latest/docs/eslint). The following scripts are available: <% } %> +<% if (addOnEnabled.oxlint) { %> +This project uses [Oxlint](https://oxc.rs/docs/guide/usage/linter.html) and [prettier](https://prettier.io/) for linting and formatting. The following scripts are available: +<% } %> ```bash <%= getPackageManagerRunScript('lint') %> <%= getPackageManagerRunScript('format') %> diff --git a/frameworks/solid/project/base/_dot_vscode/settings.json.ejs b/frameworks/solid/project/base/_dot_vscode/settings.json.ejs index a429a12b..6e038364 100644 --- a/frameworks/solid/project/base/_dot_vscode/settings.json.ejs +++ b/frameworks/solid/project/base/_dot_vscode/settings.json.ejs @@ -31,5 +31,26 @@ }, "editor.codeActionsOnSave": { "source.organizeImports.biome": "explicit" + }<% } %><% if (addOnEnabled.oxlint) { %>, + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[javascriptreact]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[typescriptreact]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[jsonc]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[css]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" }<% } %> } diff --git a/frameworks/solid/project/base/tsconfig.json.ejs b/frameworks/solid/project/base/tsconfig.json.ejs index d0ae4e61..f2d3090b 100644 --- a/frameworks/solid/project/base/tsconfig.json.ejs +++ b/frameworks/solid/project/base/tsconfig.json.ejs @@ -1,5 +1,6 @@ <% if (!typescript) { ignoreFile() } %>{ <% if (addOnEnabled.eslint) { %>"include": ["**/*.ts", "**/*.tsx", "eslint.config.js", "prettier.config.js", "vite.config.js"], + <% } else if (addOnEnabled.oxlint) { %>"include": ["**/*.ts", "**/*.tsx", ".oxlintrc.json", "prettier.config.js", "vite.config.js"], <% } else { %>"include": ["**/*.ts", "**/*.tsx"],<% } %> "compilerOptions": { "target": "ES2022", diff --git a/frameworks/solid/toolchains/oxlint/assets/.oxlintrc.json b/frameworks/solid/toolchains/oxlint/assets/.oxlintrc.json new file mode 100644 index 00000000..c819e5fd --- /dev/null +++ b/frameworks/solid/toolchains/oxlint/assets/.oxlintrc.json @@ -0,0 +1,142 @@ +{ + "$schema": "./node_modules/oxlint/configuration_schema.json", + "plugins": [ + "unicorn", + "typescript", + "oxc" + ], + "categories": {}, + "rules": { + "for-direction": "warn", + "no-async-promise-executor": "warn", + "no-caller": "warn", + "no-class-assign": "warn", + "no-compare-neg-zero": "warn", + "no-cond-assign": "warn", + "no-const-assign": "warn", + "no-constant-binary-expression": "warn", + "no-constant-condition": "warn", + "no-control-regex": "warn", + "no-debugger": "warn", + "no-delete-var": "warn", + "no-dupe-class-members": "warn", + "no-dupe-else-if": "warn", + "no-dupe-keys": "warn", + "no-duplicate-case": "warn", + "no-empty-character-class": "warn", + "no-empty-pattern": "warn", + "no-empty-static-block": "warn", + "no-eval": "warn", + "no-ex-assign": "warn", + "no-extra-boolean-cast": "warn", + "no-func-assign": "warn", + "no-global-assign": "warn", + "no-import-assign": "warn", + "no-invalid-regexp": "warn", + "no-irregular-whitespace": "warn", + "no-loss-of-precision": "warn", + "no-new-native-nonconstructor": "warn", + "no-nonoctal-decimal-escape": "warn", + "no-obj-calls": "warn", + "no-self-assign": "warn", + "no-setter-return": "warn", + "no-shadow-restricted-names": "warn", + "no-sparse-arrays": "warn", + "no-this-before-super": "warn", + "no-unassigned-vars": "warn", + "no-unsafe-finally": "warn", + "no-unsafe-negation": "warn", + "no-unsafe-optional-chaining": "warn", + "no-unused-labels": "warn", + "no-unused-private-class-members": "warn", + "no-unused-vars": "warn", + "no-useless-backreference": "warn", + "no-useless-catch": "warn", + "no-useless-escape": "warn", + "no-useless-rename": "warn", + "no-with": "warn", + "require-yield": "warn", + "use-isnan": "warn", + "valid-typeof": "warn", + "oxc/bad-array-method-on-arguments": "warn", + "oxc/bad-char-at-comparison": "warn", + "oxc/bad-comparison-sequence": "warn", + "oxc/bad-min-max-func": "warn", + "oxc/bad-object-literal-comparison": "warn", + "oxc/bad-replace-all-arg": "warn", + "oxc/const-comparisons": "warn", + "oxc/double-comparisons": "warn", + "oxc/erasing-op": "warn", + "oxc/missing-throw": "warn", + "oxc/number-arg-out-of-range": "warn", + "oxc/only-used-in-recursion": "warn", + "oxc/uninvoked-array-callback": "warn", + "typescript/await-thenable": "warn", + "typescript/no-array-delete": "warn", + "typescript/no-base-to-string": "warn", + "typescript/no-duplicate-enum-values": "warn", + "typescript/no-duplicate-type-constituents": "warn", + "typescript/no-extra-non-null-assertion": "warn", + "typescript/no-floating-promises": "warn", + "typescript/no-for-in-array": "warn", + "typescript/no-implied-eval": "warn", + "typescript/no-meaningless-void-operator": "warn", + "typescript/no-misused-new": "warn", + "typescript/no-misused-spread": "warn", + "typescript/no-non-null-asserted-optional-chain": "warn", + "typescript/no-redundant-type-constituents": "warn", + "typescript/no-this-alias": "warn", + "typescript/no-unnecessary-parameter-property-assignment": "warn", + "typescript/no-unsafe-declaration-merging": "warn", + "typescript/no-unsafe-unary-minus": "warn", + "typescript/no-useless-empty-export": "warn", + "typescript/no-wrapper-object-types": "warn", + "typescript/prefer-as-const": "warn", + "typescript/require-array-sort-compare": "warn", + "typescript/restrict-template-expressions": "warn", + "typescript/triple-slash-reference": "warn", + "typescript/unbound-method": "warn", + "unicorn/no-await-in-promise-methods": "warn", + "unicorn/no-empty-file": "warn", + "unicorn/no-invalid-fetch-options": "warn", + "unicorn/no-invalid-remove-event-listener": "warn", + "unicorn/no-new-array": "warn", + "unicorn/no-single-promise-in-promise-methods": "warn", + "unicorn/no-thenable": "warn", + "unicorn/no-unnecessary-await": "warn", + "unicorn/no-useless-fallback-in-spread": "warn", + "unicorn/no-useless-length-check": "warn", + "unicorn/no-useless-spread": "warn", + "unicorn/prefer-set-size": "warn", + "unicorn/prefer-string-starts-ends-with": "warn" + }, + "settings": { + "jsx-a11y": { + "polymorphicPropName": null, + "components": {}, + "attributes": {} + }, + "next": { + "rootDir": [] + }, + "react": { + "formComponents": [], + "linkComponents": [] + }, + "jsdoc": { + "ignorePrivate": false, + "ignoreInternal": false, + "ignoreReplacesDocs": true, + "overrideReplacesDocs": true, + "augmentsExtendsReplacesDocs": false, + "implementsReplacesDocs": false, + "exemptDestructuredRootsFromChecks": false, + "tagNamePreference": {} + } + }, + "env": { + "builtin": true + }, + "globals": {}, + "ignorePatterns": [] +} \ No newline at end of file diff --git a/frameworks/solid/toolchains/oxlint/assets/_dot_prettierignore b/frameworks/solid/toolchains/oxlint/assets/_dot_prettierignore new file mode 100644 index 00000000..5322d7fe --- /dev/null +++ b/frameworks/solid/toolchains/oxlint/assets/_dot_prettierignore @@ -0,0 +1,3 @@ +package-lock.json +pnpm-lock.yaml +yarn.lock \ No newline at end of file diff --git a/frameworks/solid/toolchains/oxlint/assets/prettier.config.js b/frameworks/solid/toolchains/oxlint/assets/prettier.config.js new file mode 100644 index 00000000..aea1c480 --- /dev/null +++ b/frameworks/solid/toolchains/oxlint/assets/prettier.config.js @@ -0,0 +1,10 @@ +// @ts-check + +/** @type {import('prettier').Config} */ +const config = { + semi: false, + singleQuote: true, + trailingComma: "all", +}; + +export default config; diff --git a/frameworks/solid/toolchains/oxlint/info.json b/frameworks/solid/toolchains/oxlint/info.json new file mode 100644 index 00000000..4d65baa4 --- /dev/null +++ b/frameworks/solid/toolchains/oxlint/info.json @@ -0,0 +1,8 @@ +{ + "name": "Oxlint", + "description": "Oxlint linter + Prettier toolchain support.", + "phase": "setup", + "type": "toolchain", + "modes": ["code-router", "file-router"], + "link": "https://oxc.rs/docs/guide/usage/linter" +} diff --git a/frameworks/solid/toolchains/oxlint/package.json b/frameworks/solid/toolchains/oxlint/package.json new file mode 100644 index 00000000..3844353e --- /dev/null +++ b/frameworks/solid/toolchains/oxlint/package.json @@ -0,0 +1,11 @@ +{ + "scripts": { + "lint": "oxlint", + "format": "prettier", + "check": "prettier --write . && oxlint --fix" + }, + "devDependencies": { + "oxlint": "^1.18.0", + "prettier": "^3.5.3" + } +} diff --git a/frameworks/solid/toolchains/oxlint/small-logo.svg b/frameworks/solid/toolchains/oxlint/small-logo.svg new file mode 100644 index 00000000..fb3e2a86 --- /dev/null +++ b/frameworks/solid/toolchains/oxlint/small-logo.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/packages/cta-cli/tests/options.test.ts b/packages/cta-cli/tests/options.test.ts index 2e9f1b86..b47d5607 100644 --- a/packages/cta-cli/tests/options.test.ts +++ b/packages/cta-cli/tests/options.test.ts @@ -35,6 +35,11 @@ beforeEach(() => { type: 'toolchain', modes: ['file-router', 'code-router'], }, + { + id: 'oxlint', + type: 'toolchain', + modes: ['file-router', 'code-router'], + }, ], supportedModes: { 'code-router': { @@ -242,6 +247,19 @@ describe('promptForCreateOptions', () => { expect(options?.chosenAddOns.map((a) => a.id).sort()).toEqual(['biome']) }) + it('should select oxlint when toolchain is specified', async () => { + setBasicSpies() + + vi.spyOn(prompts, 'selectToolchain').mockImplementation(async () => 'oxlint') + + const options = await promptForCreateOptions( + { ...baseCliOptions, toolchain: 'oxlint' }, + {}, + ) + + expect(options?.chosenAddOns.map((a) => a.id).sort()).toEqual(['oxlint']) + }) + it('should handle forced add-ons', async () => { setBasicSpies() From 8bec28e41c3887a67496748a1f99e604892ca6cc Mon Sep 17 00:00:00 2001 From: Kai <4711233+kaiiiiiiiii@users.noreply.github.com> Date: Wed, 1 Oct 2025 09:20:31 +0000 Subject: [PATCH 2/2] feat: add @prettier/plugin-oxc to prettier configuration for oxlint --- .../react-cra/toolchains/oxlint/assets/prettier.config.js | 1 + frameworks/react-cra/toolchains/oxlint/package.json | 3 ++- frameworks/solid/toolchains/oxlint/assets/prettier.config.js | 1 + frameworks/solid/toolchains/oxlint/package.json | 3 ++- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/frameworks/react-cra/toolchains/oxlint/assets/prettier.config.js b/frameworks/react-cra/toolchains/oxlint/assets/prettier.config.js index aea1c480..f2860c54 100644 --- a/frameworks/react-cra/toolchains/oxlint/assets/prettier.config.js +++ b/frameworks/react-cra/toolchains/oxlint/assets/prettier.config.js @@ -5,6 +5,7 @@ const config = { semi: false, singleQuote: true, trailingComma: "all", + plugins: ["@prettier/plugin-oxc"] }; export default config; diff --git a/frameworks/react-cra/toolchains/oxlint/package.json b/frameworks/react-cra/toolchains/oxlint/package.json index 3844353e..e2abbcd8 100644 --- a/frameworks/react-cra/toolchains/oxlint/package.json +++ b/frameworks/react-cra/toolchains/oxlint/package.json @@ -6,6 +6,7 @@ }, "devDependencies": { "oxlint": "^1.18.0", - "prettier": "^3.5.3" + "prettier": "^3.5.3", + "@prettier/plugin-oxc": "^0.0.4" } } diff --git a/frameworks/solid/toolchains/oxlint/assets/prettier.config.js b/frameworks/solid/toolchains/oxlint/assets/prettier.config.js index aea1c480..f2860c54 100644 --- a/frameworks/solid/toolchains/oxlint/assets/prettier.config.js +++ b/frameworks/solid/toolchains/oxlint/assets/prettier.config.js @@ -5,6 +5,7 @@ const config = { semi: false, singleQuote: true, trailingComma: "all", + plugins: ["@prettier/plugin-oxc"] }; export default config; diff --git a/frameworks/solid/toolchains/oxlint/package.json b/frameworks/solid/toolchains/oxlint/package.json index 3844353e..e2abbcd8 100644 --- a/frameworks/solid/toolchains/oxlint/package.json +++ b/frameworks/solid/toolchains/oxlint/package.json @@ -6,6 +6,7 @@ }, "devDependencies": { "oxlint": "^1.18.0", - "prettier": "^3.5.3" + "prettier": "^3.5.3", + "@prettier/plugin-oxc": "^0.0.4" } }