Skip to content

Make npm run lint work in stay-scout-hub - #249

Open
Hotragn wants to merge 1 commit into
tinyfish-io:mainfrom
Hotragn:hotragn/fix-eslint-flat-configs
Open

Make npm run lint work in stay-scout-hub#249
Hotragn wants to merge 1 commit into
tinyfish-io:mainfrom
Hotragn:hotragn/fix-eslint-flat-configs

Conversation

@Hotragn

@Hotragn Hotragn commented Aug 4, 2026

Copy link
Copy Markdown

First of the recipes in #248. Independent of #246, which touches different files in this recipe.

The bug

cd stay-scout-hub && npm ci && npm run lint
# > eslint .
# From ESLint v9.0.0, the default configuration file is now eslint.config.js.
# exit 2

The script is eslint . with eslint@^9 and no eslint.config.* anywhere in the recipe. ESLint 9 only reads flat config, so it exits before linting a single file. This recipe has never had working lint.

Why FlatCompat and not the style the other recipes use

The 10 recipes that already have eslint.config.mjs are all on Next 16 and import the flat subpaths:

import nextVitals from "eslint-config-next/core-web-vitals";

That can't be copied here. eslint-config-next@15.3.3 ships those files as legacy eslintrc objects

// node_modules/eslint-config-next/core-web-vitals.js
module.exports = {
  extends: [require.resolve('.'), 'plugin:@next/next/core-web-vitals'],
}

— and declares no exports subpaths at all, only "main". Spreading that into a flat config array doesn't work.

So this uses FlatCompat from @eslint/eslintrc, which is exactly what create-next-app generated for Next 15, extending the same next/core-web-vitals + next/typescript pair the Next 16 recipes get. @eslint/eslintrc is added as an explicit devDependency rather than relying on it being hoisted out of eslint's own dependency tree.

The alternative is upgrading this recipe to Next 16 and using the subpath style. That's a much bigger diff with real behaviour risk, so I raised it as a question on #248 rather than assuming.

The 8 errors turning lint on surfaced

A config-only change would have left npm run lint red, which is worse than failing loudly. All fixed here:

File Rule Fix
api/discover-areas/route.ts no-unused-vars dropped the unused purpose param from generateFallbackAreas + its 4 call sites
AreaCard.tsx ×2 react/no-unescaped-entities ""
SearchFormV2.tsx react/no-unescaped-entities ''
ui/input.tsx no-empty-object-type empty interface InputProps extends X {}type InputProps = X
ui/textarea.tsx no-empty-object-type same
hooks/useAreaSearch.ts no-unused-vars removed unused AreaSuggestion import
tailwind.config.ts no-require-imports require("tailwindcss-animate")import (already a declared dependency)

All behaviour-preserving. purpose is still read elsewhere in that route for getPurposeDescription; it was only ever unused inside generateFallbackAreas.

Verification

cd stay-scout-hub && npm ci
npm run lint      # exit 0
npx tsc --noEmit  # exit 0

The package-lock.json change is just @eslint/eslintrc moving to a direct devDependency (it was already present transitively at 3.3.5) plus a transitive js-yaml bump.

Remaining five

restaurant-comparison-tool, tutor-finder, scholarship-finder, summer-school-finder, tenders-finder — same shape, three different root causes, all measured in #248. Sending this one first so the approach can be checked before I repeat it five times.

The lint script is `eslint .` with eslint@^9 and no eslint.config.*, so
it exits 2 without linting anything -- ESLint 9 only reads flat config.
This recipe has had no working lint at all.

eslint-config-next@15.x still ships core-web-vitals.js and typescript.js
as legacy eslintrc objects with no exports subpaths, so the flat style the
Next 16 recipes use cannot be copied here. Bridged with FlatCompat from
@eslint/eslintrc instead, which is what create-next-app generated for
Next 15, extending the same next/core-web-vitals + next/typescript pair.
Added @eslint/eslintrc as an explicit devDependency rather than relying on
it being hoisted out of eslint's own tree.

Turning lint on surfaced 8 errors that were never being checked, all
fixed here so lint lands green rather than merely running:

- dropped the unused `purpose` parameter from generateFallbackAreas and
  its four call sites
- escaped quotes in AreaCard and an apostrophe in SearchFormV2
- replaced the empty InputProps/TextareaProps interfaces with type
  aliases of the attribute types they extended
- imported tailwindcss-animate instead of require()ing it

npm run lint and tsc --noEmit both exit 0. First of the recipes in tinyfish-io#248;
the other five follow the same shape once the approach looks right.
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6736a441-16a5-4061-aaa3-491989500158

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant