diff --git a/packages/eslint-plugin-next/src/rules/no-html-link-for-pages.ts b/packages/eslint-plugin-next/src/rules/no-html-link-for-pages.ts index 769fd538d5f46..f38216066d2de 100644 --- a/packages/eslint-plugin-next/src/rules/no-html-link-for-pages.ts +++ b/packages/eslint-plugin-next/src/rules/no-html-link-for-pages.ts @@ -2,7 +2,6 @@ import { defineRule } from '../utils/define-rule' import * as path from 'path' import * as fs from 'fs' import { getRootDirs } from '../utils/get-root-dirs' - import { getUrlFromPagesDirectories, normalizeURL, @@ -18,11 +17,10 @@ const pagesDirWarning = execOnce((pagesDirs) => { }) // Cache for fs.existsSync lookup. -// Prevent multiple blocking IO requests that have already been calculated. -const fsExistsSyncCache = {} +const fsExistsSyncCache: Record = {} const memoize = (fn: (...args: any[]) => T) => { - const cache = {} + const cache: Record = {} return (...args: any[]): T => { const key = JSON.stringify(args) if (cache[key] === undefined) { @@ -101,7 +99,7 @@ export default defineRule({ return fsExistsSyncCache[dir] }) - // warn if there are no pages and app directories + // Warn if no directories found if (foundPagesDirs.length === 0 && foundAppDirs.length === 0) { pagesDirWarning(pagesDirs) return {} @@ -111,6 +109,24 @@ export default defineRule({ const appDirUrls = cachedGetUrlFromAppDirectory('/', foundAppDirs) const allUrlRegex = [...pageUrls, ...appDirUrls] + // --- NEW CODE START: Support for custom pageExtensions --- + let pageExtensions: string[] = ['js', 'jsx', 'ts', 'tsx'] + + try { + const nextConfigPath = path.join(process.cwd(), 'next.config.js') + if (fs.existsSync(nextConfigPath)) { + const nextConfig = require(nextConfigPath) + if (nextConfig.pageExtensions && Array.isArray(nextConfig.pageExtensions)) { + pageExtensions = nextConfig.pageExtensions + } + } + } catch { + // ignore config errors + } + + const allowedExtRegex = new RegExp(`\\.(${pageExtensions.join('|')})$`) + // --- NEW CODE END --- + return { JSXOpeningElement(node) { if (node.name.name !== 'a') { @@ -125,7 +141,7 @@ export default defineRule({ (attr) => attr.type === 'JSXAttribute' && attr.name.name === 'target' ) - if (target && target.value.value === '_blank') { + if (target && target.value && target.value.value === '_blank') { return } @@ -152,6 +168,11 @@ export default defineRule({ return } + // --- NEW CODE: skip internal links with allowed extensions --- + if (allowedExtRegex.test(hrefPath)) { + return + } + allUrlRegex.forEach((foundUrl) => { if (foundUrl.test(normalizeURL(hrefPath))) { context.report({