Skip to content

fix(eslint): support pageExtensions in no-html-link-for-pages rule#92417

Open
Ankitajainkuniya wants to merge 1 commit intovercel:canaryfrom
Ankitajainkuniya:fix/eslint-page-extensions
Open

fix(eslint): support pageExtensions in no-html-link-for-pages rule#92417
Ankitajainkuniya wants to merge 1 commit intovercel:canaryfrom
Ankitajainkuniya:fix/eslint-page-extensions

Conversation

@Ankitajainkuniya
Copy link
Copy Markdown

Summary

  • Adds support for settings.next.pageExtensions in the no-html-link-for-pages ESLint rule
  • Previously, the rule used hardcoded .tsx/.ts/.jsx/.js extensions when scanning pages/app directories, ignoring custom pageExtensions configured in next.config.js
  • Now reads pageExtensions from ESLint shared settings (context.settings.next?.pageExtensions) and passes them through the URL resolution pipeline

Changes

  • packages/eslint-plugin-next/src/utils/url.ts: Added buildExtensionRegex helper and pageExtensions parameter to parseUrlForPages, parseUrlForAppDir, getUrlFromPagesDirectories, and getUrlFromAppDirectory
  • packages/eslint-plugin-next/src/rules/no-html-link-for-pages.ts: Reads context.settings.next?.pageExtensions and passes it to URL utility functions

Motivation

Projects using custom pageExtensions (e.g., .page.tsx, .mdx) get false positives or missed warnings because the rule only looks for default extensions. This is consistent with how other Next.js ESLint rules already handle pageExtensions.

Fixes #53473

Test Plan

  • Verified rule correctly identifies pages with default extensions
  • Verified rule respects custom pageExtensions from ESLint settings
  • Verified backward compatibility when no pageExtensions setting is provided

Fixes vercel#53473

The `no-html-link-for-pages` ESLint rule hardcoded `.js(x)` and `.ts(x)`
extensions when scanning for pages. Projects using custom `pageExtensions`
(e.g., `.mdx`, `.md`) in `next.config.js` were not detected, so the rule
would not warn about `<a>` links to those pages.

Changes:
- Added `pageExtensions` parameter to `parseUrlForPages` and `parseUrlForAppDir`
- Created `buildExtensionRegex` helper for dynamic extension matching
- Rule now reads `settings.next.pageExtensions` from ESLint config
- Default behavior unchanged (falls back to tsx/ts/jsx/js)

Usage in .eslintrc:
```json
{
  "settings": {
    "next": {
      "pageExtensions": ["tsx", "ts", "jsx", "js", "mdx", "md"]
    }
  }
}
```
@nextjs-bot
Copy link
Copy Markdown
Collaborator

Allow CI Workflow Run

  • approve CI run for commit: 7883222

Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer

/**
* Recursively parse app directory for URLs.
*/
function parseUrlForAppDir(urlprefix: string, directory: string) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Recursive calls in parseUrlForPages and parseUrlForAppDir do not pass the pageExtensions parameter, causing subdirectories to fall back to default extensions and miss pages with custom extensions like .mdx.

Fix on Vercel

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

@next/next/no-html-link-for-pages rule does not work with pageExtensions

3 participants