Skip to content

Make npm run lint work in the remaining five recipes - #250

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

Make npm run lint work in the remaining five recipes#250
Hotragn wants to merge 1 commit into
tinyfish-io:mainfrom
Hotragn:hotragn/fix-eslint-flat-configs-remaining

Conversation

@Hotragn

@Hotragn Hotragn commented Aug 5, 2026

Copy link
Copy Markdown

Completes #248. Same shape as #249, which has the detailed rationale.

Before

None of these five could lint at all. Measured by installing each and running its own script:

Recipe Setup Result
restaurant-comparison-tool eslint . + .eslintrc.json exit 2 — ESLint 9 ignores .eslintrc.*
tutor-finder next lint, no config exit 1 — blocks on an interactive setup prompt
scholarship-finder next lint, no config exit 1 — same
summer-school-finder next lint, no config exit 1 — same
tenders-finder next lint on Next 16 exit 1 — next lint was removed in Next 16

Two config styles, because they aren't interchangeable

The four on Next 15 use FlatCompat. eslint-config-next@15 ships core-web-vitals.js and typescript.js as legacy eslintrc objects (module.exports = { extends: [...] }) and declares no exports subpaths, so the flat subpath imports used by the Next 16 recipes cannot resolve there.

tenders-finder is on Next 16, so it gets the subpath style — byte-identical to the ten recipes that already have a config.

Deliberately not standardising strictness: restaurant-comparison-tool keeps extending core-web-vitals only, exactly as its .eslintrc.json did. Making it stricter would have been a separate decision smuggled into a repair. The four with no previous config get core-web-vitals + typescript, matching the Next 16 recipes.

Scripts move from next lint to eslint, the idiom in 9 of the 10 already-working recipes.

The 12 errors turning lint on surfaced

The interesting two are in tenders-finder, which is on Next 16 and therefore gets the newer react-hooks rules:

// before — flagged by react-hooks/set-state-in-effect
const [isLoading, setIsLoading] = useState(true);
useEffect(() => { setIsLoading(true); }, [streamingUrl]);

// after — derived, no effect at all
const [loadedUrl, setLoadedUrl] = useState<string | null>(null);
const isLoading = loadedUrl !== streamingUrl;
// ...
<iframe onLoad={() => setLoadedUrl(streamingUrl)} />

Both violations (LiveBrowserModal.tsx, AgentPreviewCard.tsx) were the same thing: an effect resetting an iframe loading flag when the URL changed. Deriving the flag from which URL actually loaded removes the effect entirely and a piece of state with it — which is the answer the rule is pointing at, rather than a suppression comment. A new URL brings the spinner back automatically with no synchronising code.

The rest are mechanical: ternary-as-statement in four recipes, unused vars and imports, and a dead isExpanded prop in scholarship-finder that was passed but never read (removed from the prop, the type and the call site — all in one file).

require("tailwindcss-animate")import in four tailwind configs. There's no in-repo precedent for that ESM import, since the Next 16 recipes are on Tailwind v4 and don't use the plugin, so rather than assume CJS interop works I loaded each config through jiti — the loader Tailwind v3 actually uses — and confirmed the animate plugin is present and valid in all four. That also retroactively validates the same change in #249.

Verification

for r in restaurant-comparison-tool tutor-finder scholarship-finder summer-school-finder tenders-finder; do
  (cd $r && npm install && npm run lint && npx tsc --noEmit)
done

npm run lint and tsc --noEmit exit 0 in all five.

Two warnings left untouched on purpose: an exhaustive-deps warning in summer-school-finder/src/hooks/useSummerSchoolSearch.ts — adding runAgent to the dependency array risks changing render behaviour, which isn't a call to make inside a lint repair. Nothing outstanding in the other four.

The four package-lock.json diffs are one line each@eslint/eslintrc added to root devDependencies, pinned to ^3.3.5 which the already-locked version satisfies, so no version churn.

One pre-existing problem I did not fix

npm ci already fails in tutor-finder on main:

npm error `npm ci` can only install packages when your package.json and package-lock.json are in sync.
npm error Missing: @radix-ui/react-label@2.1.15 from lock file
npm error Missing: @radix-ui/react-separator@1.1.15 from lock file
npm error Missing: @radix-ui/react-toggle@1.1.18 from lock file
npm error Missing: @radix-ui/react-tooltip@1.2.16 from lock file

Its lock predates four declared dependencies. Regenerating it is ~900 lines of unrelated churn that would bury this change, so I left it and used npm install to verify that recipe. Filed separately — it deserves its own PR where a lock regeneration is the expected diff.

Happy to split this per-recipe if you'd rather review five smaller PRs.

Completes the set from tinyfish-io#248, following the shape of tinyfish-io#249. Before this,
none of these five could lint at all:

  restaurant-comparison-tool  eslint . + .eslintrc.json  exit 2
  tutor-finder                next lint, no config       exit 1
  scholarship-finder          next lint, no config       exit 1
  summer-school-finder        next lint, no config       exit 1
  tenders-finder              next lint on Next 16       exit 1

Two config styles, because they are not interchangeable. The four on
Next 15 use FlatCompat from @eslint/eslintrc: eslint-config-next@15
ships core-web-vitals.js and typescript.js as legacy eslintrc objects
with no exports subpaths, so the flat subpath imports the Next 16
recipes use cannot resolve there. tenders-finder is on Next 16 and gets
the subpath style, matching the ten recipes that already have a config.

restaurant-comparison-tool keeps extending core-web-vitals only, as its
.eslintrc.json did, rather than being quietly made stricter. The four
with no previous config get core-web-vitals + typescript, matching the
Next 16 recipes. Scripts move from "next lint" to "eslint", the idiom in
nine of the ten already-working recipes.

Turning lint on surfaced 12 errors, all fixed so lint lands green:

- tenders-finder: two react-hooks/set-state-in-effect violations. Both
  were an effect resetting an iframe loading flag when the URL changed;
  both now derive that flag from which URL actually loaded, removing the
  effect rather than suppressing the rule.
- ternary-as-statement in four recipes, unused vars and imports, and a
  dead isExpanded prop in scholarship-finder passed but never read.
- require("tailwindcss-animate") replaced with an import in four
  tailwind configs. Verified each config still loads through jiti, the
  loader Tailwind v3 uses, with the animate plugin intact.

npm run lint and tsc --noEmit exit 0 in all five. Two warnings remain
untouched: an exhaustive-deps warning in summer-school-finder, since
adding the dependency risks changing render behaviour, and nothing in
tenders-finder.

Note tutor-finder's npm ci already fails on main - its lock predates
four declared @radix-ui dependencies. Left alone here so this stays a
lint change; filed separately.
@coderabbitai

coderabbitai Bot commented Aug 5, 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: 46124c83-2bbd-4351-a423-d7caaad411aa

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