@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,2 @@
1
+ declare const _default: import("eslint").Rule.RuleModule;
2
+ export default _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.2",
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
+ }