mirror of
https://github.com/hanzoai/next.js.git
synced 2026-10-30 14:46:38 +00:00
## For Contributors ### Adding a feature Adding a new ESLint rule to `eslint-plugin-next` reporting `location.href = [relative URL]` or `location.assign([relative URL])` usage. For some reason, some LLM models prefer this incorrect pattern, and avoid `redirect()` or `useRouter().push()` at all costs. But at least many of them do respect ESLint, by adding a new rule we can enforce correct behavior. The error documentation and unit test cases are also added. --------- Co-authored-by: Joseph <[email protected]> Co-authored-by: Benjamin Woodruff <[email protected]>
114 lines
3.6 KiB
TypeScript
114 lines
3.6 KiB
TypeScript
import { RuleTester } from 'eslint'
|
|
import { rules } from '@next/eslint-plugin-next'
|
|
|
|
const NextESLintRule = rules['no-location-assign-relative-destination']
|
|
|
|
const err = (expression: string) => ({
|
|
messageId: 'noLocationAssign',
|
|
data: { expression },
|
|
})
|
|
|
|
describe('no-location-assign-relative-destination', () => {
|
|
new RuleTester({
|
|
languageOptions: {
|
|
ecmaVersion: 2018,
|
|
sourceType: 'module',
|
|
parserOptions: {
|
|
ecmaFeatures: {
|
|
modules: true,
|
|
jsx: true,
|
|
},
|
|
},
|
|
},
|
|
}).run('eslint', NextESLintRule, {
|
|
valid: [
|
|
// Reading href is fine
|
|
`const href = location.href`,
|
|
`const url = window.location.href`,
|
|
// location.replace is not covered by this rule
|
|
`location.replace('/foo')`,
|
|
`window.location.replace('/foo')`,
|
|
// Absolute URLs (with protocol) are allowed
|
|
`location.href = 'https://example.com'`,
|
|
`window.location.href = 'https://example.com/path'`,
|
|
`globalThis.location.href = 'http://example.com'`,
|
|
`location.assign('https://example.com')`,
|
|
`window.location.assign('https://example.com/path')`,
|
|
`globalThis.location.assign('http://example.com')`,
|
|
// Bracket notation with absolute URL
|
|
`location['href'] = 'https://example.com'`,
|
|
`location['assign']('https://example.com')`,
|
|
],
|
|
invalid: [
|
|
// location.href = (relative)
|
|
{ code: `location.href = '/foo'`, errors: [err('location.href')] },
|
|
// window.location.href = (relative)
|
|
{
|
|
code: `window.location.href = '/foo'`,
|
|
errors: [err('window.location.href')],
|
|
},
|
|
// globalThis.location.href = (relative)
|
|
{
|
|
code: `globalThis.location.href = '/foo'`,
|
|
errors: [err('globalThis.location.href')],
|
|
},
|
|
// location['href'] = (relative, bracket notation)
|
|
{
|
|
code: `location['href'] = '/foo'`,
|
|
errors: [err("location['href']")],
|
|
},
|
|
// window.location['href'] = (relative, bracket notation)
|
|
{
|
|
code: `window.location['href'] = '/foo'`,
|
|
errors: [err("window.location['href']")],
|
|
},
|
|
// location.href = (dynamic, unknown whether absolute)
|
|
{ code: `location.href = someVariable`, errors: [err('location.href')] },
|
|
// location.assign() (relative)
|
|
{ code: `location.assign('/foo')`, errors: [err('location.assign()')] },
|
|
// window.location.assign() (relative)
|
|
{
|
|
code: `window.location.assign('/foo')`,
|
|
errors: [err('window.location.assign()')],
|
|
},
|
|
// globalThis.location.assign() (relative)
|
|
{
|
|
code: `globalThis.location.assign('/foo')`,
|
|
errors: [err('globalThis.location.assign()')],
|
|
},
|
|
// location['assign']() (relative, bracket notation)
|
|
{
|
|
code: `location['assign']('/foo')`,
|
|
errors: [err("location['assign']()")],
|
|
},
|
|
// window.location['assign']() (relative, bracket notation)
|
|
{
|
|
code: `window.location['assign']('/foo')`,
|
|
errors: [err("window.location['assign']()")],
|
|
},
|
|
// location.assign() (dynamic, unknown whether absolute)
|
|
{
|
|
code: `location.assign(someVariable)`,
|
|
errors: [err('location.assign()')],
|
|
},
|
|
// Inside a function
|
|
{
|
|
code: `
|
|
function handleClick() {
|
|
window.location.href = '/dashboard'
|
|
}
|
|
`,
|
|
errors: [err('window.location.href')],
|
|
},
|
|
{
|
|
code: `
|
|
function handleClick() {
|
|
location.assign('/dashboard')
|
|
}
|
|
`,
|
|
errors: [err('location.assign()')],
|
|
},
|
|
],
|
|
})
|
|
})
|