@next/eslint-plugin-next 16.3.0-canary.2 → 16.3.0-canary.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ declare const plugin: {
|
|
|
18
18
|
'no-head-import-in-document': Rule.RuleModule;
|
|
19
19
|
'no-html-link-for-pages': Rule.RuleModule;
|
|
20
20
|
'no-img-element': Rule.RuleModule;
|
|
21
|
+
'no-location-assign-relative-destination': Rule.RuleModule;
|
|
21
22
|
'no-page-custom-font': Rule.RuleModule;
|
|
22
23
|
'no-script-component-in-head': Rule.RuleModule;
|
|
23
24
|
'no-styled-jsx-in-document': Rule.RuleModule;
|
|
@@ -50,6 +51,7 @@ export declare const rules: {
|
|
|
50
51
|
'no-head-import-in-document': Rule.RuleModule;
|
|
51
52
|
'no-html-link-for-pages': Rule.RuleModule;
|
|
52
53
|
'no-img-element': Rule.RuleModule;
|
|
54
|
+
'no-location-assign-relative-destination': Rule.RuleModule;
|
|
53
55
|
'no-page-custom-font': Rule.RuleModule;
|
|
54
56
|
'no-script-component-in-head': Rule.RuleModule;
|
|
55
57
|
'no-styled-jsx-in-document': Rule.RuleModule;
|
package/dist/index.js
CHANGED
|
@@ -33,6 +33,7 @@ var _noheadelement = /*#__PURE__*/ _interop_require_default(require("./rules/no-
|
|
|
33
33
|
var _noheadimportindocument = /*#__PURE__*/ _interop_require_default(require("./rules/no-head-import-in-document"));
|
|
34
34
|
var _nohtmllinkforpages = /*#__PURE__*/ _interop_require_default(require("./rules/no-html-link-for-pages"));
|
|
35
35
|
var _noimgelement = /*#__PURE__*/ _interop_require_default(require("./rules/no-img-element"));
|
|
36
|
+
var _nolocationassignrelativedestination = /*#__PURE__*/ _interop_require_default(require("./rules/no-location-assign-relative-destination"));
|
|
36
37
|
var _nopagecustomfont = /*#__PURE__*/ _interop_require_default(require("./rules/no-page-custom-font"));
|
|
37
38
|
var _noscriptcomponentinhead = /*#__PURE__*/ _interop_require_default(require("./rules/no-script-component-in-head"));
|
|
38
39
|
var _nostyledjsxindocument = /*#__PURE__*/ _interop_require_default(require("./rules/no-styled-jsx-in-document"));
|
|
@@ -84,6 +85,7 @@ var recommendedRules = {
|
|
|
84
85
|
'@next/next/no-head-element': 'warn',
|
|
85
86
|
'@next/next/no-html-link-for-pages': 'warn',
|
|
86
87
|
'@next/next/no-img-element': 'warn',
|
|
88
|
+
'@next/next/no-location-assign-relative-destination': 'warn',
|
|
87
89
|
'@next/next/no-page-custom-font': 'warn',
|
|
88
90
|
'@next/next/no-styled-jsx-in-document': 'warn',
|
|
89
91
|
'@next/next/no-sync-scripts': 'warn',
|
|
@@ -121,6 +123,7 @@ var plugin = {
|
|
|
121
123
|
'no-head-import-in-document': _noheadimportindocument.default,
|
|
122
124
|
'no-html-link-for-pages': _nohtmllinkforpages.default,
|
|
123
125
|
'no-img-element': _noimgelement.default,
|
|
126
|
+
'no-location-assign-relative-destination': _nolocationassignrelativedestination.default,
|
|
124
127
|
'no-page-custom-font': _nopagecustomfont.default,
|
|
125
128
|
'no-script-component-in-head': _noscriptcomponentinhead.default,
|
|
126
129
|
'no-styled-jsx-in-document': _nostyledjsxindocument.default,
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "default", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return _default;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
var _definerule = require("../utils/define-rule");
|
|
12
|
+
var url = 'https://nextjs.org/docs/messages/no-location-assign-relative-destination';
|
|
13
|
+
var LOCATION_GLOBALS = new Set([
|
|
14
|
+
'window',
|
|
15
|
+
'globalThis'
|
|
16
|
+
]);
|
|
17
|
+
function isLocationObject(node) {
|
|
18
|
+
// `location`
|
|
19
|
+
if (node.type === 'Identifier' && node.name === 'location') {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
// `window.location` / `globalThis.location` (dot or bracket notation)
|
|
23
|
+
if (node.type === 'MemberExpression' && node.object.type === 'Identifier' && LOCATION_GLOBALS.has(node.object.name) && isPropertyNamed(node, 'location')) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
function isPropertyNamed(memberNode, name) {
|
|
29
|
+
return memberNode.computed === false && memberNode.property.type === 'Identifier' && memberNode.property.name === name || memberNode.computed === true && memberNode.property.type === 'Literal' && memberNode.property.value === name;
|
|
30
|
+
}
|
|
31
|
+
/** Returns true when the node is a string literal containing "://" (absolute URL). */ function isAbsoluteUrlLiteral(node) {
|
|
32
|
+
return node != null && node.type === 'Literal' && typeof node.value === 'string' && node.value.includes('://');
|
|
33
|
+
}
|
|
34
|
+
var _default = (0, _definerule.defineRule)({
|
|
35
|
+
meta: {
|
|
36
|
+
docs: {
|
|
37
|
+
description: 'Prevent usage of `location.assign` or `location.href` assignment to navigate to internal Next.js pages.',
|
|
38
|
+
recommended: true,
|
|
39
|
+
url: url
|
|
40
|
+
},
|
|
41
|
+
type: 'problem',
|
|
42
|
+
schema: [],
|
|
43
|
+
messages: {
|
|
44
|
+
noLocationAssign: "Do not use `{{expression}}` to navigate to internal Next.js pages. Use `redirect()` in the render phase, or `useRouter().push()` in Client Components' event handlers instead. See: " + url
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
create: function create(context) {
|
|
48
|
+
var sourceCode = context.sourceCode;
|
|
49
|
+
return {
|
|
50
|
+
// location.assign(...) / location['assign'](...)
|
|
51
|
+
// window.location.assign(...) / window.location['assign'](...)
|
|
52
|
+
// globalThis.location.assign(...) / globalThis.location['assign'](...)
|
|
53
|
+
CallExpression: function CallExpression(node) {
|
|
54
|
+
var callee = node.callee;
|
|
55
|
+
if (callee.type === 'MemberExpression' && isPropertyNamed(callee, 'assign') && isLocationObject(callee.object)) {
|
|
56
|
+
// Allow calls where the first argument is an absolute URL string literal
|
|
57
|
+
if (isAbsoluteUrlLiteral(node.arguments[0])) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
var expression = sourceCode.getText(callee);
|
|
61
|
+
context.report({
|
|
62
|
+
node: node,
|
|
63
|
+
messageId: 'noLocationAssign',
|
|
64
|
+
data: {
|
|
65
|
+
expression: expression + '()'
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
// location.href = ... / location['href'] = ...
|
|
71
|
+
// window.location.href = ... / window.location['href'] = ...
|
|
72
|
+
// globalThis.location.href = ... / globalThis.location['href'] = ...
|
|
73
|
+
AssignmentExpression: function AssignmentExpression(node) {
|
|
74
|
+
var left = node.left;
|
|
75
|
+
if (left.type === 'MemberExpression' && isPropertyNamed(left, 'href') && isLocationObject(left.object)) {
|
|
76
|
+
// Allow assignments where the right-hand side is an absolute URL string literal
|
|
77
|
+
if (isAbsoluteUrlLiteral(node.right)) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
var expression = sourceCode.getText(left);
|
|
81
|
+
context.report({
|
|
82
|
+
node: node,
|
|
83
|
+
messageId: 'noLocationAssign',
|
|
84
|
+
data: {
|
|
85
|
+
expression: expression
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@next/eslint-plugin-next",
|
|
3
|
-
"version": "16.3.0-canary.
|
|
3
|
+
"version": "16.3.0-canary.3",
|
|
4
4
|
"description": "ESLint plugin for Next.js.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -25,4 +25,4 @@
|
|
|
25
25
|
"types": "tsc --project tsconfig.json --skipLibCheck --declaration --emitDeclarationOnly --esModuleInterop --declarationDir dist",
|
|
26
26
|
"prepublishOnly": "cd ../../ && turbo run build"
|
|
27
27
|
}
|
|
28
|
-
}
|
|
28
|
+
}
|