From b0de546668ea85fbf6260722da199e9bf315cd9e Mon Sep 17 00:00:00 2001 From: icld Date: Wed, 26 Feb 2025 21:03:59 -0800 Subject: [PATCH] Add precommit hook --- .devcontainer/devcontainer.json | 65 +++++++ .eslintrc.js | 13 ++ .github/CODEOWNERS | 30 +++ .github/CONTRIBUTING.md | 46 +++++ .gitignore | 4 +- .npmrc | 2 + .vscode/extensions.json | 7 + .vscode/settings.json | 31 ++- apps/web/app/layout.tsx | 16 +- apps/web/app/page.tsx | 2 +- apps/web/components/providers.tsx | 6 +- apps/web/hooks/use-mobile.tsx | 6 +- apps/web/next.config.mjs | 2 +- apps/web/package.json | 9 +- apps/web/postcss.config.mjs | 2 +- apps/web/tailwind.config.ts | 2 +- biome.json | 70 ++++--- lefthook.yaml | 23 +++ lefthook.yml | 14 ++ package.json | 28 ++- pnpm-lock.yaml | 135 +++++++++++++- qwrk-laconic-migration-guide.md | 127 ++++++++++++- scripts/README.md | 36 ++++ scripts/hooks-logger.js | 81 ++++++++ services/typescript-config/react-library.json | 2 +- services/ui/package.json | 6 +- services/ui/postcss.config.mjs | 8 +- services/ui/src/components/button.tsx | 42 ++--- services/ui/src/lib/utils.ts | 4 +- services/ui/src/styles/globals.css | 2 - services/ui/tailwind.config.ts | 176 +++++++++--------- tsconfig.json | 1 - turbo.json | 29 ++- 33 files changed, 835 insertions(+), 192 deletions(-) create mode 100644 .devcontainer/devcontainer.json create mode 100644 .eslintrc.js create mode 100644 .github/CODEOWNERS create mode 100644 .github/CONTRIBUTING.md create mode 100644 .npmrc create mode 100644 .vscode/extensions.json create mode 100644 lefthook.yaml create mode 100644 lefthook.yml create mode 100644 scripts/README.md create mode 100755 scripts/hooks-logger.js diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..deffab7 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,65 @@ +{ + "name": "Laconic Core Development", + "image": "mcr.microsoft.com/devcontainers/javascript-node:0-18", + + // Add environment variables + "containerEnv": { + "NODE_ENV": "development" + }, + + // Mount your SSH keys for git authentication + "mounts": [ + "source=${localEnv:HOME}/.ssh,target=/home/node/.ssh,type=bind,readonly" + ], + + "customizations": { + "vscode": { + "extensions": [ + "biomejs.biome", + "ms-vscode.vscode-typescript-next", + "ms-azuretools.vscode-docker", + "dbaeumer.vscode-eslint", + "christian-kohler.path-intellisense", + "github.vscode-pull-request-github", + "streetsidesoftware.code-spell-checker", + "eamodio.gitlens" + ], + "settings": { + "editor.defaultFormatter": "biomejs.biome", + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.organizeImports": "explicit", + "source.fixAll": "explicit", + "source.addMissingImports.ts": "explicit", + "source.fixAll.ts": "explicit", + "source.removeUnusedImports": "explicit" + }, + // Additional helpful settings + "editor.bracketPairColorization.enabled": true, + "editor.guides.bracketPairs": true, + "terminal.integrated.defaultProfile.linux": "bash", + "javascript.updateImportsOnFileMove.enabled": "always", + "typescript.updateImportsOnFileMove.enabled": "always", + "files.exclude": { + "**/.git": true, + "**/node_modules": true, + "**/dist": true + } + } + } + }, + + // Forward common development ports + "forwardPorts": [3000, 4000, 5000, 8000], + + // Set up git configuration + "postCreateCommand": "pnpm install && git config --global pull.rebase true", + + "remoteUser": "node", + + // Features to install in the container + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers/features/git:1": {} + } +} diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..d600723 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,13 @@ +module.exports = { + root: true, + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint'], + extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], + rules: { + // Add rules that can be auto-fixed + '@typescript-eslint/no-unused-vars': 'error', + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/no-non-null-assertion': 'warn' + } +} diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..6c2dc6d --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,30 @@ +# Setting Up Contribution Guidelines with CODEOWNERS + +You can create a CODEOWNERS file to define which files require specific approval before changes can be merged. This helps protect critical files in your project. + +## Steps to implement CODEOWNERS: + +1. Create a CODEOWNERS file in either the root directory, .github directory, or docs directory +2. Define file patterns and the users/teams who own those files + +Here's how to implement it: + +# CODEOWNERS file defines who needs to approve changes to specific files +# Format: file-pattern @user-or-team + +# Dev container configuration +.devcontainer/* @your-username + +# Core configuration files +.vscode/* @your-username +*.json @your-username + +# Critical application files that need review +/src/core/* @your-username @another-team-member +/services/api/* @api-team-name + +# Documentation changes can be reviewed by docs team +/docs/* @docs-team-or-username + +# Default owners for everything else +* @default-team-or-username diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..43d6094 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,46 @@ +# Contributing to Laconic Core + +Thank you for considering contributing to our project! Here are some guidelines to help you get started. + +## Development Environment + +This project uses dev containers to ensure consistent development environments. To get started: + +1. Install [Docker](https://www.docker.com/products/docker-desktop) and [VS Code](https://code.visualstudio.com/) +2. Install the [Remote - Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension +3. Clone the repository and open it in VS Code +4. Click the green button in the bottom-left corner and select "Reopen in Container" + +## Protected Files + +Some files in this repository are protected and require specific approval before changes can be merged: + +- `.devcontainer/*` - Dev container configuration +- `.vscode/*` - VS Code workspace settings +- `core configuration files` - Project configuration files +- `critical application files` - Core functionality + +Please discuss any changes to these files with the maintainers before submitting pull requests. + +## Code Style + +This project uses Biome for formatting and linting. The dev container will automatically configure your editor to use the correct settings. + +## Submitting Changes + +1. Fork the repository +2. Create a new branch for your changes +3. Make your changes following the code style guidelines +4. Write tests for your changes +5. Submit a pull request + +## Pull Request Process + +1. Update the README.md with details of changes if applicable +2. The version numbers will be updated by maintainers following semantic versioning +3. Pull requests require approval from at least one maintainer +4. Once approved, maintainers will merge the PR + +## Questions? + +If you have questions, please open an issue or contact the maintainers. diff --git a/.gitignore b/.gitignore index 49cebd0..522f4d4 100644 --- a/.gitignore +++ b/.gitignore @@ -69,4 +69,6 @@ logs .Spotlight-V100 .Trashes ehthumbs.db -Thumbs.db \ No newline at end of file +Thumbs.db + +.pnpm-store diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..347ae0d --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +legacy-peer-deps=true +strict-peer-dependencies=false \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..866eb68 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "biomejs.biome", + "ms-vscode-remote.remote-containers", + "ms-typescript.vscode-typescript-next" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index fedfb4e..e7f470a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,30 @@ { - "editor.defaultFormatter": "biomejs.biome" -} \ No newline at end of file + // This file can be empty since all settings are in devcontainer.json + "typescript.tsdk": "node_modules/typescript/lib", + "typescript.enablePromptUseWorkspaceTsdk": true, + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll": true, + "source.organizeImports": true + }, + "editor.defaultFormatter": "biomejs.biome", + "[typescript]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[typescriptreact]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[javascript]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[javascriptreact]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[json]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "typescript.validate.enable": true, + "javascript.validate.enable": true, + "typescript.reportStyleChecksAsWarnings": true, + "typescript.surveys.enabled": false +} diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx index 7a807d4..83476dc 100644 --- a/apps/web/app/layout.tsx +++ b/apps/web/app/layout.tsx @@ -1,20 +1,20 @@ -import { Geist, Geist_Mono } from "next/font/google" +import '@workspace/ui/globals.css' -import "@workspace/ui/globals.css" -import { Providers } from "@/components/providers" +import { Providers } from '@/components/providers' +import { Geist, Geist_Mono } from 'next/font/google' const fontSans = Geist({ - subsets: ["latin"], - variable: "--font-sans", + subsets: ['latin'], + variable: '--font-sans' }) const fontMono = Geist_Mono({ - subsets: ["latin"], - variable: "--font-mono", + subsets: ['latin'], + variable: '--font-mono' }) export default function RootLayout({ - children, + children }: Readonly<{ children: React.ReactNode }>) { diff --git a/apps/web/app/page.tsx b/apps/web/app/page.tsx index e4f893a..078960f 100644 --- a/apps/web/app/page.tsx +++ b/apps/web/app/page.tsx @@ -1,4 +1,4 @@ -import { Button } from "@workspace/ui/components/button" +import { Button } from '@workspace/ui/components/button' export default function Page() { return ( diff --git a/apps/web/components/providers.tsx b/apps/web/components/providers.tsx index 25e8677..a78ecb5 100644 --- a/apps/web/components/providers.tsx +++ b/apps/web/components/providers.tsx @@ -1,7 +1,7 @@ -"use client" +'use client' -import * as React from "react" -import { ThemeProvider as NextThemesProvider } from "next-themes" +import { ThemeProvider as NextThemesProvider } from 'next-themes' +import type * as React from 'react' export function Providers({ children }: { children: React.ReactNode }) { return ( diff --git a/apps/web/hooks/use-mobile.tsx b/apps/web/hooks/use-mobile.tsx index 2b0fe1d..4331d5c 100644 --- a/apps/web/hooks/use-mobile.tsx +++ b/apps/web/hooks/use-mobile.tsx @@ -1,4 +1,4 @@ -import * as React from "react" +import * as React from 'react' const MOBILE_BREAKPOINT = 768 @@ -10,9 +10,9 @@ export function useIsMobile() { const onChange = () => { setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) } - mql.addEventListener("change", onChange) + mql.addEventListener('change', onChange) setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) - return () => mql.removeEventListener("change", onChange) + return () => mql.removeEventListener('change', onChange) }, []) return !!isMobile diff --git a/apps/web/next.config.mjs b/apps/web/next.config.mjs index bd167d9..05584cb 100644 --- a/apps/web/next.config.mjs +++ b/apps/web/next.config.mjs @@ -1,6 +1,6 @@ /** @type {import('next').NextConfig} */ const nextConfig = { - transpilePackages: ["@workspace/ui"], + transpilePackages: ['@workspace/ui'] } export default nextConfig diff --git a/apps/web/package.json b/apps/web/package.json index 5fff7e1..9f29a4b 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -7,9 +7,16 @@ "dev": "next dev --turbopack", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "biome check .", + "lint:fix": "biome check --apply .", + "format": "biome format .", + "format:fix": "biome format --write .", + "check-types": "tsc --noEmit", + "fix-types": "tsc --noEmit --pretty --incremental" }, "dependencies": { + "@biomejs/biome": "^1.9.4", + "@biomejs/monorepo": "github:biomejs/biome", "@hookform/resolvers": "^4.1.2", "@radix-ui/react-accordion": "^1.2.3", "@radix-ui/react-alert-dialog": "^1.1.6", diff --git a/apps/web/postcss.config.mjs b/apps/web/postcss.config.mjs index 535dec4..5f90e69 100644 --- a/apps/web/postcss.config.mjs +++ b/apps/web/postcss.config.mjs @@ -1 +1 @@ -export { default } from "@workspace/ui/postcss.config"; \ No newline at end of file +export { default } from '@workspace/ui/postcss.config' diff --git a/apps/web/tailwind.config.ts b/apps/web/tailwind.config.ts index f119228..7dc697b 100644 --- a/apps/web/tailwind.config.ts +++ b/apps/web/tailwind.config.ts @@ -1 +1 @@ -export * from "@workspace/ui/tailwind.config"; \ No newline at end of file +export * from '@workspace/ui/tailwind.config' diff --git a/biome.json b/biome.json index 09c3e44..e6cba48 100644 --- a/biome.json +++ b/biome.json @@ -1,33 +1,41 @@ { - "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", - "vcs": { - "enabled": false, - "clientKind": "git", - "useIgnoreFile": false - }, - "files": { - "ignoreUnknown": false, - "ignore": [] - }, - "formatter": { - "enabled": true, - "indentStyle": "space", - "indentWidth": 2, - "lineWidth": 80 - }, - "organizeImports": { - "enabled": true - }, - "linter": { - "enabled": true, - "rules": { - "recommended": true - } - }, - "javascript": { - "formatter": { - "quoteStyle": "single", - "trailingCommas": "none" - } - } + "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "vcs": { + "enabled": false, + "clientKind": "git", + "useIgnoreFile": false + }, + "files": { + "ignoreUnknown": false, + "ignore": ["node_modules", "dist", "build"] + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 2, + "lineWidth": 80 + }, + "organizeImports": { + "enabled": true + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + }, + "javascript": { + "formatter": { + "enabled": true, + "quoteStyle": "single", + "trailingCommas": "none", + "semicolons": "asNeeded" + } + }, + "json": { + "formatter": { + "enabled": true, + "trailingCommas": "none" + } + } } diff --git a/lefthook.yaml b/lefthook.yaml new file mode 100644 index 0000000..7624dd8 --- /dev/null +++ b/lefthook.yaml @@ -0,0 +1,23 @@ +pre-commit: + parallel: true + commands: + lint: + glob: "*.{js,ts,jsx,tsx}" + run: pnpm lint:fix {staged_files} + stage_fixed: true + format: + glob: "*.{js,ts,jsx,tsx}" + run: pnpm format:fix {staged_files} + stage_fixed: true + typecheck: + glob: "*.{ts,tsx}" + run: pnpm check-types + # TypeScript requires checking the whole project context + # We can't easily check only staged files while maintaining type relationships + +# Add a manual hook that can be run with `npx lefthook run fix-all` +fix-all: + commands: + fix-code: + glob: "*.{js,ts,jsx,tsx}" + run: pnpm fix-all \ No newline at end of file diff --git a/lefthook.yml b/lefthook.yml new file mode 100644 index 0000000..b2f1798 --- /dev/null +++ b/lefthook.yml @@ -0,0 +1,14 @@ +pre-commit: + commands: + check: + glob: "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}" + # run: npx @biomejs/biome check --write --no-errors-on-unmatched --files-ignore-unknown=true --colors=off {staged_files} + run: pnpm biome format --write {staged_files} + stage_fixed: true + +pre-push: + parallel: true + commands: + check: + glob: "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}" + run: npx @biomejs/biome check --no-errors-on-unmatched --files-ignore-unknown=true --colors=off {push_files} \ No newline at end of file diff --git a/package.json b/package.json index ad9760e..01dfef7 100644 --- a/package.json +++ b/package.json @@ -1,25 +1,35 @@ { "name": "qwrk-laconic-core", "version": "1.0.0", - "description": "", + "description": "Monorepo for Laconic frontend codebases", "main": "index.js", "scripts": { "build": "turbo build", "dev": "turbo dev", "lint": "turbo lint", - "lint:fix": "biome lint --write", - "test": "echo \"Error: no test specified\" && exit 1" + "lint:fix": "turbo lint:fix", + "format": "turbo format", + "format:fix": "turbo format:fix", + "check-types": "turbo check-types", + "fix-types": "turbo fix-types", + "validate": "turbo lint check-types format", + "fix-all": "turbo lint:fix fix-types format:fix", + "test": "echo \"Error: no test specified\" && exit 1", + "test:hooks": "lefthook run pre-commit" }, "keywords": [], - "author": "", + "author": "QWRK", "license": "ISC", - "packageManager": "pnpm@10.5.1", "devDependencies": { - "turbo": "^2.4.4", - "@workspace/typescript-config": "workspace:*", "@biomejs/biome": "^1.9.4", + "@workspace/typescript-config": "workspace:*", + "chalk": "5", + "lefthook": "^1.11.2", + "turbo": "^2.4.4", "typescript": "^5.7.3" + }, + "packageManager": "pnpm@10.5.1", + "engines": { + "node": ">=22.14.0" } - - } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b509ec4..cab8d74 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,12 @@ importers: '@workspace/typescript-config': specifier: workspace:* version: link:services/typescript-config + chalk: + specifier: '5' + version: 5.4.1 + lefthook: + specifier: ^1.11.2 + version: 1.11.2 turbo: specifier: ^2.4.4 version: 2.4.4 @@ -23,6 +29,12 @@ importers: apps/web: dependencies: + '@biomejs/biome': + specifier: ^1.9.4 + version: 1.9.4 + '@biomejs/monorepo': + specifier: github:biomejs/biome + version: https://codeload.github.com/biomejs/biome/tar.gz/d95df40a86c8debb369fdc9070c91642325bfe1f '@hookform/resolvers': specifier: ^4.1.2 version: 4.1.2(react-hook-form@7.54.2(react@19.0.0)) @@ -185,6 +197,12 @@ importers: services/ui: dependencies: + '@biomejs/biome': + specifier: ^1.9.4 + version: 1.9.4 + '@biomejs/monorepo': + specifier: github:biomejs/biome + version: https://codeload.github.com/biomejs/biome/tar.gz/d95df40a86c8debb369fdc9070c91642325bfe1f '@radix-ui/react-slot': specifier: ^1.1.1 version: 1.1.2(@types/react@18.3.0)(react@19.0.0) @@ -307,6 +325,10 @@ packages: cpu: [x64] os: [win32] + '@biomejs/monorepo@https://codeload.github.com/biomejs/biome/tar.gz/d95df40a86c8debb369fdc9070c91642325bfe1f': + resolution: {tarball: https://codeload.github.com/biomejs/biome/tar.gz/d95df40a86c8debb369fdc9070c91642325bfe1f} + version: 0.0.0 + '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} @@ -1468,6 +1490,10 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chalk@5.4.1: + resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + change-case@3.1.0: resolution: {integrity: sha512-2AZp7uJZbYEzRPsFoa+ijKdvp9zsrnnt6+yFokfwEpeJm0xuJDVoxiRCAaTzyJND8GJkofo2IcKWaUZ/OECVzw==} @@ -1652,8 +1678,8 @@ packages: dot-case@2.1.1: resolution: {integrity: sha512-HnM6ZlFqcajLsyudHq7LeeLDr2rFAVYtDv/hV5qchQEidSck8j9OPUsXY9KwJv/lHMtYlX4DjRQqwFYa+0r8Ug==} - electron-to-chromium@1.5.106: - resolution: {integrity: sha512-12keJGdXQWPnfVOu6/6ZzZgPPNodiDOSe3LjA8qk2yXTjnCnw2LeGUsAmtlNAmH4UW0K7tOLcz0j9lI2eJCJRA==} + electron-to-chromium@1.5.107: + resolution: {integrity: sha512-dJr1o6yCntRkXElnhsHh1bAV19bo/hKyFf7tCcWgpXbuFIF0Lakjgqv5LRfSDaNzAII8Fnxg2tqgHkgCvxdbxw==} embla-carousel-react@8.5.2: resolution: {integrity: sha512-Tmx+uY3MqseIGdwp0ScyUuxpBgx5jX1f7od4Cm5mDwg/dptEiTKf9xp6tw0lZN2VA9JbnVMl/aikmbc53c6QFA==} @@ -1919,6 +1945,60 @@ packages: jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + lefthook-darwin-arm64@1.11.2: + resolution: {integrity: sha512-8DpvrybtWdt6UmfZk+hA8daYXr6zkpJVogZ8M49BQx6ISSKUaC03xzO1m4MrAsoKok77ka4JAidYhOa2gCu15A==} + cpu: [arm64] + os: [darwin] + + lefthook-darwin-x64@1.11.2: + resolution: {integrity: sha512-DrL1SOT8lJksjudRu6fTZTp3M0EbpCP2RQ22MDT71clS8BMrFL8x3h9Ziw+uNH76j9zA241tW5zMxWMSv+foAA==} + cpu: [x64] + os: [darwin] + + lefthook-freebsd-arm64@1.11.2: + resolution: {integrity: sha512-AliG4Wi8BNC27hCSnuFBeUXh/eA3fppnUbQQPISy/G94yfwRkzyml9MZzvb7HKmUpw1LT0sq9RQ6FQPxBZ2DYA==} + cpu: [arm64] + os: [freebsd] + + lefthook-freebsd-x64@1.11.2: + resolution: {integrity: sha512-V6cgRCoi5+jcq6XBIdRYraeEOK1UhBrtL/XZlNypAIkhPoBtfTP9u2wSprGMDzZvJCRriLXZxV/d0v94laKXzA==} + cpu: [x64] + os: [freebsd] + + lefthook-linux-arm64@1.11.2: + resolution: {integrity: sha512-VKcK7sjIK8UpXX/qK6Fxa0Lnwr4gzRtlXDS17jzxThcyFk8iGBpQ+9ZnPLv2yAaEIzmGhJUG9sDgOb9IQ5kpBQ==} + cpu: [arm64] + os: [linux] + + lefthook-linux-x64@1.11.2: + resolution: {integrity: sha512-aGa2Krph14YwSW7KF0PrlCBK9P7V/Z4oFklonmz3r2Fjm8EdhA750y7OQvA9KerXRleIb5SaUH/cz1azG/izeQ==} + cpu: [x64] + os: [linux] + + lefthook-openbsd-arm64@1.11.2: + resolution: {integrity: sha512-f7owNQ9Ki6Y07KBgdXdH28EYO0eBdZuGTpIggMeHNhYFVDavxuINP2BjmbXtzpUu8K5BX6exGx0umtWhRhXbvQ==} + cpu: [arm64] + os: [openbsd] + + lefthook-openbsd-x64@1.11.2: + resolution: {integrity: sha512-HKv6PV64vOjqPrlxAqo07N9+Z34jdPDBfeExqi0ldR7vACFaBJFIdhWCLLP+3uQUrNKc8GXlikqplZn8MgRSQw==} + cpu: [x64] + os: [openbsd] + + lefthook-windows-arm64@1.11.2: + resolution: {integrity: sha512-042jCKZ/H+lS6XYoMIf2FWMP2hxXqfAT52UW6lYObIOvQ5xu/epUXFjtmXRyYxCv57No3JYYMg1Yr06xdzTKkQ==} + cpu: [arm64] + os: [win32] + + lefthook-windows-x64@1.11.2: + resolution: {integrity: sha512-1Map6Ck2AyfY6ptN9T19N41HFKFqRTzmILtGaRGJABEzHiE4+gSWcq5YT1R6cCtkVlewD3Lx+J/80D/Kb/cVtw==} + cpu: [x64] + os: [win32] + + lefthook@1.11.2: + resolution: {integrity: sha512-/5royc/WbL2KTfFJ54wEdvxUZOBXwc54v/fW2Bz4LMOkAA3LWIxnoUiybSiauu+nhdTG98qERxH1YHwF2wZlAA==} + hasBin: true + lodash.get@4.4.2: resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} deprecated: This package is deprecated. Use the optional chaining (?.) operator instead. @@ -2650,6 +2730,8 @@ snapshots: '@biomejs/cli-win32-x64@1.9.4': optional: true + '@biomejs/monorepo@https://codeload.github.com/biomejs/biome/tar.gz/d95df40a86c8debb369fdc9070c91642325bfe1f': {} + '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 @@ -3783,7 +3865,7 @@ snapshots: browserslist@4.24.4: dependencies: caniuse-lite: 1.0.30001701 - electron-to-chromium: 1.5.106 + electron-to-chromium: 1.5.107 node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.24.4) @@ -3819,6 +3901,8 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + chalk@5.4.1: {} + change-case@3.1.0: dependencies: camel-case: 3.0.0 @@ -4008,7 +4092,7 @@ snapshots: dependencies: no-case: 2.3.2 - electron-to-chromium@1.5.106: {} + electron-to-chromium@1.5.107: {} embla-carousel-react@8.5.2(react@19.0.0): dependencies: @@ -4295,6 +4379,49 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 + lefthook-darwin-arm64@1.11.2: + optional: true + + lefthook-darwin-x64@1.11.2: + optional: true + + lefthook-freebsd-arm64@1.11.2: + optional: true + + lefthook-freebsd-x64@1.11.2: + optional: true + + lefthook-linux-arm64@1.11.2: + optional: true + + lefthook-linux-x64@1.11.2: + optional: true + + lefthook-openbsd-arm64@1.11.2: + optional: true + + lefthook-openbsd-x64@1.11.2: + optional: true + + lefthook-windows-arm64@1.11.2: + optional: true + + lefthook-windows-x64@1.11.2: + optional: true + + lefthook@1.11.2: + optionalDependencies: + lefthook-darwin-arm64: 1.11.2 + lefthook-darwin-x64: 1.11.2 + lefthook-freebsd-arm64: 1.11.2 + lefthook-freebsd-x64: 1.11.2 + lefthook-linux-arm64: 1.11.2 + lefthook-linux-x64: 1.11.2 + lefthook-openbsd-arm64: 1.11.2 + lefthook-openbsd-x64: 1.11.2 + lefthook-windows-arm64: 1.11.2 + lefthook-windows-x64: 1.11.2 + lodash.get@4.4.2: {} lodash@4.17.21: {} diff --git a/qwrk-laconic-migration-guide.md b/qwrk-laconic-migration-guide.md index 741d0a6..95ac0c9 100644 --- a/qwrk-laconic-migration-guide.md +++ b/qwrk-laconic-migration-guide.md @@ -1,5 +1,42 @@ # QWRK-Laconic Turborepo Migration Technical Specification +## Implementation Starting Points + +This migration specification supports multiple entry points depending on the current state of your repository: + +### Scenario 1: New Repository Implementation +- Follow all steps sequentially starting from "Repository Initialization" +- Execute all setup commands to build the complete architecture from scratch + +### Scenario 2: Existing Repository Conversion +If the repository already exists but requires Turborepo integration: +1. Preserve existing package structure and Git history +2. Add Turborepo configuration (`turbo.json`, `pnpm-workspace.yaml`) +3. Adapt existing packages to the recommended structure +4. Integrate shared package dependencies +5. Skip initialization steps that would conflict with existing setup + +### Scenario 3: Partial Turborepo Implementation +For repositories with partial Turborepo architecture: +1. Audit existing configuration against this specification +2. Upgrade task definitions to latest syntax (`tasks` vs legacy `pipeline`) +3. Apply missing architectural components +4. Align package structure with recommended patterns +5. Integrate modular services approach + +### Prerequisite Validation +Run the following diagnostic commands to determine your starting point: +```bash +# Check for existing Turborepo configuration +[ -f turbo.json ] && echo "Existing turbo.json found, requires update" || echo "New turbo.json needed" + +# Verify package manager +command -v pnpm >/dev/null 2>&1 && echo "pnpm installed" || echo "pnpm installation required" + +# Check Next.js applications +find . -path "*/package.json" -exec grep -l "next" {} \; | xargs -I{} dirname {} +``` + ## Architecture Overview ```mermaid @@ -84,6 +121,7 @@ qwrk-laconic-mono/ ### 1. Repository Initialization +#### New Repository Approach ```bash # Initialize Turborepo with pnpm pnpm dlx create-turbo@latest qwrk-laconic-mono --package-manager=pnpm @@ -93,6 +131,23 @@ cd qwrk-laconic-mono rm -rf apps/docs apps/web ``` +#### Existing Repository Approach +```bash +# If repository already exists and initialized: +git clone qwrk-laconic-mono +cd qwrk-laconic-mono + +# Create workspace structure if not exists +mkdir -p apps packages + +# Save existing structure (optional) +find . -maxdepth 2 -type d -not -path "*/\.*" -not -path "./node_modules" \ + -not -path "./apps" -not -path "./packages" > existing_directories.txt + +# Create migration branch +git checkout -b feature/turborepo-migration +``` + ### 2. Configure Package Manager ```bash @@ -940,6 +995,76 @@ flowchart TD - Create project management features - Implement deployment functionality +## Repository Structural Migration + +For existing repositories that require Turborepo conversion, follow this structural migration approach: + +```mermaid +flowchart TB + subgraph "Initial State" + A[Existing Repository] + B[Frontend Application] + C[Backend Services] + D[Shared Libraries] + end + + subgraph "Migration Process" + E[Create Migration Branch] + F[Add Turborepo Config] + G[Restructure Packages] + H[Refactor Dependencies] + I[Implement Build System] + end + + subgraph "Final State" + J[apps/laconic-web] + K[apps/laconic-deploy] + L[apps/docs] + M[packages/ui] + N[packages/utils] + O[packages/services] + end + + A --> E + E --> F + F --> G + G --> H + H --> I + I --> J & K & L & M & N & O +``` + +### Repository Structure Analysis + +Before migration, analyze the existing code structure: + +```bash +# Identify package dependencies +find . -name "package.json" -not -path "*/node_modules/*" -exec jq -r '.dependencies | keys[]' {} \; | sort | uniq -c | sort -nr + +# Identify file distribution +find . -type f -name "*.ts*" | grep -v "node_modules" | grep -v ".turbo" | grep -v "dist" | wc -l + +# Analyze potential shared components +find . -type f -name "*.tsx" -not -path "*/node_modules/*" | xargs grep -l "export" | sort +``` + +### Incremental Migration Strategy + +1. **Coexistence Phase** + - Implement Turborepo alongside existing structure + - Gradually move components to new architecture + - Maintain backward compatibility during transition + +2. **Dual Build System** + - Configure builds for both legacy and new structure + - Implement feature flags for incremental adoption + - Monitor performance metrics across both systems + +3. **Final Migration** + - Complete transition to Turborepo architecture + - Remove legacy configuration + - Optimize build pipeline for new structure + ## Best Practices and Guidelines ### TypeScript Configuration @@ -1045,4 +1170,4 @@ jobs: This technical specification provides a comprehensive guide for migrating the qwrk-laconic repository to a modern Turborepo structure with Next.js 15. By following this guide, you can create a modular, maintainable monorepo that leverages the latest technologies and best practices for web development. -The migration approach prioritizes incremental adoption, allowing for gradual transition while maintaining backward compatibility with existing systems. +The migration approach prioritizes incremental adoption, allowing for gradual transition while maintaining backward compatibility with existing systems. \ No newline at end of file diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..03cf128 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,36 @@ +# Scripts and Hooks + +This directory contains utility scripts for the project. + +## Lefthook Configuration + +The project uses [Lefthook](https://github.com/evilmartians/lefthook) for git hooks to ensure code quality before commits. + +### Pre-commit Hooks + +The pre-commit hooks run: + +1. **Linting** - Checks and fixes code style issues +2. **Formatting** - Ensures consistent code formatting +3. **Type Checking** - Verifies TypeScript types + +These hooks are configured in `lefthook.yaml` in the root directory. + +### Usage + +The hooks run automatically when you commit code. You can also run them manually: + +```bash +# Run all pre-commit hooks +pnpm test:hooks + +# Run individual commands +pnpm lint:fix +pnpm format:fix +pnpm check-types +pnpm fix-all +``` + +## VS Code Integration + +TypeScript errors will show up directly in VS Code thanks to the configuration in `.vscode/settings.json`. \ No newline at end of file diff --git a/scripts/hooks-logger.js b/scripts/hooks-logger.js new file mode 100755 index 0000000..9365392 --- /dev/null +++ b/scripts/hooks-logger.js @@ -0,0 +1,81 @@ +#!/usr/bin/env node + +import chalk from 'chalk' + +const command = process.argv[2] +const files = process.argv.slice(3) + +// Format the command name for display +const formatCommand = (cmd) => { + switch (cmd) { + case 'lint:fix': + return chalk.blue.bold('LINTING') + case 'format:fix': + return chalk.magenta.bold('FORMATTING') + case 'check-types': + return chalk.yellow.bold('TYPE CHECKING') + case 'fix-all': + return chalk.green.bold('FIXING ALL ISSUES') + default: + return chalk.white.bold(cmd.toUpperCase()) + } +} + +// Display a header for the command +console.log( + '\n' + + chalk.gray( + '╔═════════════════════════════════════════════════════════════════════════════╗' + ) +) +console.log( + chalk.gray('║ ') + + chalk.white.bold(`LEFTHOOK: ${formatCommand(command)}`) + + chalk.gray(' ║') +) +console.log( + chalk.gray( + '╚═════════════════════════════════════════════════════════════════════════════╝\n' + ) +) + +// If we have files, display them +if (files.length > 0) { + console.log(chalk.gray('Files being processed:')) + for (const file of files) { + console.log(chalk.cyan(` → ${file}`)) + } + console.log('') +} + +// Execute the original command +const { execSync } = await import('node:child_process') +try { + // Construct the command based on what was passed + let fullCommand + if (files.length > 0 && command !== 'check-types') { + // For commands that support specific files + fullCommand = `pnpm ${command} ${files.join(' ')}` + } else { + // For commands that run on the whole project + fullCommand = `pnpm ${command}` + } + + // Execute the command + execSync(fullCommand, { stdio: 'inherit' }) + + // Show success message + console.log( + '\n' + + chalk.green.bold('✓ SUCCESS') + + chalk.green(` ${formatCommand(command)} completed successfully`) + ) +} catch (error) { + // Show error message + console.log( + '\n' + + chalk.red.bold('✗ ERROR') + + chalk.red(` ${formatCommand(command)} failed`) + ) + process.exit(1) +} diff --git a/services/typescript-config/react-library.json b/services/typescript-config/react-library.json index a755ffe..44924d9 100644 --- a/services/typescript-config/react-library.json +++ b/services/typescript-config/react-library.json @@ -3,6 +3,6 @@ "display": "React Library", "extends": "./base.json", "compilerOptions": { - "jsx": "react-jsx", + "jsx": "react-jsx" } } diff --git a/services/ui/package.json b/services/ui/package.json index f38fbc0..ec9a066 100644 --- a/services/ui/package.json +++ b/services/ui/package.json @@ -3,8 +3,12 @@ "version": "0.0.0", "type": "module", "private": true, - "scripts": {}, + "scripts": { + "lint": "biome format --write" + }, "dependencies": { + "@biomejs/biome": "^1.9.4", + "@biomejs/monorepo": "github:biomejs/biome", "@radix-ui/react-slot": "^1.1.1", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", diff --git a/services/ui/postcss.config.mjs b/services/ui/postcss.config.mjs index 0c2a10b..764f5bd 100644 --- a/services/ui/postcss.config.mjs +++ b/services/ui/postcss.config.mjs @@ -2,8 +2,8 @@ const config = { plugins: { tailwindcss: {}, - autoprefixer: {}, - }, -}; + autoprefixer: {} + } +} -export default config; \ No newline at end of file +export default config diff --git a/services/ui/src/components/button.tsx b/services/ui/src/components/button.tsx index 0e0d1d0..85b3597 100644 --- a/services/ui/src/components/button.tsx +++ b/services/ui/src/components/button.tsx @@ -1,35 +1,35 @@ -import * as React from "react" -import { Slot } from "@radix-ui/react-slot" -import { cva, type VariantProps } from "class-variance-authority" +import { Slot } from '@radix-ui/react-slot' +import { type VariantProps, cva } from 'class-variance-authority' +import * as React from 'react' -import { cn } from "@workspace/ui/lib/utils" +import { cn } from '@workspace/ui/lib/utils' const buttonVariants = cva( - "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", + 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0', { variants: { variant: { - default: "bg-primary text-primary-foreground hover:bg-primary/90", + default: 'bg-primary text-primary-foreground hover:bg-primary/90', destructive: - "bg-destructive text-destructive-foreground hover:bg-destructive/90", + 'bg-destructive text-destructive-foreground hover:bg-destructive/90', outline: - "border border-input bg-background hover:bg-accent hover:text-accent-foreground", + 'border border-input bg-background hover:bg-accent hover:text-accent-foreground', secondary: - "bg-secondary text-secondary-foreground hover:bg-secondary/80", - ghost: "hover:bg-accent hover:text-accent-foreground", - link: "text-primary underline-offset-4 hover:underline", + 'bg-secondary text-secondary-foreground hover:bg-secondary/80', + ghost: 'hover:bg-accent hover:text-accent-foreground', + link: 'text-primary underline-offset-4 hover:underline' }, size: { - default: "h-10 px-4 py-2", - sm: "h-9 rounded-md px-3", - lg: "h-11 rounded-md px-8", - icon: "h-10 w-10", - }, + default: 'h-10 px-4 py-2', + sm: 'h-9 rounded-md px-3', + lg: 'h-11 rounded-md px-8', + icon: 'h-10 w-10' + } }, defaultVariants: { - variant: "default", - size: "default", - }, + variant: 'default', + size: 'default' + } } ) @@ -41,7 +41,7 @@ export interface ButtonProps const Button = React.forwardRef( ({ className, variant, size, asChild = false, ...props }, ref) => { - const Comp = asChild ? Slot : "button" + const Comp = asChild ? Slot : 'button' return ( ( ) } ) -Button.displayName = "Button" +Button.displayName = 'Button' export { Button, buttonVariants } diff --git a/services/ui/src/lib/utils.ts b/services/ui/src/lib/utils.ts index bd0c391..d32b0fe 100644 --- a/services/ui/src/lib/utils.ts +++ b/services/ui/src/lib/utils.ts @@ -1,5 +1,5 @@ -import { clsx, type ClassValue } from "clsx" -import { twMerge } from "tailwind-merge" +import { type ClassValue, clsx } from 'clsx' +import { twMerge } from 'tailwind-merge' export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) diff --git a/services/ui/src/styles/globals.css b/services/ui/src/styles/globals.css index 8bfaaf3..05a646b 100644 --- a/services/ui/src/styles/globals.css +++ b/services/ui/src/styles/globals.css @@ -83,8 +83,6 @@ } } - - @layer base { * { @apply border-border outline-ring/50; diff --git a/services/ui/tailwind.config.ts b/services/ui/tailwind.config.ts index 99ab987..8f0ab24 100644 --- a/services/ui/tailwind.config.ts +++ b/services/ui/tailwind.config.ts @@ -1,100 +1,94 @@ -import type { Config } from "tailwindcss" -import defaultTheme from "tailwindcss" -import tailwindcssAnimate from "tailwindcss-animate" +import type { Config } from 'tailwindcss' +import defaultTheme from 'tailwindcss' +import tailwindcssAnimate from 'tailwindcss-animate' const config = { // darkMode: ["class"], content: [ - "app/**/*.{ts,tsx}", - "components/**/*.{ts,tsx}", - "../../services/ui/src/components/**/*.{ts,tsx}", + 'app/**/*.{ts,tsx}', + 'components/**/*.{ts,tsx}', + '../../services/ui/src/components/**/*.{ts,tsx}' ], theme: { - extend: { - fontFamily: { - sans: [ - 'var(--font-sans)', - ...defaultTheme.fontFamily.sans - ], - mono: [ - 'var(--font-mono)', - ...defaultTheme.fontFamily.mono - ] - }, - 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))' - }, - sidebar: { - DEFAULT: 'hsl(var(--sidebar-background))', - foreground: 'hsl(var(--sidebar-foreground))', - primary: 'hsl(var(--sidebar-primary))', - 'primary-foreground': 'hsl(var(--sidebar-primary-foreground))', - accent: 'hsl(var(--sidebar-accent))', - 'accent-foreground': 'hsl(var(--sidebar-accent-foreground))', - border: 'hsl(var(--sidebar-border))', - ring: 'hsl(var(--sidebar-ring))' - } - }, - 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' - } - } + extend: { + fontFamily: { + sans: ['var(--font-sans)', ...defaultTheme.fontFamily.sans], + mono: ['var(--font-mono)', ...defaultTheme.fontFamily.mono] + }, + 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))' + }, + sidebar: { + DEFAULT: 'hsl(var(--sidebar-background))', + foreground: 'hsl(var(--sidebar-foreground))', + primary: 'hsl(var(--sidebar-primary))', + 'primary-foreground': 'hsl(var(--sidebar-primary-foreground))', + accent: 'hsl(var(--sidebar-accent))', + 'accent-foreground': 'hsl(var(--sidebar-accent-foreground))', + border: 'hsl(var(--sidebar-border))', + ring: 'hsl(var(--sidebar-ring))' + } + }, + 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: [tailwindcssAnimate], + plugins: [tailwindcssAnimate] } satisfies Config export default config diff --git a/tsconfig.json b/tsconfig.json index c6a4ad5..f094c33 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,4 +1,3 @@ { "extends": "@workspace/typescript-config/base.json" } - diff --git a/turbo.json b/turbo.json index df4a794..c7c0793 100644 --- a/turbo.json +++ b/turbo.json @@ -2,15 +2,40 @@ "$schema": "https://turbo.build/schema.json", "tasks": { "build": { + "inputs": ["$TURBO_DEFAULT$", ".env*"], "dependsOn": ["^build"], "outputs": [".next/**", "!.next/cache/**"] }, "check-types": { - "dependsOn": ["^check-types"] + "dependsOn": ["^build"], + "outputs": [] + }, + "fix-types": { + "dependsOn": ["^build"], + "outputs": [] + }, + "format": { + "dependsOn": ["^build"], + "outputs": [] + }, + "format:fix": { + "dependsOn": ["^build"], + "outputs": [] + }, + "test": { + "outputs": ["coverage/**"], + "dependsOn": [] + }, + "lint": { + "dependsOn": ["^build"] + }, + "lint:fix": { + "dependsOn": ["^build"] }, "dev": { + "dependsOn": ["^build"], "persistent": true, "cache": false } } -} \ No newline at end of file +}