From b4c3f6ace16bdc00b288163b84d9c2e36390aeea Mon Sep 17 00:00:00 2001 From: aidansunbury Date: Fri, 25 Oct 2024 23:08:36 -0700 Subject: [PATCH 01/25] docs: added appRouter CLI flag to docs --- www/src/pages/en/installation.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/www/src/pages/en/installation.mdx b/www/src/pages/en/installation.mdx index 6b520aff59..34d183f1a5 100644 --- a/www/src/pages/en/installation.mdx +++ b/www/src/pages/en/installation.mdx @@ -58,6 +58,7 @@ For our CI, we have some experimental flags that allow you to scaffold any app w | `--nextAuth` | Include NextAuth.js in the project | | `--tailwind` | Include Tailwind CSS in the project | | `--dbProvider [provider]` | Include a configured database in the project | +| `--appRouter` | Use Next.js App Router in the project | If you don't provide the `CI` flag, the rest of these flags have no effect. From e1dfc8508fcee14e9c52c2f7e3278adf53dd8f95 Mon Sep 17 00:00:00 2001 From: aidansunbury Date: Sat, 9 Nov 2024 15:03:43 -0800 Subject: [PATCH 02/25] initial comments on edit locations --- cli/src/cli/index.ts | 1 + cli/src/installers/index.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/cli/src/cli/index.ts b/cli/src/cli/index.ts index ce5ef6ca50..9b42d69795 100644 --- a/cli/src/cli/index.ts +++ b/cli/src/cli/index.ts @@ -140,6 +140,7 @@ export const runCli = async (): Promise => { )}`, defaultOptions.flags.dbProvider ) + //* Add eslint / biome options .option( "--appRouter [boolean]", "Explicitly tell the CLI to use the new Next.js app router", diff --git a/cli/src/installers/index.ts b/cli/src/installers/index.ts index 776a16ba1c..492079ab69 100644 --- a/cli/src/installers/index.ts +++ b/cli/src/installers/index.ts @@ -86,4 +86,5 @@ export const buildPkgInstallerMap = ( inUse: true, installer: dynamicEslintInstaller, }, + //* TODO add biome installer here }); From 41d2811a98b307a1d2b1daa75d7d0901533ccfdb Mon Sep 17 00:00:00 2001 From: aidansunbury Date: Sat, 9 Nov 2024 16:13:41 -0800 Subject: [PATCH 03/25] working on being able to test initial version --- cli/src/cli/index.ts | 34 +++++- cli/src/installers/biome.ts | 22 ++++ cli/src/installers/dependencyVersionMap.ts | 4 + cli/src/installers/drizzle.ts | 2 +- cli/src/installers/index.ts | 9 +- cli/src/installers/tailwind.ts | 3 + cli/template/extras/config/biome.jsonc | 129 +++++++++++++++++++++ 7 files changed, 199 insertions(+), 4 deletions(-) create mode 100644 cli/src/installers/biome.ts create mode 100644 cli/template/extras/config/biome.jsonc diff --git a/cli/src/cli/index.ts b/cli/src/cli/index.ts index 9b42d69795..4093272e15 100644 --- a/cli/src/cli/index.ts +++ b/cli/src/cli/index.ts @@ -37,6 +37,10 @@ interface CliFlags { appRouter: boolean; /** @internal Used in CI. */ dbProvider: DatabaseProvider; + /** @internal Used in CI */ + eslint: boolean; + /** @internal Used in CI */ + biome: boolean; } interface CliResults { @@ -62,6 +66,8 @@ const defaultOptions: CliResults = { importAlias: "~/", appRouter: false, dbProvider: "sqlite", + eslint: false, + biome: false, }, databaseProvider: "sqlite", }; @@ -140,12 +146,21 @@ export const runCli = async (): Promise => { )}`, defaultOptions.flags.dbProvider ) - //* Add eslint / biome options .option( "--appRouter [boolean]", "Explicitly tell the CLI to use the new Next.js app router", (value) => !!value && value !== "false" ) + .option( + "--eslint [boolean]", + "Experimental: Boolean value if we should install eslint and prettier. Must be used in conjunction with `--CI`.", + (value) => !!value && value !== "false" + ) + .option( + "--biome [boolean]", + "Experimental: Boolean value if we should install biome. Must be used in conjunction with `--CI`.", + (value) => !!value && value !== "false" + ) /** END CI-FLAGS */ .version(getVersion(), "-v, --version", "Display the version number") .addHelpText( @@ -184,6 +199,8 @@ export const runCli = async (): Promise => { if (cliResults.flags.prisma) cliResults.packages.push("prisma"); if (cliResults.flags.drizzle) cliResults.packages.push("drizzle"); if (cliResults.flags.nextAuth) cliResults.packages.push("nextAuth"); + if (cliResults.flags.eslint) cliResults.packages.push("eslint"); + if (cliResults.flags.biome) cliResults.packages.push("biome"); if (cliResults.flags.prisma && cliResults.flags.drizzle) { // We test a matrix of all possible combination of packages in CI. Checking for impossible // combinations here and exiting gracefully is easier than changing the CI matrix to exclude @@ -191,6 +208,10 @@ export const runCli = async (): Promise => { logger.warn("Incompatible combination Prisma + Drizzle. Exiting."); process.exit(0); } + if (cliResults.flags.biome && cliResults.flags.eslint) { + logger.warn("Incompatible combination Biome + ESLint. Exiting."); + process.exit(0); + }; if (databaseProviders.includes(cliResults.flags.dbProvider) === false) { logger.warn( `Incompatible database provided. Use: ${databaseProviders.join(", ")}. Exiting.` @@ -301,6 +322,16 @@ export const runCli = async (): Promise => { initialValue: "sqlite", }); }, + linter: () => { + return p.select({ + message: "Would you like to use ESLint and Prettier or Biome for linting and formatting?", + options: [ + { value: "eslint", label: "ESLint/Prettier" }, + { value: "biome", label: "Biome" }, + ], + initialValue: "eslint", + }); + }, ...(!cliResults.flags.noGit && { git: () => { return p.confirm({ @@ -342,6 +373,7 @@ export const runCli = async (): Promise => { if (project.authentication === "next-auth") packages.push("nextAuth"); if (project.database === "prisma") packages.push("prisma"); if (project.database === "drizzle") packages.push("drizzle"); + //* TODO may need to add something here? not sure return { appName: project.name ?? cliResults.appName, diff --git a/cli/src/installers/biome.ts b/cli/src/installers/biome.ts new file mode 100644 index 0000000000..8bb8686593 --- /dev/null +++ b/cli/src/installers/biome.ts @@ -0,0 +1,22 @@ +import path from "path"; +import fs from "fs-extra"; + +import { type Installer } from "~/installers/index.js"; +import { addPackageDependency } from "~/utils/addPackageDependency.js"; +import { PKG_ROOT } from "~/consts.js"; + +export const biomeInstaller: Installer = ({ projectDir }) => { + addPackageDependency({ + projectDir, + dependencies: [ + "@biomejs/biome", + ], + devMode: true, + }); + + const extrasDir = path.join(PKG_ROOT, "template/extras"); + const biomeConfigSrc = path.join(extrasDir, "config/biome.jsonc"); + const biomeConfigDest = path.join(projectDir, "biome.jsonc"); + + fs.copySync(biomeConfigSrc, biomeConfigDest); +}; diff --git a/cli/src/installers/dependencyVersionMap.ts b/cli/src/installers/dependencyVersionMap.ts index 868214a665..8e3787487d 100644 --- a/cli/src/installers/dependencyVersionMap.ts +++ b/cli/src/installers/dependencyVersionMap.ts @@ -36,5 +36,9 @@ export const dependencyVersionMap = { "@tanstack/react-query": "^5.50.0", superjson: "^2.2.1", "server-only": "^0.0.1", + + // biome + "@biomejs/biome": "1.9.4", + //* TODO also add prettier / eslint plugins here } as const; export type AvailableDependencies = keyof typeof dependencyVersionMap; diff --git a/cli/src/installers/drizzle.ts b/cli/src/installers/drizzle.ts index d9c5930b98..6b45f1e2a2 100644 --- a/cli/src/installers/drizzle.ts +++ b/cli/src/installers/drizzle.ts @@ -15,7 +15,7 @@ export const drizzleInstaller: Installer = ({ }) => { const devPackages: AvailableDependencies[] = [ "drizzle-kit", - "eslint-plugin-drizzle", + "eslint-plugin-drizzle", //* TODO make this depend on eslint being installed ]; addPackageDependency({ diff --git a/cli/src/installers/index.ts b/cli/src/installers/index.ts index 492079ab69..77809f1195 100644 --- a/cli/src/installers/index.ts +++ b/cli/src/installers/index.ts @@ -7,6 +7,7 @@ import { type PackageManager } from "~/utils/getUserPkgManager.js"; import { dbContainerInstaller } from "./dbContainer.js"; import { drizzleInstaller } from "./drizzle.js"; import { dynamicEslintInstaller } from "./eslint.js"; +import { biomeInstaller } from "./biome.js"; // Turning this into a const allows the list to be iterated over for programmatically creating prompt options // Should increase extensibility in the future @@ -18,6 +19,7 @@ export const availablePackages = [ "trpc", "envVariables", "eslint", + "biome", "dbContainer", ] as const; export type AvailablePackages = (typeof availablePackages)[number]; @@ -83,8 +85,11 @@ export const buildPkgInstallerMap = ( installer: envVariablesInstaller, }, eslint: { - inUse: true, + inUse: packages.includes("eslint"), installer: dynamicEslintInstaller, }, - //* TODO add biome installer here + biome: { + inUse: packages.includes("biome"), + installer: biomeInstaller, + }, }); diff --git a/cli/src/installers/tailwind.ts b/cli/src/installers/tailwind.ts index 86188a241d..53cc1a7137 100644 --- a/cli/src/installers/tailwind.ts +++ b/cli/src/installers/tailwind.ts @@ -35,6 +35,9 @@ export const tailwindInstaller: Installer = ({ projectDir }) => { // add format:* scripts to package.json const packageJsonPath = path.join(projectDir, "package.json"); + //* TODO for some reason the prettier related install stuff is here with tailwind, should probably be in its own installer + //* along with biome stuff + //* Update: prettier is not installed if you don't select tailwind css, which really doesn't make sense. Should move it to the eslint installer const packageJsonContent = fs.readJSONSync(packageJsonPath) as PackageJson; packageJsonContent.scripts = { ...packageJsonContent.scripts, diff --git a/cli/template/extras/config/biome.jsonc b/cli/template/extras/config/biome.jsonc new file mode 100644 index 0000000000..7ffee4f439 --- /dev/null +++ b/cli/template/extras/config/biome.jsonc @@ -0,0 +1,129 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "vcs": { "enabled": false, "clientKind": "git", "useIgnoreFile": false }, + "files": { "ignoreUnknown": false, "ignore": [] }, + "formatter": { + "enabled": true, + "useEditorconfig": true, + "formatWithErrors": false, + "indentStyle": "space", + "indentWidth": 2, + "lineEnding": "lf", + "lineWidth": 80, + "attributePosition": "auto", + "bracketSpacing": true + }, + "organizeImports": { "enabled": true }, + "linter": { + "enabled": true, + "rules": { + "recommended": false, + "complexity": { + "noUselessTypeConstraint": "error", + "useLiteralKeys": "error", + "useOptionalChain": "error" + }, + "correctness": { "noUnusedVariables": "off", "useArrayLiterals": "off" }, + "style": { + "noInferrableTypes": "error", + "noNamespace": "error", + "useAsConstAssertion": "error", + "useConsistentArrayType": "off", + "useForOf": "error", + "useShorthandFunctionType": "error" + }, + "suspicious": { + "noEmptyBlockStatements": "error", + "noExplicitAny": "error", + "noExtraNonNullAssertion": "error", + "noMisleadingInstantiator": "error", + "noUnsafeDeclarationMerging": "error", + "useAwait": "off", + "useNamespaceKeyword": "error" + } + } + }, + "javascript": { + "formatter": { + "jsxQuoteStyle": "double", + "quoteProperties": "asNeeded", + "trailingCommas": "all", + "semicolons": "asNeeded", + "arrowParentheses": "always", + "bracketSameLine": false, + "quoteStyle": "single", + "attributePosition": "auto", + "bracketSpacing": true + } + }, + "overrides": [ + { + "include": ["*.ts", "*.tsx", "*.mts", "*.cts"], + "linter": { + "rules": { + "correctness": { + "noConstAssign": "off", + "noGlobalObjectCalls": "off", + "noInvalidBuiltinInstantiation": "off", + "noInvalidConstructorSuper": "off", + "noNewSymbol": "off", + "noSetterReturn": "off", + "noUndeclaredVariables": "off", + "noUnreachable": "off", + "noUnreachableSuper": "off" + }, + "style": { + "noArguments": "error", + "noVar": "error", + "useConst": "error" + }, + "suspicious": { + "noClassAssign": "off", + "noDuplicateClassMembers": "off", + "noDuplicateObjectKeys": "off", + "noDuplicateParameters": "off", + "noFunctionAssign": "off", + "noImportAssign": "off", + "noRedeclare": "off", + "noUnsafeNegation": "off", + "useGetterReturn": "off" + } + } + } + }, + { + "include": ["*.ts", "*.tsx", "*.mts", "*.cts"], + "linter": { + "rules": { + "correctness": { + "noConstAssign": "off", + "noGlobalObjectCalls": "off", + "noInvalidBuiltinInstantiation": "off", + "noInvalidConstructorSuper": "off", + "noNewSymbol": "off", + "noSetterReturn": "off", + "noUndeclaredVariables": "off", + "noUnreachable": "off", + "noUnreachableSuper": "off" + }, + "style": { + "noArguments": "error", + "noVar": "error", + "useConst": "error" + }, + "suspicious": { + "noClassAssign": "off", + "noDuplicateClassMembers": "off", + "noDuplicateObjectKeys": "off", + "noDuplicateParameters": "off", + "noFunctionAssign": "off", + "noImportAssign": "off", + "noRedeclare": "off", + "noUnsafeNegation": "off", + "useGetterReturn": "off" + } + } + } + } + ] +} From bafb814b24da28cd879822ec7c345f01af4d729d Mon Sep 17 00:00:00 2001 From: aidansunbury Date: Sat, 9 Nov 2024 16:55:48 -0800 Subject: [PATCH 04/25] moved prettier related setup to eslint file so that it is not tied to tailwind css --- cli/src/installers/dependencyVersionMap.ts | 18 ++++-- cli/src/installers/drizzle.ts | 7 +-- cli/src/installers/eslint.ts | 56 ++++++++++++++++++- cli/src/installers/tailwind.ts | 23 -------- cli/template/base/package.json | 5 -- .../extras/config/_prettier.config.js | 6 +- .../config/_tailwind.prettier.config.js | 4 ++ 7 files changed, 75 insertions(+), 44 deletions(-) create mode 100644 cli/template/extras/config/_tailwind.prettier.config.js diff --git a/cli/src/installers/dependencyVersionMap.ts b/cli/src/installers/dependencyVersionMap.ts index 8e3787487d..e250b0afe1 100644 --- a/cli/src/installers/dependencyVersionMap.ts +++ b/cli/src/installers/dependencyVersionMap.ts @@ -16,7 +16,6 @@ export const dependencyVersionMap = { // Drizzle "drizzle-kit": "^0.24.0", "drizzle-orm": "^0.33.0", - "eslint-plugin-drizzle": "^0.2.3", mysql2: "^3.11.0", "@planetscale/database": "^1.19.0", postgres: "^3.4.4", @@ -24,9 +23,7 @@ export const dependencyVersionMap = { // TailwindCSS tailwindcss: "^3.4.3", - postcss: "^8.4.39", - prettier: "^3.3.2", - "prettier-plugin-tailwindcss": "^0.6.5", + postcss: "^8.4.39", // tRPC "@trpc/client": "^11.0.0-rc.446", @@ -39,6 +36,17 @@ export const dependencyVersionMap = { // biome "@biomejs/biome": "1.9.4", - //* TODO also add prettier / eslint plugins here + + // eslint / prettier + prettier: "^3.3.2", + "prettier-plugin-tailwindcss": "^0.6.5", + "eslint": "^8.57.0", + "eslint-config-next": "^15.0.1", + "eslint-plugin-drizzle": "^0.2.3", + "@types/eslint": "^8.56.10", + "@typescript-eslint/eslint-plugin": "^8.1.0", + "@typescript-eslint/parser": "^8.1.0", + //* TODO make sure all these are install normally when eslint is selected + } as const; export type AvailableDependencies = keyof typeof dependencyVersionMap; diff --git a/cli/src/installers/drizzle.ts b/cli/src/installers/drizzle.ts index 6b45f1e2a2..bd90ee0c79 100644 --- a/cli/src/installers/drizzle.ts +++ b/cli/src/installers/drizzle.ts @@ -5,7 +5,6 @@ import { type PackageJson } from "type-fest"; import { PKG_ROOT } from "~/consts.js"; import { type Installer } from "~/installers/index.js"; import { addPackageDependency } from "~/utils/addPackageDependency.js"; -import { type AvailableDependencies } from "./dependencyVersionMap.js"; export const drizzleInstaller: Installer = ({ projectDir, @@ -13,14 +12,10 @@ export const drizzleInstaller: Installer = ({ scopedAppName, databaseProvider, }) => { - const devPackages: AvailableDependencies[] = [ - "drizzle-kit", - "eslint-plugin-drizzle", //* TODO make this depend on eslint being installed - ]; addPackageDependency({ projectDir, - dependencies: devPackages, + dependencies: ["drizzle-kit"], devMode: true, }); addPackageDependency({ diff --git a/cli/src/installers/eslint.ts b/cli/src/installers/eslint.ts index 6600168271..549a23f16e 100644 --- a/cli/src/installers/eslint.ts +++ b/cli/src/installers/eslint.ts @@ -1,12 +1,66 @@ import path from "path"; import fs from "fs-extra"; +import { type PackageJson } from "type-fest"; +import { PKG_ROOT } from "~/consts.js"; import { _initialConfig } from "~/../template/extras/config/_eslint.js"; import { type Installer } from "~/installers/index.js"; +import { addPackageDependency } from "~/utils/addPackageDependency.js"; +import { type AvailableDependencies } from "./dependencyVersionMap.js"; + +// Also installs prettier export const dynamicEslintInstaller: Installer = ({ projectDir, packages }) => { - const usingDrizzle = !!packages?.drizzle?.inUse; + const devPackages: AvailableDependencies[] = [ + "prettier", + "eslint", + "eslint-config-next", + "@types/eslint", + "@typescript-eslint/eslint-plugin", + "@typescript-eslint/parser", + ]; + if (packages?.tailwind.inUse) { + devPackages.push("prettier-plugin-tailwindcss"); + } + if (packages?.drizzle.inUse) { + devPackages.push("eslint-plugin-drizzle"); + } + + addPackageDependency({ + projectDir, + dependencies: devPackages, + devMode: true, + }); + const extrasDir = path.join(PKG_ROOT, "template/extras"); + + // Prettier + let prettierSrc: string; + if (packages?.tailwind.inUse) { + prettierSrc = path.join(extrasDir, "config/_tailwind.prettier.config.js"); + } + else { + prettierSrc = path.join(extrasDir, "config/_prettier.config.js"); + } + const prettierDest = path.join(projectDir, "prettier.config.js"); + + fs.copySync(prettierSrc, prettierDest); + + // add format:* scripts to package.json + const packageJsonPath = path.join(projectDir, "package.json"); + const packageJsonContent = fs.readJSONSync(packageJsonPath) as PackageJson; + packageJsonContent.scripts = { + ...packageJsonContent.scripts, + "format:write": 'prettier --write "**/*.{ts,tsx,js,jsx,mdx}" --cache', + "format:check": 'prettier --check "**/*.{ts,tsx,js,jsx,mdx}" --cache', + }; + + fs.writeJSONSync(packageJsonPath, packageJsonContent, { + spaces: 2, + }); + + // eslint + const usingDrizzle = !!packages?.drizzle?.inUse; const eslintConfig = getEslintConfig({ usingDrizzle }); // Convert config from _eslint.config.json to .eslintrc.cjs diff --git a/cli/src/installers/tailwind.ts b/cli/src/installers/tailwind.ts index 53cc1a7137..559150def2 100644 --- a/cli/src/installers/tailwind.ts +++ b/cli/src/installers/tailwind.ts @@ -1,6 +1,5 @@ import path from "path"; import fs from "fs-extra"; -import { type PackageJson } from "type-fest"; import { PKG_ROOT } from "~/consts.js"; import { type Installer } from "~/installers/index.js"; @@ -12,8 +11,6 @@ export const tailwindInstaller: Installer = ({ projectDir }) => { dependencies: [ "tailwindcss", "postcss", - "prettier", - "prettier-plugin-tailwindcss", ], devMode: true, }); @@ -26,30 +23,10 @@ export const tailwindInstaller: Installer = ({ projectDir }) => { const postcssCfgSrc = path.join(extrasDir, "config/postcss.config.js"); const postcssCfgDest = path.join(projectDir, "postcss.config.js"); - const prettierSrc = path.join(extrasDir, "config/_prettier.config.js"); - const prettierDest = path.join(projectDir, "prettier.config.js"); - const cssSrc = path.join(extrasDir, "src/styles/globals.css"); const cssDest = path.join(projectDir, "src/styles/globals.css"); - // add format:* scripts to package.json - const packageJsonPath = path.join(projectDir, "package.json"); - - //* TODO for some reason the prettier related install stuff is here with tailwind, should probably be in its own installer - //* along with biome stuff - //* Update: prettier is not installed if you don't select tailwind css, which really doesn't make sense. Should move it to the eslint installer - const packageJsonContent = fs.readJSONSync(packageJsonPath) as PackageJson; - packageJsonContent.scripts = { - ...packageJsonContent.scripts, - "format:write": 'prettier --write "**/*.{ts,tsx,js,jsx,mdx}" --cache', - "format:check": 'prettier --check "**/*.{ts,tsx,js,jsx,mdx}" --cache', - }; - fs.copySync(twCfgSrc, twCfgDest); fs.copySync(postcssCfgSrc, postcssCfgDest); fs.copySync(cssSrc, cssDest); - fs.copySync(prettierSrc, prettierDest); - fs.writeJSONSync(packageJsonPath, packageJsonContent, { - spaces: 2, - }); }; diff --git a/cli/template/base/package.json b/cli/template/base/package.json index 00ca211bdc..df54d7c844 100644 --- a/cli/template/base/package.json +++ b/cli/template/base/package.json @@ -22,14 +22,9 @@ "zod": "^3.23.3" }, "devDependencies": { - "@types/eslint": "^8.56.10", "@types/node": "^20.14.10", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", - "@typescript-eslint/eslint-plugin": "^8.1.0", - "@typescript-eslint/parser": "^8.1.0", - "eslint": "^8.57.0", - "eslint-config-next": "^15.0.1", "typescript": "^5.5.3" } } diff --git a/cli/template/extras/config/_prettier.config.js b/cli/template/extras/config/_prettier.config.js index da332bd898..6f1a202fbd 100644 --- a/cli/template/extras/config/_prettier.config.js +++ b/cli/template/extras/config/_prettier.config.js @@ -1,4 +1,2 @@ -/** @type {import('prettier').Config & import('prettier-plugin-tailwindcss').PluginOptions} */ -export default { - plugins: ["prettier-plugin-tailwindcss"], -}; +/** @type {import('prettier').Config} */ +export default {}; diff --git a/cli/template/extras/config/_tailwind.prettier.config.js b/cli/template/extras/config/_tailwind.prettier.config.js new file mode 100644 index 0000000000..da332bd898 --- /dev/null +++ b/cli/template/extras/config/_tailwind.prettier.config.js @@ -0,0 +1,4 @@ +/** @type {import('prettier').Config & import('prettier-plugin-tailwindcss').PluginOptions} */ +export default { + plugins: ["prettier-plugin-tailwindcss"], +}; From d62917f2b75f534ceb1e04b943355d0088dc162e Mon Sep 17 00:00:00 2001 From: aidansunbury Date: Sat, 9 Nov 2024 17:20:30 -0800 Subject: [PATCH 05/25] added package.json scripts for biome --- cli/src/cli/index.ts | 8 +- cli/src/installers/biome.ts | 20 ++- cli/src/installers/dependencyVersionMap.ts | 6 +- cli/src/installers/drizzle.ts | 1 - cli/src/installers/eslint.ts | 6 +- cli/src/installers/index.ts | 2 +- cli/src/installers/tailwind.ts | 5 +- cli/template/extras/config/biome.jsonc | 152 ++++----------------- 8 files changed, 51 insertions(+), 149 deletions(-) diff --git a/cli/src/cli/index.ts b/cli/src/cli/index.ts index 4093272e15..4a0e236a37 100644 --- a/cli/src/cli/index.ts +++ b/cli/src/cli/index.ts @@ -211,7 +211,7 @@ export const runCli = async (): Promise => { if (cliResults.flags.biome && cliResults.flags.eslint) { logger.warn("Incompatible combination Biome + ESLint. Exiting."); process.exit(0); - }; + } if (databaseProviders.includes(cliResults.flags.dbProvider) === false) { logger.warn( `Incompatible database provided. Use: ${databaseProviders.join(", ")}. Exiting.` @@ -324,7 +324,8 @@ export const runCli = async (): Promise => { }, linter: () => { return p.select({ - message: "Would you like to use ESLint and Prettier or Biome for linting and formatting?", + message: + "Would you like to use ESLint and Prettier or Biome for linting and formatting?", options: [ { value: "eslint", label: "ESLint/Prettier" }, { value: "biome", label: "Biome" }, @@ -373,7 +374,8 @@ export const runCli = async (): Promise => { if (project.authentication === "next-auth") packages.push("nextAuth"); if (project.database === "prisma") packages.push("prisma"); if (project.database === "drizzle") packages.push("drizzle"); - //* TODO may need to add something here? not sure + if (project.linter === "eslint") packages.push("eslint"); + if (project.linter === "biome") packages.push("biome"); return { appName: project.name ?? cliResults.appName, diff --git a/cli/src/installers/biome.ts b/cli/src/installers/biome.ts index 8bb8686593..e31de626db 100644 --- a/cli/src/installers/biome.ts +++ b/cli/src/installers/biome.ts @@ -1,16 +1,15 @@ import path from "path"; import fs from "fs-extra"; +import { type PackageJson } from "type-fest"; +import { PKG_ROOT } from "~/consts.js"; import { type Installer } from "~/installers/index.js"; import { addPackageDependency } from "~/utils/addPackageDependency.js"; -import { PKG_ROOT } from "~/consts.js"; export const biomeInstaller: Installer = ({ projectDir }) => { addPackageDependency({ projectDir, - dependencies: [ - "@biomejs/biome", - ], + dependencies: ["@biomejs/biome"], devMode: true, }); @@ -19,4 +18,17 @@ export const biomeInstaller: Installer = ({ projectDir }) => { const biomeConfigDest = path.join(projectDir, "biome.jsonc"); fs.copySync(biomeConfigSrc, biomeConfigDest); + + // add format:* scripts to package.json + const packageJsonPath = path.join(projectDir, "package.json"); + const packageJsonContent = fs.readJSONSync(packageJsonPath) as PackageJson; + packageJsonContent.scripts = { + ...packageJsonContent.scripts, + "format:write": 'biome format --write "**/*.{ts,tsx,js,jsx,mdx}"', + "format:check": 'biome format --check "**/*.{ts,tsx,js,jsx,mdx}"', + }; + + fs.writeJSONSync(packageJsonPath, packageJsonContent, { + spaces: 2, + }); }; diff --git a/cli/src/installers/dependencyVersionMap.ts b/cli/src/installers/dependencyVersionMap.ts index e250b0afe1..b95d246220 100644 --- a/cli/src/installers/dependencyVersionMap.ts +++ b/cli/src/installers/dependencyVersionMap.ts @@ -23,7 +23,7 @@ export const dependencyVersionMap = { // TailwindCSS tailwindcss: "^3.4.3", - postcss: "^8.4.39", + postcss: "^8.4.39", // tRPC "@trpc/client": "^11.0.0-rc.446", @@ -40,13 +40,11 @@ export const dependencyVersionMap = { // eslint / prettier prettier: "^3.3.2", "prettier-plugin-tailwindcss": "^0.6.5", - "eslint": "^8.57.0", + eslint: "^8.57.0", "eslint-config-next": "^15.0.1", "eslint-plugin-drizzle": "^0.2.3", "@types/eslint": "^8.56.10", "@typescript-eslint/eslint-plugin": "^8.1.0", "@typescript-eslint/parser": "^8.1.0", - //* TODO make sure all these are install normally when eslint is selected - } as const; export type AvailableDependencies = keyof typeof dependencyVersionMap; diff --git a/cli/src/installers/drizzle.ts b/cli/src/installers/drizzle.ts index bd90ee0c79..5b9ad9bcd0 100644 --- a/cli/src/installers/drizzle.ts +++ b/cli/src/installers/drizzle.ts @@ -12,7 +12,6 @@ export const drizzleInstaller: Installer = ({ scopedAppName, databaseProvider, }) => { - addPackageDependency({ projectDir, dependencies: ["drizzle-kit"], diff --git a/cli/src/installers/eslint.ts b/cli/src/installers/eslint.ts index 549a23f16e..e317d44939 100644 --- a/cli/src/installers/eslint.ts +++ b/cli/src/installers/eslint.ts @@ -2,13 +2,12 @@ import path from "path"; import fs from "fs-extra"; import { type PackageJson } from "type-fest"; -import { PKG_ROOT } from "~/consts.js"; import { _initialConfig } from "~/../template/extras/config/_eslint.js"; +import { PKG_ROOT } from "~/consts.js"; import { type Installer } from "~/installers/index.js"; import { addPackageDependency } from "~/utils/addPackageDependency.js"; import { type AvailableDependencies } from "./dependencyVersionMap.js"; - // Also installs prettier export const dynamicEslintInstaller: Installer = ({ projectDir, packages }) => { const devPackages: AvailableDependencies[] = [ @@ -38,8 +37,7 @@ export const dynamicEslintInstaller: Installer = ({ projectDir, packages }) => { let prettierSrc: string; if (packages?.tailwind.inUse) { prettierSrc = path.join(extrasDir, "config/_tailwind.prettier.config.js"); - } - else { + } else { prettierSrc = path.join(extrasDir, "config/_prettier.config.js"); } const prettierDest = path.join(projectDir, "prettier.config.js"); diff --git a/cli/src/installers/index.ts b/cli/src/installers/index.ts index 77809f1195..366760a23b 100644 --- a/cli/src/installers/index.ts +++ b/cli/src/installers/index.ts @@ -4,10 +4,10 @@ import { prismaInstaller } from "~/installers/prisma.js"; import { tailwindInstaller } from "~/installers/tailwind.js"; import { trpcInstaller } from "~/installers/trpc.js"; import { type PackageManager } from "~/utils/getUserPkgManager.js"; +import { biomeInstaller } from "./biome.js"; import { dbContainerInstaller } from "./dbContainer.js"; import { drizzleInstaller } from "./drizzle.js"; import { dynamicEslintInstaller } from "./eslint.js"; -import { biomeInstaller } from "./biome.js"; // Turning this into a const allows the list to be iterated over for programmatically creating prompt options // Should increase extensibility in the future diff --git a/cli/src/installers/tailwind.ts b/cli/src/installers/tailwind.ts index 559150def2..3df90bfa66 100644 --- a/cli/src/installers/tailwind.ts +++ b/cli/src/installers/tailwind.ts @@ -8,10 +8,7 @@ import { addPackageDependency } from "~/utils/addPackageDependency.js"; export const tailwindInstaller: Installer = ({ projectDir }) => { addPackageDependency({ projectDir, - dependencies: [ - "tailwindcss", - "postcss", - ], + dependencies: ["tailwindcss", "postcss"], devMode: true, }); diff --git a/cli/template/extras/config/biome.jsonc b/cli/template/extras/config/biome.jsonc index 7ffee4f439..adb632dfa2 100644 --- a/cli/template/extras/config/biome.jsonc +++ b/cli/template/extras/config/biome.jsonc @@ -1,129 +1,25 @@ { - "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", - "vcs": { "enabled": false, "clientKind": "git", "useIgnoreFile": false }, - "files": { "ignoreUnknown": false, "ignore": [] }, - "formatter": { - "enabled": true, - "useEditorconfig": true, - "formatWithErrors": false, - "indentStyle": "space", - "indentWidth": 2, - "lineEnding": "lf", - "lineWidth": 80, - "attributePosition": "auto", - "bracketSpacing": true - }, - "organizeImports": { "enabled": true }, - "linter": { - "enabled": true, - "rules": { - "recommended": false, - "complexity": { - "noUselessTypeConstraint": "error", - "useLiteralKeys": "error", - "useOptionalChain": "error" - }, - "correctness": { "noUnusedVariables": "off", "useArrayLiterals": "off" }, - "style": { - "noInferrableTypes": "error", - "noNamespace": "error", - "useAsConstAssertion": "error", - "useConsistentArrayType": "off", - "useForOf": "error", - "useShorthandFunctionType": "error" - }, - "suspicious": { - "noEmptyBlockStatements": "error", - "noExplicitAny": "error", - "noExtraNonNullAssertion": "error", - "noMisleadingInstantiator": "error", - "noUnsafeDeclarationMerging": "error", - "useAwait": "off", - "useNamespaceKeyword": "error" - } - } - }, - "javascript": { - "formatter": { - "jsxQuoteStyle": "double", - "quoteProperties": "asNeeded", - "trailingCommas": "all", - "semicolons": "asNeeded", - "arrowParentheses": "always", - "bracketSameLine": false, - "quoteStyle": "single", - "attributePosition": "auto", - "bracketSpacing": true - } - }, - "overrides": [ - { - "include": ["*.ts", "*.tsx", "*.mts", "*.cts"], - "linter": { - "rules": { - "correctness": { - "noConstAssign": "off", - "noGlobalObjectCalls": "off", - "noInvalidBuiltinInstantiation": "off", - "noInvalidConstructorSuper": "off", - "noNewSymbol": "off", - "noSetterReturn": "off", - "noUndeclaredVariables": "off", - "noUnreachable": "off", - "noUnreachableSuper": "off" - }, - "style": { - "noArguments": "error", - "noVar": "error", - "useConst": "error" - }, - "suspicious": { - "noClassAssign": "off", - "noDuplicateClassMembers": "off", - "noDuplicateObjectKeys": "off", - "noDuplicateParameters": "off", - "noFunctionAssign": "off", - "noImportAssign": "off", - "noRedeclare": "off", - "noUnsafeNegation": "off", - "useGetterReturn": "off" - } - } - } - }, - { - "include": ["*.ts", "*.tsx", "*.mts", "*.cts"], - "linter": { - "rules": { - "correctness": { - "noConstAssign": "off", - "noGlobalObjectCalls": "off", - "noInvalidBuiltinInstantiation": "off", - "noInvalidConstructorSuper": "off", - "noNewSymbol": "off", - "noSetterReturn": "off", - "noUndeclaredVariables": "off", - "noUnreachable": "off", - "noUnreachableSuper": "off" - }, - "style": { - "noArguments": "error", - "noVar": "error", - "useConst": "error" - }, - "suspicious": { - "noClassAssign": "off", - "noDuplicateClassMembers": "off", - "noDuplicateObjectKeys": "off", - "noDuplicateParameters": "off", - "noFunctionAssign": "off", - "noImportAssign": "off", - "noRedeclare": "off", - "noUnsafeNegation": "off", - "useGetterReturn": "off" - } - } - } - } - ] -} + "$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 }, + "organizeImports": { "enabled": true }, + "linter": { + "enabled": true, + "rules": { + "nursery": { + "useSortedClasses": { + "level": "error", + "options": { + "functions": ["clsx", "cva", "cn"] + } + } + }, + "recommended": true } + }, + "javascript": { "formatter": { "quoteStyle": "double" } } +} \ No newline at end of file From 2c1f7f18b1b0cb1379a6f6fd4587caf174a3f404 Mon Sep 17 00:00:00 2001 From: aidansunbury Date: Sat, 9 Nov 2024 17:22:45 -0800 Subject: [PATCH 06/25] added changeset --- .changeset/late-tips-eat.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/late-tips-eat.md diff --git a/.changeset/late-tips-eat.md b/.changeset/late-tips-eat.md new file mode 100644 index 0000000000..197aae6389 --- /dev/null +++ b/.changeset/late-tips-eat.md @@ -0,0 +1,5 @@ +--- +"create-t3-app": minor +--- + +Added support for biome.js as a formatter and linter From cbad9bc5093082c50aa16a727066614577886603 Mon Sep 17 00:00:00 2001 From: aidansunbury Date: Thu, 14 Nov 2024 21:17:02 -0800 Subject: [PATCH 07/25] fixed biome scripts and created addPackageScript function --- cli/src/installers/biome.ts | 20 ++++++++------------ cli/src/installers/drizzle.ts | 25 ++++++++++--------------- cli/src/installers/eslint.ts | 22 ++++++++++------------ cli/src/installers/prisma.ts | 27 +++++++++++---------------- cli/src/utils/addPackageScript.ts | 25 +++++++++++++++++++++++++ cli/template/base/package.json | 3 --- 6 files changed, 64 insertions(+), 58 deletions(-) create mode 100644 cli/src/utils/addPackageScript.ts diff --git a/cli/src/installers/biome.ts b/cli/src/installers/biome.ts index e31de626db..dfa5254e2d 100644 --- a/cli/src/installers/biome.ts +++ b/cli/src/installers/biome.ts @@ -1,10 +1,10 @@ import path from "path"; import fs from "fs-extra"; -import { type PackageJson } from "type-fest"; import { PKG_ROOT } from "~/consts.js"; import { type Installer } from "~/installers/index.js"; import { addPackageDependency } from "~/utils/addPackageDependency.js"; +import { addPackageScript } from "~/utils/addPackageScript.js"; export const biomeInstaller: Installer = ({ projectDir }) => { addPackageDependency({ @@ -19,16 +19,12 @@ export const biomeInstaller: Installer = ({ projectDir }) => { fs.copySync(biomeConfigSrc, biomeConfigDest); - // add format:* scripts to package.json - const packageJsonPath = path.join(projectDir, "package.json"); - const packageJsonContent = fs.readJSONSync(packageJsonPath) as PackageJson; - packageJsonContent.scripts = { - ...packageJsonContent.scripts, - "format:write": 'biome format --write "**/*.{ts,tsx,js,jsx,mdx}"', - "format:check": 'biome format --check "**/*.{ts,tsx,js,jsx,mdx}"', - }; - - fs.writeJSONSync(packageJsonPath, packageJsonContent, { - spaces: 2, + addPackageScript({ + projectDir, + scripts: { + "format:unsafe": "biome check --write --unsafe .", + "format:write": "biome check --write .", + "format:check": "biome check .", + }, }); }; diff --git a/cli/src/installers/drizzle.ts b/cli/src/installers/drizzle.ts index 5b9ad9bcd0..c9bbae8590 100644 --- a/cli/src/installers/drizzle.ts +++ b/cli/src/installers/drizzle.ts @@ -1,10 +1,10 @@ import path from "path"; import fs from "fs-extra"; -import { type PackageJson } from "type-fest"; import { PKG_ROOT } from "~/consts.js"; import { type Installer } from "~/installers/index.js"; import { addPackageDependency } from "~/utils/addPackageDependency.js"; +import { addPackageScript } from "~/utils/addPackageScript.js"; export const drizzleInstaller: Installer = ({ projectDir, @@ -69,24 +69,19 @@ export const drizzleInstaller: Installer = ({ ); const clientDest = path.join(projectDir, "src/server/db/index.ts"); - // add db:* scripts to package.json - const packageJsonPath = path.join(projectDir, "package.json"); - - const packageJsonContent = fs.readJSONSync(packageJsonPath) as PackageJson; - packageJsonContent.scripts = { - ...packageJsonContent.scripts, - "db:push": "drizzle-kit push", - "db:studio": "drizzle-kit studio", - "db:generate": "drizzle-kit generate", - "db:migrate": "drizzle-kit migrate", - }; + addPackageScript({ + projectDir, + scripts: { + "db:push": "drizzle-kit push", + "db:studio": "drizzle-kit studio", + "db:generate": "drizzle-kit generate", + "db:migrate": "drizzle-kit migrate", + }, + }); fs.copySync(configFile, configDest); fs.mkdirSync(path.dirname(schemaDest), { recursive: true }); fs.writeFileSync(schemaDest, schemaContent); fs.writeFileSync(configDest, configContent); fs.copySync(clientSrc, clientDest); - fs.writeJSONSync(packageJsonPath, packageJsonContent, { - spaces: 2, - }); }; diff --git a/cli/src/installers/eslint.ts b/cli/src/installers/eslint.ts index e317d44939..4b0a872fd7 100644 --- a/cli/src/installers/eslint.ts +++ b/cli/src/installers/eslint.ts @@ -1,11 +1,11 @@ import path from "path"; import fs from "fs-extra"; -import { type PackageJson } from "type-fest"; import { _initialConfig } from "~/../template/extras/config/_eslint.js"; import { PKG_ROOT } from "~/consts.js"; import { type Installer } from "~/installers/index.js"; import { addPackageDependency } from "~/utils/addPackageDependency.js"; +import { addPackageScript } from "~/utils/addPackageScript.js"; import { type AvailableDependencies } from "./dependencyVersionMap.js"; // Also installs prettier @@ -44,17 +44,15 @@ export const dynamicEslintInstaller: Installer = ({ projectDir, packages }) => { fs.copySync(prettierSrc, prettierDest); - // add format:* scripts to package.json - const packageJsonPath = path.join(projectDir, "package.json"); - const packageJsonContent = fs.readJSONSync(packageJsonPath) as PackageJson; - packageJsonContent.scripts = { - ...packageJsonContent.scripts, - "format:write": 'prettier --write "**/*.{ts,tsx,js,jsx,mdx}" --cache', - "format:check": 'prettier --check "**/*.{ts,tsx,js,jsx,mdx}" --cache', - }; - - fs.writeJSONSync(packageJsonPath, packageJsonContent, { - spaces: 2, + addPackageScript({ + projectDir, + scripts: { + lint: "next lint", + "lint:fix": "next lint --fix", + check: "next lint && tsc --noEmit", + "format:write": 'prettier --write "**/*.{ts,tsx,js,jsx,mdx}" --cache', + "format:check": 'prettier --check "**/*.{ts,tsx,js,jsx,mdx}" --cache', + }, }); // eslint diff --git a/cli/src/installers/prisma.ts b/cli/src/installers/prisma.ts index f92da12395..36c2b7cff7 100644 --- a/cli/src/installers/prisma.ts +++ b/cli/src/installers/prisma.ts @@ -1,10 +1,10 @@ import path from "path"; import fs from "fs-extra"; -import { type PackageJson } from "type-fest"; import { PKG_ROOT } from "~/consts.js"; import { type Installer } from "~/installers/index.js"; import { addPackageDependency } from "~/utils/addPackageDependency.js"; +import { addPackageScript } from "~/utils/addPackageScript.js"; export const prismaInstaller: Installer = ({ projectDir, @@ -65,21 +65,16 @@ export const prismaInstaller: Installer = ({ ); const clientDest = path.join(projectDir, "src/server/db.ts"); - // add postinstall and push script to package.json - const packageJsonPath = path.join(projectDir, "package.json"); - - const packageJsonContent = fs.readJSONSync(packageJsonPath) as PackageJson; - packageJsonContent.scripts = { - ...packageJsonContent.scripts, - postinstall: "prisma generate", - "db:push": "prisma db push", - "db:studio": "prisma studio", - "db:generate": "prisma migrate dev", - "db:migrate": "prisma migrate deploy", - }; + addPackageScript({ + projectDir, + scripts: { + postinstall: "prisma generate", + "db:push": "prisma db push", + "db:studio": "prisma studio", + "db:generate": "prisma migrate dev", + "db:migrate": "prisma migrate deploy", + }, + }); fs.copySync(clientSrc, clientDest); - fs.writeJSONSync(packageJsonPath, packageJsonContent, { - spaces: 2, - }); }; diff --git a/cli/src/utils/addPackageScript.ts b/cli/src/utils/addPackageScript.ts new file mode 100644 index 0000000000..fc14a7d2df --- /dev/null +++ b/cli/src/utils/addPackageScript.ts @@ -0,0 +1,25 @@ +import path from "path"; +import fs from "fs-extra"; +import sortPackageJson from "sort-package-json"; +import { type PackageJson } from "type-fest"; + +export const addPackageScript = (opts: { + scripts: Record; + projectDir: string; +}) => { + const { scripts, projectDir } = opts; + + const packageJsonPath = path.join(projectDir, "package.json"); + const packageJsonContent = fs.readJSONSync(packageJsonPath) as PackageJson; + + packageJsonContent.scripts = { + ...packageJsonContent.scripts, + ...scripts, + }; + + const sortedPkgJson = sortPackageJson(packageJsonContent); + + fs.writeJSONSync(packageJsonPath, sortedPkgJson, { + spaces: 2, + }); +}; diff --git a/cli/template/base/package.json b/cli/template/base/package.json index df54d7c844..5ba41fb202 100644 --- a/cli/template/base/package.json +++ b/cli/template/base/package.json @@ -7,9 +7,6 @@ "dev": "next dev --turbo", "build": "next build", "start": "next start", - "lint": "next lint", - "lint:fix": "next lint --fix", - "check": "next lint && tsc --noEmit", "preview": "next build && next start", "typecheck": "tsc --noEmit" }, From e84958ea91259cfc5add912866dd65e6acbd5a19 Mon Sep 17 00:00:00 2001 From: aidansunbury Date: Wed, 15 Jan 2025 13:32:48 -0800 Subject: [PATCH 08/25] test adding lint and formating check to e2e tests --- .github/workflows/e2e.yml | 4 ++++ cli/src/helpers/format.ts | 8 ++++++++ cli/src/index.ts | 4 +++- cli/src/installers/biome.ts | 6 +++--- cli/template/extras/src/trpc/react.tsx | 5 ++++- 5 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 cli/src/helpers/format.ts diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index ae0d0fc562..7bb594b76d 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -34,6 +34,7 @@ jobs: appRouter: ["true", "false"] drizzle: ["true", "false"] dbType: ["planetscale", "sqlite", "mysql", "postgres"] + # linter: ["eslint", "biome"] name: "Build and Start T3 App ${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }}" steps: @@ -66,6 +67,9 @@ jobs: AUTH_DISCORD_SECRET: baz SKIP_ENV_VALIDATION: true + # WIP ensure that generated app passes formatting and linting checks + - run: pnpm format:check && pnpm check + build-t3-app-with-bun: runs-on: ubuntu-latest diff --git a/cli/src/helpers/format.ts b/cli/src/helpers/format.ts new file mode 100644 index 0000000000..a25d88a54a --- /dev/null +++ b/cli/src/helpers/format.ts @@ -0,0 +1,8 @@ +import { execa } from "execa"; + +import { logger } from "~/utils/logger.js"; + +//! WIP not implemented yet + +// Ensures that generated project is tidy after init according to selected formatter +export const formatProject = (eslint: boolean, biome: boolean) => {}; diff --git a/cli/src/index.ts b/cli/src/index.ts index 0394f25180..cc0ab4d134 100644 --- a/cli/src/index.ts +++ b/cli/src/index.ts @@ -38,7 +38,7 @@ const main = async () => { const { appName, packages, - flags: { noGit, noInstall, importAlias, appRouter }, + flags: { noGit, noInstall, importAlias, appRouter, eslint }, databaseProvider, } = await runCli(); @@ -89,6 +89,8 @@ const main = async () => { await initializeGit(projectDir); } + // TODO run format command + await logNextSteps({ projectName: appDir, packages: usePackages, diff --git a/cli/src/installers/biome.ts b/cli/src/installers/biome.ts index dfa5254e2d..ed24047046 100644 --- a/cli/src/installers/biome.ts +++ b/cli/src/installers/biome.ts @@ -22,9 +22,9 @@ export const biomeInstaller: Installer = ({ projectDir }) => { addPackageScript({ projectDir, scripts: { - "format:unsafe": "biome check --write --unsafe .", - "format:write": "biome check --write .", - "format:check": "biome check .", + "check:unsafe": "biome check --write --unsafe .", + "check:write": "biome check --write .", + check: "biome check .", }, }); }; diff --git a/cli/template/extras/src/trpc/react.tsx b/cli/template/extras/src/trpc/react.tsx index 8c0521a74e..f84b4da390 100644 --- a/cli/template/extras/src/trpc/react.tsx +++ b/cli/template/extras/src/trpc/react.tsx @@ -17,7 +17,10 @@ const getQueryClient = () => { return createQueryClient(); } // Browser: use singleton pattern to keep the same query client - return (clientQueryClientSingleton ??= createQueryClient()); + if (!clientQueryClientSingleton) { + clientQueryClientSingleton = createQueryClient(); + } + return clientQueryClientSingleton; }; export const api = createTRPCReact(); From 9ef765b4c950bbd5b35bfc073ce11aa97143adaf Mon Sep 17 00:00:00 2001 From: aidansunbury Date: Wed, 15 Jan 2025 13:37:24 -0800 Subject: [PATCH 09/25] fix lint issues to be able to run updated e2e tests --- cli/src/helpers/format.ts | 8 -------- cli/src/index.ts | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/cli/src/helpers/format.ts b/cli/src/helpers/format.ts index a25d88a54a..e69de29bb2 100644 --- a/cli/src/helpers/format.ts +++ b/cli/src/helpers/format.ts @@ -1,8 +0,0 @@ -import { execa } from "execa"; - -import { logger } from "~/utils/logger.js"; - -//! WIP not implemented yet - -// Ensures that generated project is tidy after init according to selected formatter -export const formatProject = (eslint: boolean, biome: boolean) => {}; diff --git a/cli/src/index.ts b/cli/src/index.ts index cc0ab4d134..b8b420d32b 100644 --- a/cli/src/index.ts +++ b/cli/src/index.ts @@ -38,7 +38,7 @@ const main = async () => { const { appName, packages, - flags: { noGit, noInstall, importAlias, appRouter, eslint }, + flags: { noGit, noInstall, importAlias, appRouter }, databaseProvider, } = await runCli(); From 4ed4df7c646996fbc13505740e75b2958a69f2a1 Mon Sep 17 00:00:00 2001 From: aidansunbury Date: Wed, 15 Jan 2025 13:43:12 -0800 Subject: [PATCH 10/25] move check to correct directory to actually run tests --- .github/workflows/e2e.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 7bb594b76d..572f095a15 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -59,6 +59,10 @@ jobs: - run: cd cli && pnpm start ../../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }} --noGit --CI --trpc=${{ matrix.trpc }} --tailwind=${{ matrix.tailwind }} --nextAuth=${{ matrix.nextAuth }} --prisma=${{ matrix.prisma }} --drizzle=${{ matrix.drizzle }} --appRouter=${{ matrix.appRouter }} --dbProvider=${{ matrix.dbType }} if: ${{ steps.matrix-valid.outputs.continue == 'true' }} # can't use default mysql string cause t3-env blocks that + + # WIP ensure that generated app passes formatting and linting checks + - run: pnpm format:check && pnpm check + - run: cd ../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }} && pnpm build if: ${{ steps.matrix-valid.outputs.continue == 'true' }} env: @@ -67,9 +71,6 @@ jobs: AUTH_DISCORD_SECRET: baz SKIP_ENV_VALIDATION: true - # WIP ensure that generated app passes formatting and linting checks - - run: pnpm format:check && pnpm check - build-t3-app-with-bun: runs-on: ubuntu-latest From af52d73998a66f2a969d320f7231025fe8bf13d3 Mon Sep 17 00:00:00 2001 From: aidansunbury Date: Wed, 15 Jan 2025 13:56:32 -0800 Subject: [PATCH 11/25] make sure we can format and lint --- .github/workflows/e2e.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 572f095a15..0990aed733 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -60,16 +60,14 @@ jobs: if: ${{ steps.matrix-valid.outputs.continue == 'true' }} # can't use default mysql string cause t3-env blocks that - # WIP ensure that generated app passes formatting and linting checks - - run: pnpm format:check && pnpm check - - - run: cd ../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }} && pnpm build + - run: cd ../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }} && pnpm build && pnpm format:check && pnpm check # This shouldn't have command not found if: ${{ steps.matrix-valid.outputs.continue == 'true' }} env: AUTH_SECRET: foo AUTH_DISCORD_ID: bar AUTH_DISCORD_SECRET: baz SKIP_ENV_VALIDATION: true + - run: pwd build-t3-app-with-bun: runs-on: ubuntu-latest From d27c29f5b2305235e9d96cf6b7c399f961bdeaea Mon Sep 17 00:00:00 2001 From: aidansunbury Date: Wed, 15 Jan 2025 14:09:27 -0800 Subject: [PATCH 12/25] run check and format in correct directory with eslint scaffolded --- .github/workflows/e2e.yml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 0990aed733..2d567635ac 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -56,18 +56,26 @@ jobs: # has to be scaffolded outside the CLI project so that no lint/tsconfig are leaking # through. this way it ensures that it is the app's configs that are being used # FIXME: this is a bit hacky, would rather have --packages=trpc,tailwind,... but not sure how to setup the matrix for that - - run: cd cli && pnpm start ../../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }} --noGit --CI --trpc=${{ matrix.trpc }} --tailwind=${{ matrix.tailwind }} --nextAuth=${{ matrix.nextAuth }} --prisma=${{ matrix.prisma }} --drizzle=${{ matrix.drizzle }} --appRouter=${{ matrix.appRouter }} --dbProvider=${{ matrix.dbType }} + - run: cd cli && pnpm start ../../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }} --noGit --CI --trpc=${{ matrix.trpc }} --tailwind=${{ matrix.tailwind }} --nextAuth=${{ matrix.nextAuth }} --prisma=${{ matrix.prisma }} --drizzle=${{ matrix.drizzle }} --appRouter=${{ matrix.appRouter }} --dbProvider=${{ matrix.dbType }} --eslint if: ${{ steps.matrix-valid.outputs.continue == 'true' }} # can't use default mysql string cause t3-env blocks that - - run: cd ../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }} && pnpm build && pnpm format:check && pnpm check # This shouldn't have command not found + - run: cd ../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }} && pnpm build + if: ${{ steps.matrix-valid.outputs.continue == 'true' }} + env: + AUTH_SECRET: foo + AUTH_DISCORD_ID: bar + AUTH_DISCORD_SECRET: baz + SKIP_ENV_VALIDATION: true + + # setup eslint correctly, and run it in correct directory + - run: cd ../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }} && pnpm format:check && pnpm check if: ${{ steps.matrix-valid.outputs.continue == 'true' }} env: AUTH_SECRET: foo AUTH_DISCORD_ID: bar AUTH_DISCORD_SECRET: baz SKIP_ENV_VALIDATION: true - - run: pwd build-t3-app-with-bun: runs-on: ubuntu-latest From 6ad3205de97cf25c0e3844fc92db8b54fe5e21b7 Mon Sep 17 00:00:00 2001 From: aidansunbury Date: Wed, 15 Jan 2025 15:31:56 -0800 Subject: [PATCH 13/25] format scaffolded project after creation and check in e2e --- .github/workflows/e2e.yml | 26 ++++++++++++++++++-------- cli/src/helpers/format.ts | 33 +++++++++++++++++++++++++++++++++ cli/src/index.ts | 5 +++-- 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 2d567635ac..1bfa5dc077 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -34,9 +34,10 @@ jobs: appRouter: ["true", "false"] drizzle: ["true", "false"] dbType: ["planetscale", "sqlite", "mysql", "postgres"] - # linter: ["eslint", "biome"] + eslint: ["true", "false"] + biome: ["true", "false"] - name: "Build and Start T3 App ${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }}" + name: "Build and Start T3 App ${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }}-${{matrix.eslint}}-${{matrix.biome}}" steps: - uses: actions/checkout@v4 with: @@ -45,7 +46,7 @@ jobs: - name: Check valid matrix id: matrix-valid run: | - echo "continue=${{ (matrix.prisma == 'false' || matrix.drizzle == 'false') && (matrix.drizzle == 'true' || matrix.prisma == 'true' || matrix.dbType == 'sqlite') }}" >> $GITHUB_OUTPUT + echo "continue=${{ (matrix.prisma == 'false' || matrix.drizzle == 'false') && (matrix.drizzle == 'true' || matrix.prisma == 'true' || matrix.dbType == 'sqlite') && (matrix.eslint == 'false' || matrix.biome == 'false') && (matrix.eslint == 'true' || matrix.biome == 'true')}}" >> $GITHUB_OUTPUT - uses: ./.github/actions/setup if: ${{ steps.matrix-valid.outputs.continue == 'true' }} @@ -56,11 +57,11 @@ jobs: # has to be scaffolded outside the CLI project so that no lint/tsconfig are leaking # through. this way it ensures that it is the app's configs that are being used # FIXME: this is a bit hacky, would rather have --packages=trpc,tailwind,... but not sure how to setup the matrix for that - - run: cd cli && pnpm start ../../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }} --noGit --CI --trpc=${{ matrix.trpc }} --tailwind=${{ matrix.tailwind }} --nextAuth=${{ matrix.nextAuth }} --prisma=${{ matrix.prisma }} --drizzle=${{ matrix.drizzle }} --appRouter=${{ matrix.appRouter }} --dbProvider=${{ matrix.dbType }} --eslint + - run: cd cli && pnpm start ../../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }} --noGit --CI --trpc=${{ matrix.trpc }} --tailwind=${{ matrix.tailwind }} --nextAuth=${{ matrix.nextAuth }} --prisma=${{ matrix.prisma }} --drizzle=${{ matrix.drizzle }} --appRouter=${{ matrix.appRouter }} --dbProvider=${{ matrix.dbType }} --eslint=${{ matrix.eslint }} --biome=${{ matrix.biome }} if: ${{ steps.matrix-valid.outputs.continue == 'true' }} # can't use default mysql string cause t3-env blocks that - - run: cd ../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }} && pnpm build + - run: cd ../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }}-${{matrix.eslint}}-${{matrix.biome}} && pnpm build if: ${{ steps.matrix-valid.outputs.continue == 'true' }} env: AUTH_SECRET: foo @@ -68,9 +69,18 @@ jobs: AUTH_DISCORD_SECRET: baz SKIP_ENV_VALIDATION: true - # setup eslint correctly, and run it in correct directory - - run: cd ../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }} && pnpm format:check && pnpm check - if: ${{ steps.matrix-valid.outputs.continue == 'true' }} + # Check formatting for eslint / prettier + - run: cd ../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }}-${{matrix.eslint}}-${{matrix.biome}} && pnpm format:check && pnpm check + if: ${{ steps.matrix-valid.outputs.continue == 'true' && matrix.eslint == 'true' }} + env: + AUTH_SECRET: foo + AUTH_DISCORD_ID: bar + AUTH_DISCORD_SECRET: baz + SKIP_ENV_VALIDATION: true + + # Check formatting for biome + - run: cd ../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }}-${{matrix.eslint}}-${{matrix.biome}} && pnpm check + if: ${{ steps.matrix-valid.outputs.continue == 'true' && matrix.biome == 'true' }} env: AUTH_SECRET: foo AUTH_DISCORD_ID: bar diff --git a/cli/src/helpers/format.ts b/cli/src/helpers/format.ts index e69de29bb2..37ee7ff4bb 100644 --- a/cli/src/helpers/format.ts +++ b/cli/src/helpers/format.ts @@ -0,0 +1,33 @@ +import chalk from "chalk"; +import { execa } from "execa"; +import ora from "ora"; + +import type { PackageManager } from "~/utils/getUserPkgManager.js"; +import { logger } from "~/utils/logger.js"; + +// Runs format and lint command to ensure created repository is tidy upon creation +export const formatProject = async ({ + pkgManager, + projectDir, + eslint, + biome, +}: { + pkgManager: PackageManager; + projectDir: string; + eslint: boolean; + biome: boolean; +}) => { + logger.info("Formatting project..."); + const spinner = ora("Running format command\n").start(); + + if (eslint) { + await execa(pkgManager, ["format:write"], { + cwd: projectDir, + }); + } else if (biome) { + await execa(pkgManager, ["check:unsafe"], { + cwd: projectDir, + }); + } + spinner.succeed(`${chalk.green("Successfully formatted project")}`); +}; diff --git a/cli/src/index.ts b/cli/src/index.ts index b8b420d32b..7015bfb7ca 100644 --- a/cli/src/index.ts +++ b/cli/src/index.ts @@ -14,6 +14,7 @@ import { getUserPkgManager } from "~/utils/getUserPkgManager.js"; import { logger } from "~/utils/logger.js"; import { parseNameAndPath } from "~/utils/parseNameAndPath.js"; import { renderTitle } from "~/utils/renderTitle.js"; +import { formatProject } from "./helpers/format.js"; import { installDependencies } from "./helpers/installDependencies.js"; import { getVersion } from "./utils/getT3Version.js"; import { @@ -38,7 +39,7 @@ const main = async () => { const { appName, packages, - flags: { noGit, noInstall, importAlias, appRouter }, + flags: { noGit, noInstall, importAlias, appRouter, eslint, biome }, databaseProvider, } = await runCli(); @@ -89,7 +90,7 @@ const main = async () => { await initializeGit(projectDir); } - // TODO run format command + await formatProject({ pkgManager, projectDir, eslint, biome }); await logNextSteps({ projectName: appDir, From 08173ced6eb8b8a1fa51e791be4cec17bcc9093b Mon Sep 17 00:00:00 2001 From: aidansunbury Date: Wed, 15 Jan 2025 15:34:19 -0800 Subject: [PATCH 14/25] lint fix --- cli/src/helpers/format.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/helpers/format.ts b/cli/src/helpers/format.ts index 37ee7ff4bb..d0ed54a0b8 100644 --- a/cli/src/helpers/format.ts +++ b/cli/src/helpers/format.ts @@ -2,7 +2,7 @@ import chalk from "chalk"; import { execa } from "execa"; import ora from "ora"; -import type { PackageManager } from "~/utils/getUserPkgManager.js"; +import { type PackageManager } from "~/utils/getUserPkgManager.js"; import { logger } from "~/utils/logger.js"; // Runs format and lint command to ensure created repository is tidy upon creation From 9cfd0d2ad3fc995a58138f5a5d6f12821f297142 Mon Sep 17 00:00:00 2001 From: aidansunbury Date: Wed, 15 Jan 2025 15:52:03 -0800 Subject: [PATCH 15/25] revert e2e tests to ensure less than 256 matrix variations --- .github/workflows/e2e.yml | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 1bfa5dc077..7a58f996b6 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -34,10 +34,8 @@ jobs: appRouter: ["true", "false"] drizzle: ["true", "false"] dbType: ["planetscale", "sqlite", "mysql", "postgres"] - eslint: ["true", "false"] - biome: ["true", "false"] - name: "Build and Start T3 App ${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }}-${{matrix.eslint}}-${{matrix.biome}}" + name: "Build and Start T3 App ${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }}" steps: - uses: actions/checkout@v4 with: @@ -61,7 +59,7 @@ jobs: if: ${{ steps.matrix-valid.outputs.continue == 'true' }} # can't use default mysql string cause t3-env blocks that - - run: cd ../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }}-${{matrix.eslint}}-${{matrix.biome}} && pnpm build + - run: cd ../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }} && pnpm build if: ${{ steps.matrix-valid.outputs.continue == 'true' }} env: AUTH_SECRET: foo @@ -69,24 +67,6 @@ jobs: AUTH_DISCORD_SECRET: baz SKIP_ENV_VALIDATION: true - # Check formatting for eslint / prettier - - run: cd ../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }}-${{matrix.eslint}}-${{matrix.biome}} && pnpm format:check && pnpm check - if: ${{ steps.matrix-valid.outputs.continue == 'true' && matrix.eslint == 'true' }} - env: - AUTH_SECRET: foo - AUTH_DISCORD_ID: bar - AUTH_DISCORD_SECRET: baz - SKIP_ENV_VALIDATION: true - - # Check formatting for biome - - run: cd ../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }}-${{matrix.eslint}}-${{matrix.biome}} && pnpm check - if: ${{ steps.matrix-valid.outputs.continue == 'true' && matrix.biome == 'true' }} - env: - AUTH_SECRET: foo - AUTH_DISCORD_ID: bar - AUTH_DISCORD_SECRET: baz - SKIP_ENV_VALIDATION: true - build-t3-app-with-bun: runs-on: ubuntu-latest From 8415dfa42d350d6043c137c7b3176cf40d2c9adc Mon Sep 17 00:00:00 2001 From: aidansunbury Date: Wed, 15 Jan 2025 15:53:22 -0800 Subject: [PATCH 16/25] remove extra parts of e2e --- .github/workflows/e2e.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 7a58f996b6..0d1b84dd5c 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -44,7 +44,7 @@ jobs: - name: Check valid matrix id: matrix-valid run: | - echo "continue=${{ (matrix.prisma == 'false' || matrix.drizzle == 'false') && (matrix.drizzle == 'true' || matrix.prisma == 'true' || matrix.dbType == 'sqlite') && (matrix.eslint == 'false' || matrix.biome == 'false') && (matrix.eslint == 'true' || matrix.biome == 'true')}}" >> $GITHUB_OUTPUT + echo "continue=${{ (matrix.prisma == 'false' || matrix.drizzle == 'false') && (matrix.drizzle == 'true' || matrix.prisma == 'true' || matrix.dbType == 'sqlite')}}" >> $GITHUB_OUTPUT - uses: ./.github/actions/setup if: ${{ steps.matrix-valid.outputs.continue == 'true' }} @@ -55,7 +55,7 @@ jobs: # has to be scaffolded outside the CLI project so that no lint/tsconfig are leaking # through. this way it ensures that it is the app's configs that are being used # FIXME: this is a bit hacky, would rather have --packages=trpc,tailwind,... but not sure how to setup the matrix for that - - run: cd cli && pnpm start ../../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }} --noGit --CI --trpc=${{ matrix.trpc }} --tailwind=${{ matrix.tailwind }} --nextAuth=${{ matrix.nextAuth }} --prisma=${{ matrix.prisma }} --drizzle=${{ matrix.drizzle }} --appRouter=${{ matrix.appRouter }} --dbProvider=${{ matrix.dbType }} --eslint=${{ matrix.eslint }} --biome=${{ matrix.biome }} + - run: cd cli && pnpm start ../../ci-${{ matrix.trpc }}-${{ matrix.tailwind }}-${{ matrix.nextAuth }}-${{ matrix.prisma }}-${{ matrix.drizzle}}-${{ matrix.appRouter }}-${{ matrix.dbType }} --noGit --CI --trpc=${{ matrix.trpc }} --tailwind=${{ matrix.tailwind }} --nextAuth=${{ matrix.nextAuth }} --prisma=${{ matrix.prisma }} --drizzle=${{ matrix.drizzle }} --appRouter=${{ matrix.appRouter }} --dbProvider=${{ matrix.dbType }} --eslint if: ${{ steps.matrix-valid.outputs.continue == 'true' }} # can't use default mysql string cause t3-env blocks that From 63534b45a63e312d60ff030f923e35786c87dd2b Mon Sep 17 00:00:00 2001 From: aidansunbury Date: Wed, 15 Jan 2025 15:54:27 -0800 Subject: [PATCH 17/25] add back space --- .github/workflows/e2e.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 0d1b84dd5c..fb2a397aea 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -44,7 +44,7 @@ jobs: - name: Check valid matrix id: matrix-valid run: | - echo "continue=${{ (matrix.prisma == 'false' || matrix.drizzle == 'false') && (matrix.drizzle == 'true' || matrix.prisma == 'true' || matrix.dbType == 'sqlite')}}" >> $GITHUB_OUTPUT + echo "continue=${{ (matrix.prisma == 'false' || matrix.drizzle == 'false') && (matrix.drizzle == 'true' || matrix.prisma == 'true' || matrix.dbType == 'sqlite') }}" >> $GITHUB_OUTPUT - uses: ./.github/actions/setup if: ${{ steps.matrix-valid.outputs.continue == 'true' }} From 2ce9ea55f079090d64e1bdc07d1e34533a9ff515 Mon Sep 17 00:00:00 2001 From: aidansunbury Date: Wed, 15 Jan 2025 17:15:08 -0800 Subject: [PATCH 18/25] added biome.jsonc suggestions --- cli/src/index.ts | 4 ++-- cli/template/extras/config/biome.jsonc | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/cli/src/index.ts b/cli/src/index.ts index 7015bfb7ca..dee8eb0291 100644 --- a/cli/src/index.ts +++ b/cli/src/index.ts @@ -86,12 +86,12 @@ const main = async () => { await installDependencies({ projectDir }); } + await formatProject({ pkgManager, projectDir, eslint, biome }); + if (!noGit) { await initializeGit(projectDir); } - await formatProject({ pkgManager, projectDir, eslint, biome }); - await logNextSteps({ projectName: appDir, packages: usePackages, diff --git a/cli/template/extras/config/biome.jsonc b/cli/template/extras/config/biome.jsonc index adb632dfa2..6c718cf8fd 100644 --- a/cli/template/extras/config/biome.jsonc +++ b/cli/template/extras/config/biome.jsonc @@ -1,25 +1,25 @@ { "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", "vcs": { - "enabled": false, + "enabled": true, "clientKind": "git", - "useIgnoreFile": false + "useIgnoreFile": true, }, "files": { "ignoreUnknown": false, "ignore": [] }, - "formatter": { "enabled": true, "indentStyle": "space", "indentWidth": 2 }, + "formatter": { "enabled": true }, "organizeImports": { "enabled": true }, "linter": { "enabled": true, - "rules": { + "rules": { "nursery": { "useSortedClasses": { "level": "error", "options": { - "functions": ["clsx", "cva", "cn"] - } - } - }, - "recommended": true } + "functions": ["clsx", "cva", "cn"], + }, + }, + }, + "recommended": true, + }, }, - "javascript": { "formatter": { "quoteStyle": "double" } } -} \ No newline at end of file +} From 315a9cea4b70975e60c1729243c715a3a703ea56 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Sat, 25 Jan 2025 15:27:51 +0100 Subject: [PATCH 19/25] Update biome.jsonc --- cli/template/extras/config/biome.jsonc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cli/template/extras/config/biome.jsonc b/cli/template/extras/config/biome.jsonc index 6c718cf8fd..1bd56f81a4 100644 --- a/cli/template/extras/config/biome.jsonc +++ b/cli/template/extras/config/biome.jsonc @@ -13,7 +13,8 @@ "rules": { "nursery": { "useSortedClasses": { - "level": "error", + "level": "warn", + "fix": "safe", "options": { "functions": ["clsx", "cva", "cn"], }, From d9f378841ded5f8b8bda35bd748fef4fd3c2e9a6 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Sat, 25 Jan 2025 15:32:53 +0100 Subject: [PATCH 20/25] fix lint warnings in biome config --- cli/template/extras/config/biome.jsonc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cli/template/extras/config/biome.jsonc b/cli/template/extras/config/biome.jsonc index 1bd56f81a4..9aeafccac4 100644 --- a/cli/template/extras/config/biome.jsonc +++ b/cli/template/extras/config/biome.jsonc @@ -3,7 +3,7 @@ "vcs": { "enabled": true, "clientKind": "git", - "useIgnoreFile": true, + "useIgnoreFile": true }, "files": { "ignoreUnknown": false, "ignore": [] }, "formatter": { "enabled": true }, @@ -16,11 +16,11 @@ "level": "warn", "fix": "safe", "options": { - "functions": ["clsx", "cva", "cn"], - }, - }, + "functions": ["clsx", "cva", "cn"] + } + } }, - "recommended": true, - }, - }, + "recommended": true + } + } } From 4d681596c6cd6ac19ba59fdb5a232f4eb45d8d83 Mon Sep 17 00:00:00 2001 From: aidansunbury Date: Wed, 29 Jan 2025 00:40:03 -0800 Subject: [PATCH 21/25] fixed issue with eslint / biome only being run when using flags --- cli/src/helpers/format.ts | 2 +- cli/src/index.ts | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/cli/src/helpers/format.ts b/cli/src/helpers/format.ts index d0ed54a0b8..e7488ab7a2 100644 --- a/cli/src/helpers/format.ts +++ b/cli/src/helpers/format.ts @@ -17,7 +17,7 @@ export const formatProject = async ({ eslint: boolean; biome: boolean; }) => { - logger.info("Formatting project..."); + logger.info(`Formatting project with ${eslint ? "eslint" : "biome"}...`); const spinner = ora("Running format command\n").start(); if (eslint) { diff --git a/cli/src/index.ts b/cli/src/index.ts index dee8eb0291..0ffd1e7d5d 100644 --- a/cli/src/index.ts +++ b/cli/src/index.ts @@ -39,7 +39,7 @@ const main = async () => { const { appName, packages, - flags: { noGit, noInstall, importAlias, appRouter, eslint, biome }, + flags: { noGit, noInstall, importAlias, appRouter }, databaseProvider, } = await runCli(); @@ -86,7 +86,12 @@ const main = async () => { await installDependencies({ projectDir }); } - await formatProject({ pkgManager, projectDir, eslint, biome }); + await formatProject({ + pkgManager, + projectDir, + eslint: packages.includes("eslint"), + biome: packages.includes("biome"), + }); if (!noGit) { await initializeGit(projectDir); From 38e9eabb2a40c715a16eaa4dcf72f14525735aed Mon Sep 17 00:00:00 2001 From: aidansunbury Date: Wed, 29 Jan 2025 10:39:46 -0800 Subject: [PATCH 22/25] add e2e test to ensure generated project passed linting and formatting checks with chosen linter --- .github/workflows/e2e.yml | 44 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index fb2a397aea..c8a2d1c774 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -67,6 +67,50 @@ jobs: AUTH_DISCORD_SECRET: baz SKIP_ENV_VALIDATION: true + check-well-formatted: + runs-on: ubuntu-latest + + strategy: + matrix: + eslint: ["true", "false"] + biome: ["true", "false"] + + name: "Build and Start T3 App" + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Check valid matrix + id: matrix-valid + run: | + echo "continue=${{ (matrix.eslint == 'false' || matrix.biome == 'false') && (matrix.biome == 'true' || matrix.eslint == 'true') }}" >> $GITHUB_OUTPUT + + - uses: ./.github/actions/setup + if: ${{ steps.matrix-valid.outputs.continue == 'true' }} + + - run: pnpm turbo --filter=create-t3-app build + if: ${{ steps.matrix-valid.outputs.continue == 'true' }} + + - run: cd cli && pnpm start ../../ci-format-${{ matrix.eslint }}-${{ matrix.biome }} --noGit --CI --trpc --tailwind --nextAuth --drizzle --appRouter --dbProvider=postgres --eslint=${{ matrix.eslint }} --biome=${{ matrix.biome }} + if: ${{ steps.matrix-valid.outputs.continue == 'true' }} + + - run: cd ../ci-format-${{ matrix.eslint }}-${{ matrix.biome }} && pnpm build + if: ${{ steps.matrix-valid.outputs.continue == 'true' }} + env: + AUTH_SECRET: foo + AUTH_DISCORD_ID: bar + AUTH_DISCORD_SECRET: baz + SKIP_ENV_VALIDATION: true + + # Run biome check + - run: cd ../ci-format-${{ matrix.eslint }}-${{ matrix.biome }} && pnpm check + if: ${{ steps.matrix-valid.outputs.continue == 'true' && matrix.biome == 'true' }} + + # Check linting and formatting with eslint and prettier + - run: cd ../ci-format-${{ matrix.eslint }}-${{ matrix.biome }} && pnpm lint && pnpm format:check + if: ${{ steps.matrix-valid.outputs.continue == 'true' && matrix.eslint == 'true' }} + build-t3-app-with-bun: runs-on: ubuntu-latest From 46727d5977deab1c6eb05a4cdb0bd3e4687920bf Mon Sep 17 00:00:00 2001 From: aidansunbury Date: Wed, 29 Jan 2025 10:53:52 -0800 Subject: [PATCH 23/25] added env to eslint check to pass next-lint --- .github/workflows/e2e.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index c8a2d1c774..591034abc7 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -110,6 +110,11 @@ jobs: # Check linting and formatting with eslint and prettier - run: cd ../ci-format-${{ matrix.eslint }}-${{ matrix.biome }} && pnpm lint && pnpm format:check if: ${{ steps.matrix-valid.outputs.continue == 'true' && matrix.eslint == 'true' }} + env: + AUTH_SECRET: foo + AUTH_DISCORD_ID: bar + AUTH_DISCORD_SECRET: baz + SKIP_ENV_VALIDATION: true build-t3-app-with-bun: runs-on: ubuntu-latest From 9bbf1abcc4ed2beca85695e8fbc1ca6873003e9c Mon Sep 17 00:00:00 2001 From: aidansunbury Date: Wed, 29 Jan 2025 14:40:04 -0800 Subject: [PATCH 24/25] added eslint as a default package so that bun e2e test passes --- cli/src/cli/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/cli/index.ts b/cli/src/cli/index.ts index 4a0e236a37..013c4c36ea 100644 --- a/cli/src/cli/index.ts +++ b/cli/src/cli/index.ts @@ -52,7 +52,7 @@ interface CliResults { const defaultOptions: CliResults = { appName: DEFAULT_APP_NAME, - packages: ["nextAuth", "prisma", "tailwind", "trpc"], + packages: ["nextAuth", "prisma", "tailwind", "trpc", "eslint"], flags: { noGit: false, noInstall: false, From e563aec1cd9962311eef20e1e158f8211be8a373 Mon Sep 17 00:00:00 2001 From: aidansunbury Date: Wed, 29 Jan 2025 16:38:17 -0800 Subject: [PATCH 25/25] modify bun test to check for bun.lock instead of bun.lockb --- .github/workflows/e2e.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 591034abc7..5c43580b12 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -139,7 +139,7 @@ jobs: - name: We should have a Bun lockfile run: | - if [ ! -f "../ci-bun/bun.lockb" ]; then + if [ ! -f "../ci-bun/bun.lock" ]; then echo "Bun lockfile not found" exit 1 fi