diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 54f52f9ce..9d116a3e5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: strategy: fail-fast: true matrix: - script: ["format", "lint", "typecheck:ci"] + script: ["format", "lint:ci", "typecheck:ci"] steps: - name: Checkout repo diff --git a/contentlayer.config.ts b/contentlayer.config.ts index 1c3a39456..3958c85a1 100644 --- a/contentlayer.config.ts +++ b/contentlayer.config.ts @@ -4,6 +4,7 @@ import remarkGfm from "remark-gfm" import rehypeMdxCodeProps from "rehype-mdx-code-props" import emoji from "remark-emoji" import * as sidebar from "./src/components/Menu/MenuLinks" +import type { Pages } from "./src/types/types" export const Doc = defineDocumentType(() => ({ name: "Doc", @@ -33,13 +34,22 @@ export const Doc = defineDocumentType(() => ({ type: "string", resolve: (doc) => doc._raw.flattenedPath.split("/").slice(1).join("/"), }, + + /** + * Can't define value different from primitives, so hardcoding the correct type + * @see https://github.com/contentlayerdev/contentlayer/issues/149 + */ segment: { - type: "list", + type: "string[]" as "list", resolve: (doc) => doc._raw.flattenedPath.split("/"), }, pages: { - type: "list", - resolve: (doc) => sidebar[doc.sidebar] ?? [], + type: "json", + resolve: (doc) => { + // added explicit type casting to keep track of this data structure + // in case in the future contentlayer will support values different than primitives + return sidebar[doc.sidebar] as unknown as Pages + }, }, }, })) diff --git a/eslint.config.mjs b/eslint.config.mjs index d4767491e..d56f1e8fd 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -9,7 +9,8 @@ const compat = new FlatCompat({ }) export default tseslint.config( - tseslint.configs.recommended, + tseslint.configs.recommendedTypeChecked, + ...compat.config({ extends: ["next"], rules: { @@ -30,17 +31,37 @@ export default tseslint.config( "@next/next/no-img-element": "off", }, }), + // @ts-expect-error eslintPluginReact.configs.flat, but runtime is always defined eslintPluginReact.configs.flat["jsx-runtime"], + { linterOptions: { reportUnusedDisableDirectives: "error", }, + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, + }, rules: { // typescript "@typescript-eslint/explicit-function-return-type": "off", - "@typescript-eslint/interface-name-prefix": "off", "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/interface-name-prefix": "off", + "@typescript-eslint/no-floating-promises": "off", + "@typescript-eslint/restrict-template-expressions": [ + "error", + { + allowAny: false, + allowBoolean: false, + allowNever: false, + allowNullish: false, + allowNumber: true, + allowRegExp: false, + }, + ], }, } ) diff --git a/next.config.ts b/next.config.ts index 3e4956cd4..5d589531d 100644 --- a/next.config.ts +++ b/next.config.ts @@ -3,7 +3,17 @@ import { withContentlayer } from "next-contentlayer" import withBundleAnalyzer from "@next/bundle-analyzer" const nextConfig: NextConfig = { + eslint: { + /** + * Now eslint requires typecheck so we have to run build before executing lint + * These check are performed via `.github/workflows/ci.yml` action + * + * @see https://github.com/react-hook-form/documentation/pull/1107 + */ + ignoreDuringBuilds: true, + }, typescript: { + /** @see `eslint.ignoreDuringBuilds` comment */ ignoreBuildErrors: true, }, reactStrictMode: true, diff --git a/package.json b/package.json index 470aac8c0..aff74ced2 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "format:fix": "prettier . --write", "lint": "next lint", "lint:fix": "next lint --fix", + "lint:ci": "next build --no-lint && next lint", "now-build": "pnpm run build", "start": "next start", "typecheck": "tsc --noEmit", diff --git a/src/components/Admonition.tsx b/src/components/Admonition.tsx index b1ad3b1ae..b6921b309 100644 --- a/src/components/Admonition.tsx +++ b/src/components/Admonition.tsx @@ -109,7 +109,7 @@ export const Admonition = ({ children, }: { type: AdmonitionType - title: string + title?: string children: ReactNode }) => { return ( diff --git a/src/components/ApiGallery.tsx b/src/components/ApiGallery.tsx index d4e2623fc..24fccbb7e 100644 --- a/src/components/ApiGallery.tsx +++ b/src/components/ApiGallery.tsx @@ -12,7 +12,9 @@ export default function ApiGallery() { const router = useRouter() const onChange: MouseEventHandler = (e) => { - const version = parseInt((e.target as HTMLElement).getAttribute("value")!) + const version = parseInt( + (e.target as HTMLElement).getAttribute("value") as string + ) if (version !== 7) { router.push(`https://legacy.react-hook-form.com/v${version}/api`) diff --git a/src/components/ApiRefTable.tsx b/src/components/ApiRefTable.tsx index 076b14b0d..4fc0897f4 100644 --- a/src/components/ApiRefTable.tsx +++ b/src/components/ApiRefTable.tsx @@ -86,7 +86,9 @@ export default function ApiRefTable({ api }: { api: typeof apiData }) { {api.register.options.title}