Skip to content

Commit

Permalink
feat: use typescript-eslint's recommended-requiring-type-checking (#1036
Browse files Browse the repository at this point in the history
)
  • Loading branch information
JoshuaKGoldberg committed Jan 7, 2023
1 parent 2fcde4a commit c5ca65e
Show file tree
Hide file tree
Showing 31 changed files with 139 additions and 91 deletions.
5 changes: 5 additions & 0 deletions .changeset/dry-items-tie.md
@@ -0,0 +1,5 @@
---
"create-t3-app": minor
---

use typescript-eslint's recommended-required-type-checking
39 changes: 29 additions & 10 deletions .eslintrc.cjs
Expand Up @@ -2,28 +2,47 @@ module.exports = {
parser: "@typescript-eslint/parser", // Specifies the ESLint parser
plugins: ["turbo"],
extends: [
"plugin:@typescript-eslint/recommended", // Uses the recommended rules from the @typescript-eslint/eslint-plugin
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
],
overrides: [
{
extends: [
"plugin:@typescript-eslint/recommended-requiring-type-checking",
],
files: ["*.ts", "*.tsx"],
parserOptions: {
project: "tsconfig.json",
},
rules: {
"@typescript-eslint/require-await": "off",
"@typescript-eslint/restrict-plus-operands": "off",
"@typescript-eslint/restrict-template-expressions": "off",

// These rules are only disabled because we hit a bug in linting.
// See https://github.com/t3-oss/create-t3-app/pull/1036#discussion_r1060505136
// If you still see the bug once TypeScript@5 is used, please let typescript-eslint know!
"@typescript-eslint/no-unsafe-argument": "off",
"@typescript-eslint/no-unsafe-assignment": "off",
"@typescript-eslint/no-unsafe-call": "off",
"@typescript-eslint/no-unsafe-call": "off",
"@typescript-eslint/no-unsafe-member-access": "off",
"@typescript-eslint/no-unsafe-return": "off",
},
},
],
parserOptions: {
ecmaVersion: "latest", // Allows for the parsing of modern ECMAScript features
sourceType: "module", // Allows for the use of import
project: "./tsconfig.eslint.json", // Allows for the use of rules which require parserServices to be generated
},
rules: {
// Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-floating-promises": "error",
"prettier/prettier": ["error", { endOfLine: "auto" }],
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_",
},
{ argsIgnorePattern: "^_", destructuredArrayIgnorePattern: "^_" },
],
},
};
1 change: 0 additions & 1 deletion .gitignore
Expand Up @@ -40,7 +40,6 @@ yarn-error.log*
.nuxt/
tmp/
temp/
.eslintcache
.docusaurus

# MAC
Expand Down
1 change: 1 addition & 0 deletions .turbo-cookie
@@ -0,0 +1 @@
cookie
2 changes: 1 addition & 1 deletion cli/package.json
Expand Up @@ -31,7 +31,7 @@
"dev": "tsup --watch",
"clean": "rm -rf dist .turbo node_modules",
"start": "node dist/index.js",
"lint": "eslint src --cache --cache-strategy content",
"lint": "eslint src --report-unused-disable-directives",
"format": "prettier --write --plugin-search-dir=. **/*.{cjs,mjs,ts,tsx,md,json} --ignore-path ../.gitignore",
"format:check": "prettier --check --plugin-search-dir=. **/*.{cjs,mjs,ts,tsx,md,json} --ignore-path ../.gitignore",
"release": "changeset version",
Expand Down
2 changes: 1 addition & 1 deletion cli/src/cli/index.ts
Expand Up @@ -176,7 +176,7 @@ export const runCli = async () => {
} catch (err) {
// If the user is not calling create-t3-app from an interactive terminal, inquirer will throw an error with isTTYError = true
// If this happens, we catch the error, tell the user what has happened, and then continue to run the program with a default t3 app
// eslint-disable-next-line -- Otherwise we have to do some fancy namespace extension logic on the Error type which feels overkill for one line
// Otherwise we have to do some fancy namespace extension logic on the Error type which feels overkill for one line
if (err instanceof Error && (err as any).isTTYError) {
logger.warn(
`${CREATE_T3_APP} needs an interactive terminal to provide options`,
Expand Down
30 changes: 30 additions & 0 deletions cli/src/installers/dependencyVersionMap.ts
@@ -0,0 +1,30 @@
/*
* This maps the necessary packages to a version.
* This improves performance significantly over fetching it from the npm registry.
*/
export const dependencyVersionMap = {
// NextAuth.js
"next-auth": "^4.18.7",
"@next-auth/prisma-adapter": "^1.0.5",

// Prisma
prisma: "^4.8.0",
"@prisma/client": "^4.8.0",

// TailwindCSS
tailwindcss: "^3.2.0",
autoprefixer: "^10.4.7",
postcss: "^8.4.14",
prettier: "^2.8.1",
"prettier-plugin-tailwindcss": "^0.2.1",
"@types/prettier": "^2.7.2",

// tRPC
"@trpc/client": "^10.7.0",
"@trpc/server": "^10.7.0",
"@trpc/react-query": "^10.7.0",
"@trpc/next": "^10.7.0",
"@tanstack/react-query": "^4.20.0",
superjson: "1.9.1",
} as const;
export type AvailableDependencies = keyof typeof dependencyVersionMap;
31 changes: 0 additions & 31 deletions cli/src/installers/index.ts
Expand Up @@ -16,37 +16,6 @@ export const availablePackages = [
] as const;
export type AvailablePackages = typeof availablePackages[number];

/*
* This maps the necessary packages to a version.
* This improves performance significantly over fetching it from the npm registry.
*/
export const dependencyVersionMap = {
// NextAuth.js
"next-auth": "^4.18.7",
"@next-auth/prisma-adapter": "^1.0.5",

// Prisma
prisma: "^4.8.0",
"@prisma/client": "^4.8.0",

// TailwindCSS
tailwindcss: "^3.2.0",
autoprefixer: "^10.4.7",
postcss: "^8.4.14",
prettier: "^2.8.1",
"prettier-plugin-tailwindcss": "^0.2.1",
"@types/prettier": "^2.7.2",

// tRPC
"@trpc/client": "^10.7.0",
"@trpc/server": "^10.7.0",
"@trpc/react-query": "^10.7.0",
"@trpc/next": "^10.7.0",
"@tanstack/react-query": "^4.20.0",
superjson: "1.9.1",
} as const;
export type AvailableDependencies = keyof typeof dependencyVersionMap;

export interface InstallerOptions {
projectDir: string;
pkgManager: PackageManager;
Expand Down
3 changes: 2 additions & 1 deletion cli/src/installers/nextAuth.ts
@@ -1,4 +1,5 @@
import type { Installer, AvailableDependencies } from "~/installers/index.js";
import type { Installer } from "~/installers/index.js";
import { AvailableDependencies } from "~/installers/dependencyVersionMap.js";
import path from "path";
import fs from "fs-extra";
import { PKG_ROOT } from "~/consts.js";
Expand Down
2 changes: 1 addition & 1 deletion cli/src/installers/prisma.ts
Expand Up @@ -33,7 +33,7 @@ export const prismaInstaller: Installer = ({ projectDir, packages }) => {
const packageJsonPath = path.join(projectDir, "package.json");

const packageJsonContent = fs.readJSONSync(packageJsonPath) as PackageJson;
packageJsonContent.scripts!.postinstall = "prisma generate"; //eslint-disable-line @typescript-eslint/no-non-null-assertion
packageJsonContent.scripts!.postinstall = "prisma generate";

fs.copySync(schemaSrc, schemaDest);
fs.copySync(clientSrc, clientDest);
Expand Down
4 changes: 1 addition & 3 deletions cli/src/utils/addPackageDependency.ts
Expand Up @@ -4,7 +4,7 @@ import { type PackageJson } from "type-fest";
import {
dependencyVersionMap,
AvailableDependencies,
} from "~/installers/index.js";
} from "~/installers/dependencyVersionMap.js";
import sortPackageJson from "sort-package-json";

export const addPackageDependency = (opts: {
Expand All @@ -22,10 +22,8 @@ export const addPackageDependency = (opts: {
const version = dependencyVersionMap[pkgName];

if (devMode) {
//eslint-disable-next-line @typescript-eslint/no-non-null-assertion
pkgJson.devDependencies![pkgName] = version;
} else {
//eslint-disable-next-line @typescript-eslint/no-non-null-assertion
pkgJson.dependencies![pkgName] = version;
}
});
Expand Down
7 changes: 6 additions & 1 deletion cli/src/utils/renderVersionWarning.ts
Expand Up @@ -37,6 +37,11 @@ export const renderVersionWarning = (npmVersion: string) => {
* https://github.com/facebook/create-react-app/blob/main/packages/create-react-app/LICENSE
*/
import https from "https";

type DistTagsBody = {
latest: string;
};

function checkForLatestVersion(): Promise<string> {
return new Promise((resolve, reject) => {
https
Expand All @@ -47,7 +52,7 @@ function checkForLatestVersion(): Promise<string> {
let body = "";
res.on("data", (data) => (body += data));
res.on("end", () => {
resolve(JSON.parse(body).latest);
resolve((JSON.parse(body) as DistTagsBody).latest);
});
} else {
reject();
Expand Down
11 changes: 11 additions & 0 deletions cli/template/base/.eslintrc.json
@@ -1,4 +1,15 @@
{
"overrides": [
{
"extends": [
"plugin:@typescript-eslint/recommended-requiring-type-checking"
],
"files": ["*.ts", "*.tsx"],
"parserOptions": {
"project": "tsconfig.json"
}
}
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json"
Expand Down
4 changes: 3 additions & 1 deletion cli/template/extras/src/pages/api/trpc/[trpc].ts
Expand Up @@ -11,7 +11,9 @@ export default createNextApiHandler({
onError:
env.NODE_ENV === "development"
? ({ path, error }) => {
console.error(`❌ tRPC failed on ${path}: ${error}`);
console.error(
`❌ tRPC failed on ${path ?? "<no-path>"}: ${error.message}`,
);
}
: undefined,
});
2 changes: 1 addition & 1 deletion cli/template/extras/src/pages/index/with-auth-trpc-tw.tsx
Expand Up @@ -74,7 +74,7 @@ const AuthShowcase: React.FC = () => {
</p>
<button
className="rounded-full bg-white/10 px-10 py-3 font-semibold text-white no-underline transition hover:bg-white/20"
onClick={sessionData ? () => signOut() : () => signIn()}
onClick={sessionData ? () => void signOut() : () => void signIn()}
>
{sessionData ? "Sign out" : "Sign in"}
</button>
Expand Down
2 changes: 1 addition & 1 deletion cli/template/extras/src/pages/index/with-auth-trpc.tsx
Expand Up @@ -75,7 +75,7 @@ const AuthShowcase: React.FC = () => {
</p>
<button
className={styles.loginButton}
onClick={sessionData ? () => signOut() : () => signIn()}
onClick={sessionData ? () => void signOut() : () => void signIn()}
>
{sessionData ? "Sign out" : "Sign in"}
</button>
Expand Down
6 changes: 3 additions & 3 deletions cli/template/extras/src/server/api/trpc/base.ts
Expand Up @@ -32,7 +32,7 @@ type CreateContextOptions = Record<string, never>;
* - trpc's `createSSGHelpers` where we don't have req/res
* @see https://create.t3.gg/en/usage/trpc#-servertrpccontextts
*/
const createInnerTRPCContext = async (_opts: CreateContextOptions) => {
const createInnerTRPCContext = (_opts: CreateContextOptions) => {
return {};
};

Expand All @@ -41,8 +41,8 @@ const createInnerTRPCContext = async (_opts: CreateContextOptions) => {
* process every request that goes through your tRPC endpoint
* @see https://trpc.io/docs/context
*/
export const createTRPCContext = async (_opts: CreateNextContextOptions) => {
return await createInnerTRPCContext({});
export const createTRPCContext = (_opts: CreateNextContextOptions) => {
return createInnerTRPCContext({});
};

/**
Expand Down
4 changes: 2 additions & 2 deletions cli/template/extras/src/server/api/trpc/with-auth-prisma.ts
Expand Up @@ -35,7 +35,7 @@ type CreateContextOptions = {
* - trpc's `createSSGHelpers` where we don't have req/res
* @see https://create.t3.gg/en/usage/trpc#-servertrpccontextts
*/
const createInnerTRPCContext = async (opts: CreateContextOptions) => {
const createInnerTRPCContext = (opts: CreateContextOptions) => {
return {
session: opts.session,
prisma,
Expand All @@ -53,7 +53,7 @@ export const createTRPCContext = async (opts: CreateNextContextOptions) => {
// Get the session from the server using the unstable_getServerSession wrapper function
const session = await getServerAuthSession({ req, res });

return await createInnerTRPCContext({
return createInnerTRPCContext({
session,
});
};
Expand Down
4 changes: 2 additions & 2 deletions cli/template/extras/src/server/api/trpc/with-auth.ts
Expand Up @@ -34,7 +34,7 @@ type CreateContextOptions = {
* - trpc's `createSSGHelpers` where we don't have req/res
* @see https://create.t3.gg/en/usage/trpc#-servertrpccontextts
*/
const createInnerTRPCContext = async (opts: CreateContextOptions) => {
const createInnerTRPCContext = (opts: CreateContextOptions) => {
return {
session: opts.session,
};
Expand All @@ -51,7 +51,7 @@ export const createTRPCContext = async (opts: CreateNextContextOptions) => {
// Get the session from the server using the unstable_getServerSession wrapper function
const session = await getServerAuthSession({ req, res });

return await createInnerTRPCContext({
return createInnerTRPCContext({
session,
});
};
Expand Down
6 changes: 3 additions & 3 deletions cli/template/extras/src/server/api/trpc/with-prisma.ts
Expand Up @@ -31,7 +31,7 @@ type CreateContextOptions = Record<string, never>;
* - trpc's `createSSGHelpers` where we don't have req/res
* @see https://create.t3.gg/en/usage/trpc#-servertrpccontextts
*/
const createInnerTRPCContext = async (_opts: CreateContextOptions) => {
const createInnerTRPCContext = (_opts: CreateContextOptions) => {
return {
prisma,
};
Expand All @@ -42,8 +42,8 @@ const createInnerTRPCContext = async (_opts: CreateContextOptions) => {
* process every request that goes through your tRPC endpoint
* @link https://trpc.io/docs/context
*/
export const createTRPCContext = async (_opts: CreateNextContextOptions) => {
return await createInnerTRPCContext({});
export const createTRPCContext = (_opts: CreateNextContextOptions) => {
return createInnerTRPCContext({});
};

/**
Expand Down
1 change: 1 addition & 0 deletions tsconfig.eslint.json
@@ -1,4 +1,5 @@
{
"extends": "./tsconfig.json",
"include": [".eslintrc.cjs", "**/*"],
"exclude": ["node_modules"]
}
4 changes: 1 addition & 3 deletions www/.eslintrc.cjs
Expand Up @@ -35,13 +35,11 @@ module.exports = {
{
files: ["*.ts", "*.tsx"],
parser: "@typescript-eslint/parser",
extends: ["plugin:@typescript-eslint/recommended"],
rules: {
"@typescript-eslint/no-unused-vars": [
"no-unused-vars": [
"error",
{ argsIgnorePattern: "^_", destructuredArrayIgnorePattern: "^_" },
],
"@typescript-eslint/no-non-null-assertion": "off",
},
},
],
Expand Down
2 changes: 1 addition & 1 deletion www/package.json
Expand Up @@ -10,7 +10,7 @@
"clean": "rm -rf node_modules .turbo dist .eslintcache",
"format": "prettier --write --plugin-search-dir=. **/*.{cjs,mjs,ts,tsx,md,json,astro} --ignore-path ../.gitignore",
"format:check": "prettier --check --plugin-search-dir=. **/*.{cjs,mjs,ts,tsx,md,json,astro} --ignore-path ../.gitignore",
"lint": "eslint src --cache --cache-strategy content",
"lint": "eslint src --report-unused-disable-directives",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
Expand Down
9 changes: 2 additions & 7 deletions www/src/components/docs/breadCrumbs.tsx
@@ -1,18 +1,13 @@
import clsx from "clsx";
import {
KnownLanguageCode,
SIDEBAR,
SIDEBAR_HEADER_MAP,
type OuterHeaders,
} from "../../config";
import { SIDEBAR, SIDEBAR_HEADER_MAP, type OuterHeaders } from "../../config";
import { getIsRtlFromLangCode, getLanguageFromURL } from "../../languages";

type SlugType = "" | "usage" | "deployment";
type Entry = { text: string; link: string };

export default function BreadCrumbs() {
const lang = getLanguageFromURL(window.location.href);
const isRtl = getIsRtlFromLangCode((lang ?? "en") as KnownLanguageCode);
const isRtl = getIsRtlFromLangCode(lang ?? "en");
const slugToEntryPath = (slug: SlugType) => {
switch (slug) {
case "":
Expand Down

1 comment on commit c5ca65e

@vercel
Copy link

@vercel vercel bot commented on c5ca65e Jan 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.