eslint-plugin-nextjs 0.1.2 → 1.0.1
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/README.md +13 -13
- package/dist/index.d.ts +3 -6
- package/dist/index.js +399 -264
- package/dist/index.js.map +1 -1
- package/package.json +18 -12
- package/dist/index.cjs +0 -1485
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -11
- package/dist/rules/google-font-display.cjs +0 -119
- package/dist/rules/google-font-display.cjs.map +0 -1
- package/dist/rules/google-font-display.d.cts +0 -8
- package/dist/rules/google-font-display.d.ts +0 -8
- package/dist/rules/google-font-display.js +0 -92
- package/dist/rules/google-font-display.js.map +0 -1
- package/dist/rules/google-font-preconnect.cjs +0 -109
- package/dist/rules/google-font-preconnect.cjs.map +0 -1
- package/dist/rules/google-font-preconnect.d.cts +0 -5
- package/dist/rules/google-font-preconnect.d.ts +0 -5
- package/dist/rules/google-font-preconnect.js +0 -82
- package/dist/rules/google-font-preconnect.js.map +0 -1
- package/dist/rules/inline-script-id.cjs +0 -94
- package/dist/rules/inline-script-id.cjs.map +0 -1
- package/dist/rules/inline-script-id.d.cts +0 -5
- package/dist/rules/inline-script-id.d.ts +0 -5
- package/dist/rules/inline-script-id.js +0 -67
- package/dist/rules/inline-script-id.js.map +0 -1
- package/dist/rules/next-script-for-ga.cjs +0 -129
- package/dist/rules/next-script-for-ga.cjs.map +0 -1
- package/dist/rules/next-script-for-ga.d.cts +0 -5
- package/dist/rules/next-script-for-ga.d.ts +0 -5
- package/dist/rules/next-script-for-ga.js +0 -102
- package/dist/rules/next-script-for-ga.js.map +0 -1
- package/dist/rules/no-assign-module-variable.cjs +0 -64
- package/dist/rules/no-assign-module-variable.cjs.map +0 -1
- package/dist/rules/no-assign-module-variable.d.cts +0 -5
- package/dist/rules/no-assign-module-variable.d.ts +0 -5
- package/dist/rules/no-assign-module-variable.js +0 -37
- package/dist/rules/no-assign-module-variable.js.map +0 -1
- package/dist/rules/no-async-client-component.cjs +0 -99
- package/dist/rules/no-async-client-component.cjs.map +0 -1
- package/dist/rules/no-async-client-component.d.cts +0 -5
- package/dist/rules/no-async-client-component.d.ts +0 -5
- package/dist/rules/no-async-client-component.js +0 -72
- package/dist/rules/no-async-client-component.js.map +0 -1
- package/dist/rules/no-before-interactive-script-outside-document.cjs +0 -94
- package/dist/rules/no-before-interactive-script-outside-document.cjs.map +0 -1
- package/dist/rules/no-before-interactive-script-outside-document.d.cts +0 -5
- package/dist/rules/no-before-interactive-script-outside-document.d.ts +0 -5
- package/dist/rules/no-before-interactive-script-outside-document.js +0 -59
- package/dist/rules/no-before-interactive-script-outside-document.js.map +0 -1
- package/dist/rules/no-css-tags.cjs +0 -70
- package/dist/rules/no-css-tags.cjs.map +0 -1
- package/dist/rules/no-css-tags.d.cts +0 -5
- package/dist/rules/no-css-tags.d.ts +0 -5
- package/dist/rules/no-css-tags.js +0 -43
- package/dist/rules/no-css-tags.js.map +0 -1
- package/dist/rules/no-document-import-in-page.cjs +0 -74
- package/dist/rules/no-document-import-in-page.cjs.map +0 -1
- package/dist/rules/no-document-import-in-page.d.cts +0 -5
- package/dist/rules/no-document-import-in-page.d.ts +0 -5
- package/dist/rules/no-document-import-in-page.js +0 -39
- package/dist/rules/no-document-import-in-page.js.map +0 -1
- package/dist/rules/no-duplicate-head.cjs +0 -87
- package/dist/rules/no-duplicate-head.cjs.map +0 -1
- package/dist/rules/no-duplicate-head.d.cts +0 -5
- package/dist/rules/no-duplicate-head.d.ts +0 -5
- package/dist/rules/no-duplicate-head.js +0 -60
- package/dist/rules/no-duplicate-head.js.map +0 -1
- package/dist/rules/no-head-element.cjs +0 -76
- package/dist/rules/no-head-element.cjs.map +0 -1
- package/dist/rules/no-head-element.d.cts +0 -5
- package/dist/rules/no-head-element.d.ts +0 -5
- package/dist/rules/no-head-element.js +0 -41
- package/dist/rules/no-head-element.js.map +0 -1
- package/dist/rules/no-head-import-in-document.cjs +0 -76
- package/dist/rules/no-head-import-in-document.cjs.map +0 -1
- package/dist/rules/no-head-import-in-document.d.cts +0 -5
- package/dist/rules/no-head-import-in-document.d.ts +0 -5
- package/dist/rules/no-head-import-in-document.js +0 -41
- package/dist/rules/no-head-import-in-document.js.map +0 -1
- package/dist/rules/no-html-link-for-pages.cjs +0 -302
- package/dist/rules/no-html-link-for-pages.cjs.map +0 -1
- package/dist/rules/no-html-link-for-pages.d.cts +0 -5
- package/dist/rules/no-html-link-for-pages.d.ts +0 -5
- package/dist/rules/no-html-link-for-pages.js +0 -267
- package/dist/rules/no-html-link-for-pages.js.map +0 -1
- package/dist/rules/no-img-element.cjs +0 -83
- package/dist/rules/no-img-element.cjs.map +0 -1
- package/dist/rules/no-img-element.d.cts +0 -5
- package/dist/rules/no-img-element.d.ts +0 -5
- package/dist/rules/no-img-element.js +0 -48
- package/dist/rules/no-img-element.js.map +0 -1
- package/dist/rules/no-page-custom-font.cjs +0 -184
- package/dist/rules/no-page-custom-font.cjs.map +0 -1
- package/dist/rules/no-page-custom-font.d.cts +0 -5
- package/dist/rules/no-page-custom-font.d.ts +0 -5
- package/dist/rules/no-page-custom-font.js +0 -159
- package/dist/rules/no-page-custom-font.js.map +0 -1
- package/dist/rules/no-script-component-in-head.cjs +0 -74
- package/dist/rules/no-script-component-in-head.cjs.map +0 -1
- package/dist/rules/no-script-component-in-head.d.cts +0 -5
- package/dist/rules/no-script-component-in-head.d.ts +0 -5
- package/dist/rules/no-script-component-in-head.js +0 -47
- package/dist/rules/no-script-component-in-head.js.map +0 -1
- package/dist/rules/no-styled-jsx-in-document.cjs +0 -78
- package/dist/rules/no-styled-jsx-in-document.cjs.map +0 -1
- package/dist/rules/no-styled-jsx-in-document.d.cts +0 -5
- package/dist/rules/no-styled-jsx-in-document.d.ts +0 -5
- package/dist/rules/no-styled-jsx-in-document.js +0 -43
- package/dist/rules/no-styled-jsx-in-document.js.map +0 -1
- package/dist/rules/no-sync-scripts.cjs +0 -64
- package/dist/rules/no-sync-scripts.cjs.map +0 -1
- package/dist/rules/no-sync-scripts.d.cts +0 -5
- package/dist/rules/no-sync-scripts.d.ts +0 -5
- package/dist/rules/no-sync-scripts.js +0 -37
- package/dist/rules/no-sync-scripts.js.map +0 -1
- package/dist/rules/no-title-in-document-head.cjs +0 -78
- package/dist/rules/no-title-in-document-head.cjs.map +0 -1
- package/dist/rules/no-title-in-document-head.d.cts +0 -5
- package/dist/rules/no-title-in-document-head.d.ts +0 -5
- package/dist/rules/no-title-in-document-head.js +0 -51
- package/dist/rules/no-title-in-document-head.js.map +0 -1
- package/dist/rules/no-typos.cjs +0 -133
- package/dist/rules/no-typos.cjs.map +0 -1
- package/dist/rules/no-typos.d.cts +0 -5
- package/dist/rules/no-typos.d.ts +0 -5
- package/dist/rules/no-typos.js +0 -98
- package/dist/rules/no-typos.js.map +0 -1
- package/dist/rules/no-unwanted-polyfillio.cjs +0 -164
- package/dist/rules/no-unwanted-polyfillio.cjs.map +0 -1
- package/dist/rules/no-unwanted-polyfillio.d.cts +0 -5
- package/dist/rules/no-unwanted-polyfillio.d.ts +0 -5
- package/dist/rules/no-unwanted-polyfillio.js +0 -137
- package/dist/rules/no-unwanted-polyfillio.js.map +0 -1
- package/dist/utils/define-rule.cjs +0 -31
- package/dist/utils/define-rule.cjs.map +0 -1
- package/dist/utils/define-rule.d.cts +0 -5
- package/dist/utils/define-rule.d.ts +0 -5
- package/dist/utils/define-rule.js +0 -6
- package/dist/utils/define-rule.js.map +0 -1
- package/dist/utils/get-root-dirs.cjs +0 -60
- package/dist/utils/get-root-dirs.cjs.map +0 -1
- package/dist/utils/get-root-dirs.d.cts +0 -8
- package/dist/utils/get-root-dirs.d.ts +0 -8
- package/dist/utils/get-root-dirs.js +0 -25
- package/dist/utils/get-root-dirs.js.map +0 -1
- package/dist/utils/node-attributes.cjs +0 -67
- package/dist/utils/node-attributes.cjs.map +0 -1
- package/dist/utils/node-attributes.d.cts +0 -15
- package/dist/utils/node-attributes.d.ts +0 -15
- package/dist/utils/node-attributes.js +0 -46
- package/dist/utils/node-attributes.js.map +0 -1
- package/dist/utils/url.cjs +0 -167
- package/dist/utils/url.cjs.map +0 -1
- package/dist/utils/url.d.cts +0 -35
- package/dist/utils/url.d.ts +0 -35
- package/dist/utils/url.js +0 -128
- package/dist/utils/url.js.map +0 -1
package/dist/index.js
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
-
// src/
|
2
|
-
|
1
|
+
// src/index.ts
|
2
|
+
import fs3 from "node:fs";
|
3
|
+
|
4
|
+
// src/rules/google-font-display.ts
|
5
|
+
import { URLSearchParams } from "node:url";
|
3
6
|
|
4
7
|
// src/utils/node-attributes.ts
|
5
8
|
var NodeAttributes = class {
|
@@ -45,12 +48,14 @@ var NodeAttributes = class {
|
|
45
48
|
};
|
46
49
|
|
47
50
|
// src/rules/google-font-display.ts
|
48
|
-
var
|
49
|
-
var
|
51
|
+
var name = "google-font-display";
|
52
|
+
var url = `https://nextjs.org/docs/messages/${name}`;
|
53
|
+
var googleFontDisplay = {
|
50
54
|
create: (context) => ({
|
51
55
|
JSXOpeningElement: (node) => {
|
52
|
-
let
|
53
|
-
|
56
|
+
let messageId;
|
57
|
+
let data;
|
58
|
+
if (node.name.type !== "JSXIdentifier" || node.name.name !== "link") {
|
54
59
|
return;
|
55
60
|
}
|
56
61
|
const attributes = new NodeAttributes(node);
|
@@ -60,17 +65,24 @@ var googleFontDisplay = defineRule({
|
|
60
65
|
const hrefValue = attributes.value("href");
|
61
66
|
const isGoogleFont = typeof hrefValue === "string" && hrefValue.startsWith("https://fonts.googleapis.com/css");
|
62
67
|
if (isGoogleFont) {
|
63
|
-
const
|
68
|
+
const queryPart = hrefValue.includes("?") ? hrefValue.substring(hrefValue.indexOf("?") + 1) : "";
|
69
|
+
const params = new URLSearchParams(queryPart);
|
64
70
|
const displayValue = params.get("display");
|
65
71
|
if (!params.has("display")) {
|
66
|
-
|
72
|
+
messageId = "missingFontDisplay";
|
73
|
+
data = { url };
|
67
74
|
} else if (displayValue === "auto" || displayValue === "block" || displayValue === "fallback") {
|
68
|
-
|
75
|
+
messageId = "notRecommendedFontDisplay";
|
76
|
+
data = {
|
77
|
+
display: displayValue[0]?.toUpperCase() + displayValue.slice(1),
|
78
|
+
url
|
79
|
+
};
|
69
80
|
}
|
70
81
|
}
|
71
|
-
if (
|
82
|
+
if (messageId) {
|
72
83
|
context.report({
|
73
|
-
|
84
|
+
data,
|
85
|
+
messageId,
|
74
86
|
node
|
75
87
|
});
|
76
88
|
}
|
@@ -82,17 +94,22 @@ var googleFontDisplay = defineRule({
|
|
82
94
|
recommended: true,
|
83
95
|
url
|
84
96
|
},
|
97
|
+
messages: {
|
98
|
+
missingFontDisplay: "A font-display parameter is missing (adding `&display=optional` is recommended). See: {{url}}",
|
99
|
+
notRecommendedFontDisplay: "{{display}} is not recommended. See: {{url}}"
|
100
|
+
},
|
85
101
|
schema: [],
|
86
102
|
type: "problem"
|
87
103
|
}
|
88
|
-
}
|
104
|
+
};
|
89
105
|
|
90
106
|
// src/rules/google-font-preconnect.ts
|
91
|
-
var
|
92
|
-
var
|
107
|
+
var name2 = "google-font-preconnect";
|
108
|
+
var url2 = `https://nextjs.org/docs/messages/${name2}`;
|
109
|
+
var googleFontPreconnect = {
|
93
110
|
create: (context) => ({
|
94
111
|
JSXOpeningElement: (node) => {
|
95
|
-
if (node.name.name !== "link") {
|
112
|
+
if (node.name.type !== "JSXIdentifier" || node.name.name !== "link") {
|
96
113
|
return;
|
97
114
|
}
|
98
115
|
const attributes = new NodeAttributes(node);
|
@@ -103,7 +120,8 @@ var googleFontPreconnect = defineRule({
|
|
103
120
|
const preconnectMissing = !attributes.has("rel") || !attributes.hasValue("rel") || attributes.value("rel") !== "preconnect";
|
104
121
|
if (typeof hrefValue === "string" && hrefValue.startsWith("https://fonts.gstatic.com") && preconnectMissing) {
|
105
122
|
context.report({
|
106
|
-
|
123
|
+
data: { url: url2 },
|
124
|
+
messageId: "missingPreconnect",
|
107
125
|
node
|
108
126
|
});
|
109
127
|
}
|
@@ -115,27 +133,34 @@ var googleFontPreconnect = defineRule({
|
|
115
133
|
recommended: true,
|
116
134
|
url: url2
|
117
135
|
},
|
136
|
+
messages: {
|
137
|
+
missingPreconnect: '`rel="preconnect"` is missing from Google Font. See: {{url}}'
|
138
|
+
},
|
118
139
|
schema: [],
|
119
140
|
type: "problem"
|
120
141
|
}
|
121
|
-
}
|
142
|
+
};
|
122
143
|
|
123
144
|
// src/rules/inline-script-id.ts
|
124
|
-
var
|
125
|
-
var
|
145
|
+
var name3 = "inline-script-id";
|
146
|
+
var url3 = `https://nextjs.org/docs/messages/${name3}`;
|
147
|
+
var inlineScriptId = {
|
126
148
|
create: (context) => {
|
127
149
|
let nextScriptImportName = null;
|
128
150
|
return {
|
129
151
|
ImportDeclaration: (node) => {
|
130
|
-
if (node.source.value === "next/script") {
|
131
|
-
|
152
|
+
if (node.source.value === "next/script" && node.specifiers.length > 0) {
|
153
|
+
const specifier = node.specifiers[0];
|
154
|
+
if (specifier && specifier.type === "ImportDefaultSpecifier") {
|
155
|
+
nextScriptImportName = specifier.local.name;
|
156
|
+
}
|
132
157
|
}
|
133
158
|
},
|
134
159
|
JSXElement: (node) => {
|
135
160
|
if (nextScriptImportName === null) {
|
136
161
|
return;
|
137
162
|
}
|
138
|
-
if (node.openingElement
|
163
|
+
if (node.openingElement.name.type === "JSXIdentifier" && node.openingElement.name.name !== nextScriptImportName) {
|
139
164
|
return;
|
140
165
|
}
|
141
166
|
const attributeNames = /* @__PURE__ */ new Set();
|
@@ -145,11 +170,15 @@ var inlineScriptId = defineRule({
|
|
145
170
|
return;
|
146
171
|
}
|
147
172
|
if (attribute.type === "JSXAttribute") {
|
148
|
-
|
173
|
+
if (attribute.name.type === "JSXIdentifier") {
|
174
|
+
attributeNames.add(attribute.name.name);
|
175
|
+
}
|
149
176
|
} else if (attribute.type === "JSXSpreadAttribute") {
|
150
|
-
if (attribute.argument
|
177
|
+
if (attribute.argument.type === "ObjectExpression") {
|
151
178
|
attribute.argument.properties.forEach((property) => {
|
152
|
-
|
179
|
+
if (property.type === "Property" && property.key.type === "Identifier") {
|
180
|
+
attributeNames.add(property.key.name);
|
181
|
+
}
|
153
182
|
});
|
154
183
|
} else {
|
155
184
|
hasNonCheckableSpreadAttribute = true;
|
@@ -162,7 +191,8 @@ var inlineScriptId = defineRule({
|
|
162
191
|
if (node.children.length > 0 || attributeNames.has("dangerouslySetInnerHTML")) {
|
163
192
|
if (!attributeNames.has("id")) {
|
164
193
|
context.report({
|
165
|
-
|
194
|
+
data: { url: url3 },
|
195
|
+
messageId: "missingId",
|
166
196
|
node
|
167
197
|
});
|
168
198
|
}
|
@@ -176,10 +206,13 @@ var inlineScriptId = defineRule({
|
|
176
206
|
recommended: true,
|
177
207
|
url: url3
|
178
208
|
},
|
209
|
+
messages: {
|
210
|
+
missingId: "`next/script` components with inline content must specify an `id` attribute. See: {{url}}"
|
211
|
+
},
|
179
212
|
schema: [],
|
180
213
|
type: "problem"
|
181
214
|
}
|
182
|
-
}
|
215
|
+
};
|
183
216
|
|
184
217
|
// src/rules/next-script-for-ga.ts
|
185
218
|
var SUPPORTED_SRCS = [
|
@@ -190,16 +223,16 @@ var SUPPORTED_HTML_CONTENT_URLS = [
|
|
190
223
|
"www.google-analytics.com/analytics.js",
|
191
224
|
"www.googletagmanager.com/gtm.js"
|
192
225
|
];
|
226
|
+
var name4 = "next-script-for-ga";
|
227
|
+
var url4 = `https://nextjs.org/docs/messages/${name4}`;
|
193
228
|
var description = "Prefer `next/script` component when using the inline script for Google Analytics.";
|
194
|
-
var url4 = "https://nextjs.org/docs/messages/next-script-for-ga";
|
195
|
-
var ERROR_MSG = `${description} See: ${url4}`;
|
196
229
|
var containsStr = (str, strList) => {
|
197
230
|
return strList.some((s) => str.includes(s));
|
198
231
|
};
|
199
|
-
var nextScriptForGa =
|
232
|
+
var nextScriptForGa = {
|
200
233
|
create: (context) => ({
|
201
234
|
JSXOpeningElement: (node) => {
|
202
|
-
if (node.name.name !== "script") {
|
235
|
+
if (node.name.type !== "JSXIdentifier" || node.name.name !== "script") {
|
203
236
|
return;
|
204
237
|
}
|
205
238
|
if (node.attributes.length === 0) {
|
@@ -207,16 +240,19 @@ var nextScriptForGa = defineRule({
|
|
207
240
|
}
|
208
241
|
const attributes = new NodeAttributes(node);
|
209
242
|
if (typeof attributes.value("src") === "string" && containsStr(attributes.value("src"), SUPPORTED_SRCS)) {
|
210
|
-
|
211
|
-
|
243
|
+
context.report({
|
244
|
+
data: { url: url4 },
|
245
|
+
messageId: "useNextScript",
|
212
246
|
node
|
213
247
|
});
|
248
|
+
return;
|
214
249
|
}
|
215
250
|
if (attributes.value("dangerouslySetInnerHTML") && attributes.value("dangerouslySetInnerHTML").length > 0) {
|
216
251
|
const htmlContent = attributes.value("dangerouslySetInnerHTML")[0].value.quasis?.[0].value.raw;
|
217
252
|
if (htmlContent && containsStr(htmlContent, SUPPORTED_HTML_CONTENT_URLS)) {
|
218
253
|
context.report({
|
219
|
-
|
254
|
+
data: { url: url4 },
|
255
|
+
messageId: "useNextScript",
|
220
256
|
node
|
221
257
|
});
|
222
258
|
}
|
@@ -229,19 +265,23 @@ var nextScriptForGa = defineRule({
|
|
229
265
|
recommended: true,
|
230
266
|
url: url4
|
231
267
|
},
|
268
|
+
messages: {
|
269
|
+
useNextScript: "Prefer `next/script` component when using the inline script for Google Analytics. See: {{url}}"
|
270
|
+
},
|
232
271
|
schema: [],
|
233
272
|
type: "problem"
|
234
273
|
}
|
235
|
-
}
|
274
|
+
};
|
236
275
|
|
237
276
|
// src/rules/no-assign-module-variable.ts
|
238
|
-
var
|
239
|
-
var
|
277
|
+
var name5 = "no-assign-module-variable";
|
278
|
+
var url5 = `https://nextjs.org/docs/messages/${name5}`;
|
279
|
+
var noAssignModuleVariable = {
|
240
280
|
create: (context) => ({
|
241
281
|
VariableDeclaration: (node) => {
|
242
282
|
const moduleVariableFound = node.declarations.some((declaration) => {
|
243
|
-
if ("
|
244
|
-
return
|
283
|
+
if (declaration.id.type === "Identifier" && declaration.id.name === "module") {
|
284
|
+
return true;
|
245
285
|
}
|
246
286
|
return false;
|
247
287
|
});
|
@@ -249,7 +289,8 @@ var noAssignModuleVariable = defineRule({
|
|
249
289
|
return;
|
250
290
|
}
|
251
291
|
context.report({
|
252
|
-
|
292
|
+
data: { url: url5 },
|
293
|
+
messageId: "noAssignModule",
|
253
294
|
node
|
254
295
|
});
|
255
296
|
}
|
@@ -260,17 +301,20 @@ var noAssignModuleVariable = defineRule({
|
|
260
301
|
recommended: true,
|
261
302
|
url: url5
|
262
303
|
},
|
304
|
+
messages: {
|
305
|
+
noAssignModule: "Do not assign to the variable `module`. See: {{url}}"
|
306
|
+
},
|
263
307
|
schema: [],
|
264
308
|
type: "problem"
|
265
309
|
}
|
266
|
-
}
|
310
|
+
};
|
267
311
|
|
268
312
|
// src/rules/no-async-client-component.ts
|
269
|
-
var
|
313
|
+
var name6 = "no-async-client-component";
|
314
|
+
var url6 = `https://nextjs.org/docs/messages/${name6}`;
|
270
315
|
var description2 = "Prevent client components from being async functions.";
|
271
|
-
var message = `${description2} See: ${url6}`;
|
272
316
|
var isCapitalized = (str) => /[A-Z]/.test(str[0] ?? "");
|
273
|
-
var noAsyncClientComponent =
|
317
|
+
var noAsyncClientComponent = {
|
274
318
|
create: (context) => ({
|
275
319
|
Program: (node) => {
|
276
320
|
let isClientComponent = false;
|
@@ -279,9 +323,10 @@ var noAsyncClientComponent = defineRule({
|
|
279
323
|
isClientComponent = true;
|
280
324
|
}
|
281
325
|
if (block.type === "ExportDefaultDeclaration" && isClientComponent) {
|
282
|
-
if (block.declaration
|
326
|
+
if (block.declaration.type === "FunctionDeclaration" && block.declaration.async && block.declaration.id && isCapitalized(block.declaration.id.name)) {
|
283
327
|
context.report({
|
284
|
-
|
328
|
+
data: { url: url6 },
|
329
|
+
messageId: "noAsyncClientComponent",
|
285
330
|
node: block
|
286
331
|
});
|
287
332
|
}
|
@@ -292,7 +337,7 @@ var noAsyncClientComponent = defineRule({
|
|
292
337
|
return true;
|
293
338
|
}
|
294
339
|
if (localBlock.type === "VariableDeclaration" && localBlock.declarations.find(
|
295
|
-
(declaration) => declaration.id
|
340
|
+
(declaration) => declaration.id.type === "Identifier" && declaration.id.name === targetName
|
296
341
|
)) {
|
297
342
|
return true;
|
298
343
|
}
|
@@ -300,17 +345,19 @@ var noAsyncClientComponent = defineRule({
|
|
300
345
|
});
|
301
346
|
if (functionDeclaration?.type === "FunctionDeclaration" && functionDeclaration.async) {
|
302
347
|
context.report({
|
303
|
-
|
348
|
+
data: { url: url6 },
|
349
|
+
messageId: "noAsyncClientComponent",
|
304
350
|
node: functionDeclaration
|
305
351
|
});
|
306
352
|
}
|
307
353
|
if (functionDeclaration?.type === "VariableDeclaration") {
|
308
354
|
const varDeclarator = functionDeclaration.declarations.find(
|
309
|
-
(declaration) => declaration.id
|
355
|
+
(declaration) => declaration.id.type === "Identifier" && declaration.id.name === targetName
|
310
356
|
);
|
311
357
|
if (varDeclarator?.init?.type === "ArrowFunctionExpression" && varDeclarator.init.async) {
|
312
358
|
context.report({
|
313
|
-
|
359
|
+
data: { url: url6 },
|
360
|
+
messageId: "noAsyncClientComponent",
|
314
361
|
node: functionDeclaration
|
315
362
|
});
|
316
363
|
}
|
@@ -326,16 +373,20 @@ var noAsyncClientComponent = defineRule({
|
|
326
373
|
recommended: true,
|
327
374
|
url: url6
|
328
375
|
},
|
376
|
+
messages: {
|
377
|
+
noAsyncClientComponent: "Prevent client components from being async functions. See: {{url}}"
|
378
|
+
},
|
329
379
|
schema: [],
|
330
380
|
type: "problem"
|
331
381
|
}
|
332
|
-
}
|
382
|
+
};
|
333
383
|
|
334
384
|
// src/rules/no-before-interactive-script-outside-document.ts
|
335
385
|
import * as path from "node:path";
|
336
|
-
var
|
386
|
+
var name7 = "no-before-interactive-script-outside-document";
|
387
|
+
var url7 = `https://nextjs.org/docs/messages/${name7}`;
|
337
388
|
var convertToCorrectSeparator = (str) => str.replaceAll(/[/\\]/g, path.sep);
|
338
|
-
var noBeforeInteractiveScriptOutsideDocument =
|
389
|
+
var noBeforeInteractiveScriptOutsideDocument = {
|
339
390
|
create: (context) => {
|
340
391
|
let scriptImportName = null;
|
341
392
|
return {
|
@@ -351,13 +402,13 @@ var noBeforeInteractiveScriptOutsideDocument = defineRule({
|
|
351
402
|
if (!scriptImportName) {
|
352
403
|
return;
|
353
404
|
}
|
354
|
-
if (node.name && node.name.name !== scriptImportName) {
|
405
|
+
if (node.name.type === "JSXIdentifier" && node.name.name !== scriptImportName) {
|
355
406
|
return;
|
356
407
|
}
|
357
408
|
const strategy = node.attributes.find(
|
358
|
-
(child) => child.name && child.name.name === "strategy"
|
409
|
+
(child) => child.type === "JSXAttribute" && child.name.type === "JSXIdentifier" && child.name.name === "strategy"
|
359
410
|
);
|
360
|
-
if (!strategy?.value || strategy.value.value !== "beforeInteractive") {
|
411
|
+
if (!strategy?.value || strategy.value.type !== "Literal" || strategy.value.value !== "beforeInteractive") {
|
361
412
|
return;
|
362
413
|
}
|
363
414
|
const document = context.filename.split("pages", 2)[1];
|
@@ -365,7 +416,8 @@ var noBeforeInteractiveScriptOutsideDocument = defineRule({
|
|
365
416
|
return;
|
366
417
|
}
|
367
418
|
context.report({
|
368
|
-
|
419
|
+
data: { url: url7 },
|
420
|
+
messageId: "noBeforeInteractiveOutsideDocument",
|
369
421
|
node
|
370
422
|
});
|
371
423
|
}
|
@@ -377,17 +429,21 @@ var noBeforeInteractiveScriptOutsideDocument = defineRule({
|
|
377
429
|
recommended: true,
|
378
430
|
url: url7
|
379
431
|
},
|
432
|
+
messages: {
|
433
|
+
noBeforeInteractiveOutsideDocument: "`next/script`'s `beforeInteractive` strategy should not be used outside of `pages/_document.js`. See: {{url}}"
|
434
|
+
},
|
380
435
|
schema: [],
|
381
436
|
type: "problem"
|
382
437
|
}
|
383
|
-
}
|
438
|
+
};
|
384
439
|
|
385
440
|
// src/rules/no-css-tags.ts
|
386
|
-
var
|
387
|
-
var
|
441
|
+
var name8 = "no-css-tags";
|
442
|
+
var url8 = `https://nextjs.org/docs/messages/${name8}`;
|
443
|
+
var noCssTags = {
|
388
444
|
create: (context) => ({
|
389
445
|
JSXOpeningElement: (node) => {
|
390
|
-
if (node.name.name !== "link") {
|
446
|
+
if (node.name.type !== "JSXIdentifier" || node.name.name !== "link") {
|
391
447
|
return;
|
392
448
|
}
|
393
449
|
if (node.attributes.length === 0) {
|
@@ -397,12 +453,13 @@ var noCssTags = defineRule({
|
|
397
453
|
(attr) => attr.type === "JSXAttribute"
|
398
454
|
);
|
399
455
|
if (attributes.find(
|
400
|
-
(attr) => attr.name.name === "rel" && attr.value.value === "stylesheet"
|
456
|
+
(attr) => attr.name.type === "JSXIdentifier" && attr.name.name === "rel" && attr.value && attr.value.type === "Literal" && attr.value.value === "stylesheet"
|
401
457
|
) && attributes.find(
|
402
|
-
(attr) => attr.name.name === "href" && attr.value.type === "Literal" && !/^https?/.test(attr.value.value)
|
458
|
+
(attr) => attr.name.type === "JSXIdentifier" && attr.name.name === "href" && attr.value && attr.value.type === "Literal" && typeof attr.value.value === "string" && !/^https?/.test(attr.value.value)
|
403
459
|
)) {
|
404
460
|
context.report({
|
405
|
-
|
461
|
+
data: { url: url8 },
|
462
|
+
messageId: "noCssTags",
|
406
463
|
node
|
407
464
|
});
|
408
465
|
}
|
@@ -414,15 +471,19 @@ var noCssTags = defineRule({
|
|
414
471
|
recommended: true,
|
415
472
|
url: url8
|
416
473
|
},
|
474
|
+
messages: {
|
475
|
+
noCssTags: "Do not include stylesheets manually. See: {{url}}"
|
476
|
+
},
|
417
477
|
schema: [],
|
418
478
|
type: "problem"
|
419
479
|
}
|
420
|
-
}
|
480
|
+
};
|
421
481
|
|
422
482
|
// src/rules/no-document-import-in-page.ts
|
423
483
|
import * as path2 from "node:path";
|
424
|
-
var
|
425
|
-
var
|
484
|
+
var name9 = "no-document-import-in-page";
|
485
|
+
var url9 = `https://nextjs.org/docs/messages/${name9}`;
|
486
|
+
var noDocumentImportInPage = {
|
426
487
|
create: (context) => ({
|
427
488
|
ImportDeclaration: (node) => {
|
428
489
|
if (node.source.value !== "next/document") {
|
@@ -434,7 +495,8 @@ var noDocumentImportInPage = defineRule({
|
|
434
495
|
return;
|
435
496
|
}
|
436
497
|
context.report({
|
437
|
-
|
498
|
+
data: { url: url9 },
|
499
|
+
messageId: "noDocumentImportInPage",
|
438
500
|
node
|
439
501
|
});
|
440
502
|
}
|
@@ -445,14 +507,18 @@ var noDocumentImportInPage = defineRule({
|
|
445
507
|
recommended: true,
|
446
508
|
url: url9
|
447
509
|
},
|
510
|
+
messages: {
|
511
|
+
noDocumentImportInPage: "`<Document />` from `next/document` should not be imported outside of `pages/_document.js`. See: {{url}}"
|
512
|
+
},
|
448
513
|
schema: [],
|
449
514
|
type: "problem"
|
450
515
|
}
|
451
|
-
}
|
516
|
+
};
|
452
517
|
|
453
518
|
// src/rules/no-duplicate-head.ts
|
454
|
-
var
|
455
|
-
var
|
519
|
+
var name10 = "no-duplicate-head";
|
520
|
+
var url10 = `https://nextjs.org/docs/messages/${name10}`;
|
521
|
+
var noDuplicateHead = {
|
456
522
|
create: (context) => {
|
457
523
|
const { sourceCode } = context;
|
458
524
|
let documentImportName = null;
|
@@ -460,7 +526,7 @@ var noDuplicateHead = defineRule({
|
|
460
526
|
ImportDeclaration: (node) => {
|
461
527
|
if (node.source.value === "next/document") {
|
462
528
|
const documentImport = node.specifiers.find(
|
463
|
-
(
|
529
|
+
(specifier) => specifier.type === "ImportDefaultSpecifier"
|
464
530
|
);
|
465
531
|
if (documentImport?.local) {
|
466
532
|
documentImportName = documentImport.local.name;
|
@@ -470,21 +536,20 @@ var noDuplicateHead = defineRule({
|
|
470
536
|
ReturnStatement: (node) => {
|
471
537
|
const ancestors = sourceCode.getAncestors(node);
|
472
538
|
const documentClass = ancestors.find(
|
473
|
-
(ancestorNode) => ancestorNode.type === "ClassDeclaration" && ancestorNode.superClass &&
|
539
|
+
(ancestorNode) => ancestorNode.type === "ClassDeclaration" && ancestorNode.superClass && ancestorNode.superClass.type === "Identifier" && ancestorNode.superClass.name === documentImportName
|
474
540
|
);
|
475
541
|
if (!documentClass) {
|
476
542
|
return;
|
477
543
|
}
|
478
|
-
if (node.argument &&
|
479
|
-
node.argument.children) {
|
544
|
+
if (node.argument && node.argument.type === "JSXElement") {
|
480
545
|
const headComponents = node.argument.children.filter(
|
481
|
-
(childrenNode) => childrenNode.openingElement
|
482
|
-
);
|
546
|
+
(childrenNode) => childrenNode.type === "JSXElement" && childrenNode.openingElement.name.type === "JSXIdentifier" && childrenNode.openingElement.name.name === "Head"
|
547
|
+
).filter(Boolean);
|
483
548
|
if (headComponents.length > 1) {
|
484
549
|
for (let i = 1; i < headComponents.length; i++) {
|
485
550
|
context.report({
|
486
|
-
|
487
|
-
|
551
|
+
data: { url: url10 },
|
552
|
+
messageId: "noDuplicateHead",
|
488
553
|
node: headComponents[i]
|
489
554
|
});
|
490
555
|
}
|
@@ -499,28 +564,32 @@ var noDuplicateHead = defineRule({
|
|
499
564
|
recommended: true,
|
500
565
|
url: url10
|
501
566
|
},
|
567
|
+
messages: {
|
568
|
+
noDuplicateHead: "Do not include multiple instances of `<Head/>`. See: {{url}}"
|
569
|
+
},
|
502
570
|
schema: [],
|
503
571
|
type: "problem"
|
504
572
|
}
|
505
|
-
}
|
573
|
+
};
|
506
574
|
|
507
575
|
// src/rules/no-head-element.ts
|
508
576
|
import path3 from "node:path";
|
509
|
-
var
|
510
|
-
var
|
577
|
+
var name11 = "no-head-element";
|
578
|
+
var url11 = `https://nextjs.org/docs/messages/${name11}`;
|
579
|
+
var noHeadElement = {
|
511
580
|
create: (context) => ({
|
512
581
|
JSXOpeningElement: (node) => {
|
513
582
|
const paths = context.filename;
|
514
583
|
const isInAppDir = () => (
|
515
|
-
//
|
516
|
-
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
584
|
+
// Check if we're in the app directory using either platform separator
|
517
585
|
paths.includes(`app${path3.sep}`) || paths.includes(`app${path3.posix.sep}`)
|
518
586
|
);
|
519
|
-
if (node.name.name !== "head" || isInAppDir()) {
|
587
|
+
if (node.name.type !== "JSXIdentifier" || node.name.name !== "head" || isInAppDir()) {
|
520
588
|
return;
|
521
589
|
}
|
522
590
|
context.report({
|
523
|
-
|
591
|
+
data: { url: url11 },
|
592
|
+
messageId: "noHeadElement",
|
524
593
|
node
|
525
594
|
});
|
526
595
|
}
|
@@ -532,15 +601,19 @@ var noHeadElement = defineRule({
|
|
532
601
|
recommended: true,
|
533
602
|
url: url11
|
534
603
|
},
|
604
|
+
messages: {
|
605
|
+
noHeadElement: "Do not use `<head>` element. Use `<Head />` from `next/head` instead. See: {{url}}"
|
606
|
+
},
|
535
607
|
schema: [],
|
536
608
|
type: "problem"
|
537
609
|
}
|
538
|
-
}
|
610
|
+
};
|
539
611
|
|
540
612
|
// src/rules/no-head-import-in-document.ts
|
541
613
|
import * as path4 from "node:path";
|
542
|
-
var
|
543
|
-
var
|
614
|
+
var name12 = "no-head-import-in-document";
|
615
|
+
var url12 = `https://nextjs.org/docs/messages/${name12}`;
|
616
|
+
var noHeadImportInDocument = {
|
544
617
|
create: (context) => ({
|
545
618
|
ImportDeclaration: (node) => {
|
546
619
|
if (node.source.value !== "next/head") {
|
@@ -550,10 +623,11 @@ var noHeadImportInDocument = defineRule({
|
|
550
623
|
if (!document) {
|
551
624
|
return;
|
552
625
|
}
|
553
|
-
const { dir, name } = path4.parse(document);
|
554
|
-
if (
|
626
|
+
const { dir, name: name22 } = path4.parse(document);
|
627
|
+
if (name22.startsWith("_document") || dir === "/_document" && name22 === "index") {
|
555
628
|
context.report({
|
556
|
-
|
629
|
+
data: { document, url: url12 },
|
630
|
+
messageId: "noHeadImportInDocument",
|
557
631
|
node
|
558
632
|
});
|
559
633
|
}
|
@@ -565,10 +639,13 @@ var noHeadImportInDocument = defineRule({
|
|
565
639
|
recommended: true,
|
566
640
|
url: url12
|
567
641
|
},
|
642
|
+
messages: {
|
643
|
+
noHeadImportInDocument: "`next/head` should not be imported in `pages{{document}}`. Use `<Head />` from `next/document` instead. See: {{url}}"
|
644
|
+
},
|
568
645
|
schema: [],
|
569
646
|
type: "problem"
|
570
647
|
}
|
571
|
-
}
|
648
|
+
};
|
572
649
|
|
573
650
|
// src/rules/no-html-link-for-pages.ts
|
574
651
|
import * as fs2 from "node:fs";
|
@@ -583,10 +660,7 @@ var processRootDir = (rootDir) => {
|
|
583
660
|
};
|
584
661
|
var getRootDirs = (context) => {
|
585
662
|
let rootDirs = [context.cwd];
|
586
|
-
const nextSettings =
|
587
|
-
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
588
|
-
context.settings.next || {}
|
589
|
-
);
|
663
|
+
const nextSettings = context.settings.next || {};
|
590
664
|
const rootDir = nextSettings.rootDir;
|
591
665
|
if (typeof rootDir === "string") {
|
592
666
|
rootDirs = processRootDir(rootDir);
|
@@ -649,18 +723,18 @@ var parseUrlForAppDir = (urlprefix, directory) => {
|
|
649
723
|
});
|
650
724
|
return res;
|
651
725
|
};
|
652
|
-
var normalizeURL = (
|
653
|
-
if (!
|
726
|
+
var normalizeURL = (url22) => {
|
727
|
+
if (!url22) {
|
654
728
|
return;
|
655
729
|
}
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
if (
|
660
|
-
return
|
730
|
+
url22 = url22.split("?", 1)[0];
|
731
|
+
url22 = url22.split("#", 1)[0];
|
732
|
+
url22 = url22.replace(/(?<temp1>\/index\.html)$/, "/");
|
733
|
+
if (url22 === "") {
|
734
|
+
return url22;
|
661
735
|
}
|
662
|
-
|
663
|
-
return
|
736
|
+
url22 = url22.endsWith("/") ? url22 : `${url22}/`;
|
737
|
+
return url22;
|
664
738
|
};
|
665
739
|
var normalizeAppPath = (route) => ensureLeadingSlash(
|
666
740
|
route.split("/").reduce((pathname, segment, index, segments) => {
|
@@ -684,7 +758,7 @@ var getUrlFromPagesDirectories = (urlPrefix, directories) => Array.from(
|
|
684
758
|
new Set(
|
685
759
|
directories.flatMap((directory) => parseUrlForPages(urlPrefix, directory)).map(
|
686
760
|
// Since the URLs are normalized we add `^` and `$` to the RegExp to make sure they match exactly.
|
687
|
-
(
|
761
|
+
(url22) => `^${normalizeURL(url22)}$`
|
688
762
|
)
|
689
763
|
)
|
690
764
|
).map((urlReg) => {
|
@@ -696,7 +770,7 @@ var getUrlFromAppDirectory = (urlPrefix, directories) => Array.from(
|
|
696
770
|
new Set(
|
697
771
|
directories.map((directory) => parseUrlForAppDir(urlPrefix, directory)).flat().map(
|
698
772
|
// Since the URLs are normalized we add `^` and `$` to the RegExp to make sure they match exactly.
|
699
|
-
(
|
773
|
+
(url22) => `^${normalizeAppPath(url22)}$`
|
700
774
|
)
|
701
775
|
)
|
702
776
|
).map((urlReg) => {
|
@@ -725,23 +799,27 @@ var pagesDirWarning = execOnce((pagesDirs) => {
|
|
725
799
|
});
|
726
800
|
var fsExistsSyncCache = {};
|
727
801
|
var memoize = (fn) => {
|
728
|
-
const cache =
|
729
|
-
|
802
|
+
const cache = /* @__PURE__ */ new Map();
|
803
|
+
const memoized = (...args) => {
|
730
804
|
const key = JSON.stringify(args);
|
731
|
-
cache
|
732
|
-
|
805
|
+
if (!cache.has(key)) {
|
806
|
+
cache.set(key, fn(...args));
|
807
|
+
}
|
808
|
+
const value = cache.get(key);
|
809
|
+
return value;
|
733
810
|
};
|
811
|
+
return memoized;
|
734
812
|
};
|
735
813
|
var cachedGetUrlFromPagesDirectories = memoize(getUrlFromPagesDirectories);
|
736
814
|
var cachedGetUrlFromAppDirectory = memoize(getUrlFromAppDirectory);
|
737
|
-
var
|
738
|
-
var
|
815
|
+
var name13 = "no-html-link-for-pages";
|
816
|
+
var url13 = `https://nextjs.org/docs/messages/${name13}`;
|
817
|
+
var noHtmlLinkForPages = {
|
739
818
|
/**
|
740
819
|
* Creates an ESLint rule listener.
|
741
820
|
*/
|
742
821
|
create: (context) => {
|
743
|
-
const
|
744
|
-
const [customPagesDirectory] = ruleOptions;
|
822
|
+
const [customPagesDirectory] = context.options;
|
745
823
|
const rootDirs = getRootDirs(context);
|
746
824
|
const pagesDirs = (customPagesDirectory ? [customPagesDirectory] : rootDirs.map((dir) => [
|
747
825
|
path6.join(dir, "pages"),
|
@@ -765,26 +843,26 @@ var noHtmlLinkForPages = defineRule({
|
|
765
843
|
const allUrlRegex = [...pageUrls, ...appDirUrls];
|
766
844
|
return {
|
767
845
|
JSXOpeningElement: (node) => {
|
768
|
-
if (node.name.name !== "a") {
|
846
|
+
if (node.name.type !== "JSXIdentifier" || node.name.name !== "a") {
|
769
847
|
return;
|
770
848
|
}
|
771
849
|
if (node.attributes.length === 0) {
|
772
850
|
return;
|
773
851
|
}
|
774
852
|
const target = node.attributes.find(
|
775
|
-
(attr) => attr.type === "JSXAttribute" && attr.name.name === "target"
|
853
|
+
(attr) => attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && attr.name.name === "target"
|
776
854
|
);
|
777
|
-
if (target && target.value.value === "_blank") {
|
855
|
+
if (target?.value?.type === "Literal" && target.value.value === "_blank") {
|
778
856
|
return;
|
779
857
|
}
|
780
858
|
const href = node.attributes.find(
|
781
|
-
(attr) => attr.type === "JSXAttribute" && attr.name.name === "href"
|
859
|
+
(attr) => attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && attr.name.name === "href"
|
782
860
|
);
|
783
|
-
if (!href || href.value
|
861
|
+
if (!href?.value || href.value.type !== "Literal") {
|
784
862
|
return;
|
785
863
|
}
|
786
864
|
const hasDownloadAttr = node.attributes.find(
|
787
|
-
(attr) => attr.type === "JSXAttribute" && attr.name.name === "download"
|
865
|
+
(attr) => attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && attr.name.name === "download"
|
788
866
|
);
|
789
867
|
if (hasDownloadAttr) {
|
790
868
|
return;
|
@@ -796,7 +874,8 @@ var noHtmlLinkForPages = defineRule({
|
|
796
874
|
allUrlRegex.forEach((foundUrl) => {
|
797
875
|
if (hrefPath && foundUrl.test(normalizeURL(hrefPath))) {
|
798
876
|
context.report({
|
799
|
-
|
877
|
+
data: { hrefPath, url: url13 },
|
878
|
+
messageId: "noHtmlLinkForPages",
|
800
879
|
node
|
801
880
|
});
|
802
881
|
}
|
@@ -811,6 +890,9 @@ var noHtmlLinkForPages = defineRule({
|
|
811
890
|
recommended: true,
|
812
891
|
url: url13
|
813
892
|
},
|
893
|
+
messages: {
|
894
|
+
noHtmlLinkForPages: "Do not use an `<a>` element to navigate to `{{hrefPath}}`. Use `<Link />` from `next/link` instead. See: {{url}}"
|
895
|
+
},
|
814
896
|
schema: [
|
815
897
|
{
|
816
898
|
oneOf: [
|
@@ -829,31 +911,35 @@ var noHtmlLinkForPages = defineRule({
|
|
829
911
|
],
|
830
912
|
type: "problem"
|
831
913
|
}
|
832
|
-
}
|
914
|
+
};
|
833
915
|
|
834
916
|
// src/rules/no-img-element.ts
|
835
917
|
import path7 from "node:path";
|
836
|
-
var
|
837
|
-
var
|
918
|
+
var name14 = "no-img-element";
|
919
|
+
var url14 = `https://nextjs.org/docs/messages/${name14}`;
|
920
|
+
var noImgElement = {
|
838
921
|
create: (context) => {
|
839
922
|
const relativePath = context.filename.replace(path7.sep, "/").replace(context.cwd, "").replace(/^\//, "");
|
840
923
|
const isAppDir = /^(?<temp1>src\/)?app\//.test(relativePath);
|
841
924
|
return {
|
842
925
|
JSXOpeningElement: (node) => {
|
843
|
-
if (node.name.name !== "img") {
|
926
|
+
if (node.name.type !== "JSXIdentifier" || node.name.name !== "img") {
|
844
927
|
return;
|
845
928
|
}
|
846
929
|
if (node.attributes.length === 0) {
|
847
930
|
return;
|
848
931
|
}
|
849
|
-
|
932
|
+
const parentJSXElement = node.parent;
|
933
|
+
const grandParentJSXElement = parentJSXElement?.parent;
|
934
|
+
if (grandParentJSXElement?.openingElement?.name?.type === "JSXIdentifier" && grandParentJSXElement?.openingElement?.name?.name === "picture") {
|
850
935
|
return;
|
851
936
|
}
|
852
937
|
if (isAppDir && /\/opengraph-image|twitter-image|icon\.\w+$/.test(relativePath)) {
|
853
938
|
return;
|
854
939
|
}
|
855
940
|
context.report({
|
856
|
-
|
941
|
+
data: { url: url14 },
|
942
|
+
messageId: "noImgElement",
|
857
943
|
node
|
858
944
|
});
|
859
945
|
}
|
@@ -866,16 +952,20 @@ var noImgElement = defineRule({
|
|
866
952
|
recommended: true,
|
867
953
|
url: url14
|
868
954
|
},
|
955
|
+
messages: {
|
956
|
+
noImgElement: "Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` or a custom image loader to automatically optimize images. This may incur additional usage or cost from your provider. See: {{url}}"
|
957
|
+
},
|
869
958
|
schema: [],
|
870
959
|
type: "problem"
|
871
960
|
}
|
872
|
-
}
|
961
|
+
};
|
873
962
|
|
874
963
|
// src/rules/no-page-custom-font.ts
|
875
964
|
import { posix as posix2, sep as sep3 } from "node:path";
|
876
|
-
var
|
965
|
+
var name15 = "no-page-custom-font";
|
966
|
+
var url15 = `https://nextjs.org/docs/messages/${name15}`;
|
877
967
|
var isIdentifierMatch = (id1, id2) => id1 === null && id2 === null || id1 && id2 && id1.name === id2.name;
|
878
|
-
var noPageCustomFont =
|
968
|
+
var noPageCustomFont = {
|
879
969
|
create: (context) => {
|
880
970
|
const { sourceCode } = context;
|
881
971
|
const paths = context.filename.split("pages");
|
@@ -883,12 +973,9 @@ var noPageCustomFont = defineRule({
|
|
883
973
|
if (!page) {
|
884
974
|
return {};
|
885
975
|
}
|
886
|
-
const isDocument = (
|
887
|
-
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
888
|
-
page.startsWith(`${sep3}_document`) || page.startsWith(`${posix2.sep}_document`)
|
889
|
-
);
|
976
|
+
const isDocument = page.startsWith(`${sep3}_document`) || page.startsWith(`${posix2.sep}_document`);
|
890
977
|
let documentImportName;
|
891
|
-
let localDefaultExportId;
|
978
|
+
let localDefaultExportId = null;
|
892
979
|
let exportDeclarationType;
|
893
980
|
return {
|
894
981
|
ExportDefaultDeclaration: (node) => {
|
@@ -897,14 +984,14 @@ var noPageCustomFont = defineRule({
|
|
897
984
|
localDefaultExportId = node.declaration.id;
|
898
985
|
return;
|
899
986
|
}
|
900
|
-
if (node.declaration.type === "ClassDeclaration" && node.declaration.superClass &&
|
987
|
+
if (node.declaration.type === "ClassDeclaration" && node.declaration.superClass && node.declaration.superClass.type === "Identifier" && node.declaration.superClass.name === documentImportName) {
|
901
988
|
localDefaultExportId = node.declaration.id;
|
902
989
|
}
|
903
990
|
},
|
904
991
|
ImportDeclaration: (node) => {
|
905
992
|
if (node.source.value === "next/document") {
|
906
993
|
const documentImport = node.specifiers.find(
|
907
|
-
(
|
994
|
+
(specifier) => specifier.type === "ImportDefaultSpecifier"
|
908
995
|
);
|
909
996
|
if (documentImport?.local) {
|
910
997
|
documentImportName = documentImport.local.name;
|
@@ -912,7 +999,7 @@ var noPageCustomFont = defineRule({
|
|
912
999
|
}
|
913
1000
|
},
|
914
1001
|
JSXOpeningElement: (node) => {
|
915
|
-
if (node.name.name !== "link") {
|
1002
|
+
if (node.name.type !== "JSXIdentifier" || node.name.name !== "link") {
|
916
1003
|
return;
|
917
1004
|
}
|
918
1005
|
const ancestors = sourceCode.getAncestors(node);
|
@@ -920,6 +1007,9 @@ var noPageCustomFont = defineRule({
|
|
920
1007
|
const program = ancestors.find(
|
921
1008
|
(ancestor) => ancestor.type === "Program"
|
922
1009
|
);
|
1010
|
+
if (!program?.tokens) {
|
1011
|
+
return;
|
1012
|
+
}
|
923
1013
|
for (let i = 0; i <= program.tokens.length - 1; i++) {
|
924
1014
|
if (localDefaultExportId) {
|
925
1015
|
break;
|
@@ -927,10 +1017,20 @@ var noPageCustomFont = defineRule({
|
|
927
1017
|
const token = program.tokens[i];
|
928
1018
|
if (token?.type === "Keyword" && token.value === "export") {
|
929
1019
|
const nextToken = program.tokens[i + 1];
|
930
|
-
if (nextToken && nextToken.
|
1020
|
+
if (nextToken && nextToken.value === "default") {
|
931
1021
|
const maybeIdentifier = program.tokens[i + 2];
|
932
1022
|
if (maybeIdentifier && maybeIdentifier.type === "Identifier") {
|
933
|
-
localDefaultExportId = {
|
1023
|
+
localDefaultExportId = {
|
1024
|
+
decorators: [],
|
1025
|
+
loc: {
|
1026
|
+
end: { column: 0, line: 0 },
|
1027
|
+
start: { column: 0, line: 0 }
|
1028
|
+
},
|
1029
|
+
name: maybeIdentifier.value,
|
1030
|
+
optional: false,
|
1031
|
+
range: [0, 0],
|
1032
|
+
type: "Identifier"
|
1033
|
+
};
|
934
1034
|
}
|
935
1035
|
}
|
936
1036
|
}
|
@@ -938,7 +1038,7 @@ var noPageCustomFont = defineRule({
|
|
938
1038
|
}
|
939
1039
|
const parentComponent = ancestors.find((ancestor) => {
|
940
1040
|
if (exportDeclarationType === "ClassDeclaration") {
|
941
|
-
return ancestor.type === exportDeclarationType && "superClass" in ancestor && ancestor.superClass &&
|
1041
|
+
return ancestor.type === exportDeclarationType && "superClass" in ancestor && ancestor.superClass && ancestor.superClass.type === "Identifier" && ancestor.superClass.name === documentImportName;
|
942
1042
|
}
|
943
1043
|
if ("id" in ancestor) {
|
944
1044
|
if (exportDeclarationType === "FunctionDeclaration") {
|
@@ -958,10 +1058,9 @@ var noPageCustomFont = defineRule({
|
|
958
1058
|
const hrefValue = attributes.value("href");
|
959
1059
|
const isGoogleFont = typeof hrefValue === "string" && hrefValue.startsWith("https://fonts.googleapis.com/css");
|
960
1060
|
if (isGoogleFont) {
|
961
|
-
const end = `This is discouraged. See: ${url15}`;
|
962
|
-
const message2 = isDocument ? `Using \`<link />\` outside of \`<Head>\` will disable automatic font optimization. ${end}` : `Custom fonts not added in \`pages/_document.js\` will only load for a single page. ${end}`;
|
963
1061
|
context.report({
|
964
|
-
|
1062
|
+
data: { url: url15 },
|
1063
|
+
messageId: isDocument ? "noPageCustomFontOutsideHead" : "noPageCustomFont",
|
965
1064
|
node
|
966
1065
|
});
|
967
1066
|
}
|
@@ -974,16 +1073,36 @@ var noPageCustomFont = defineRule({
|
|
974
1073
|
recommended: true,
|
975
1074
|
url: url15
|
976
1075
|
},
|
1076
|
+
messages: {
|
1077
|
+
noPageCustomFont: "Custom fonts not added in `pages/_document.js` will only load for a single page. This is discouraged. See: {{url}}",
|
1078
|
+
noPageCustomFontOutsideHead: "Using `<link />` outside of `<Head>` will disable automatic font optimization. This is discouraged. See: {{url}}"
|
1079
|
+
},
|
977
1080
|
schema: [],
|
978
1081
|
type: "problem"
|
979
1082
|
}
|
980
|
-
}
|
1083
|
+
};
|
981
1084
|
|
982
1085
|
// src/rules/no-script-component-in-head.ts
|
983
|
-
var
|
984
|
-
var
|
1086
|
+
var name16 = "no-script-component-in-head";
|
1087
|
+
var url16 = `https://nextjs.org/docs/messages/${name16}`;
|
1088
|
+
var noScriptComponentInHead = {
|
985
1089
|
create: (context) => {
|
986
1090
|
let isNextHead = null;
|
1091
|
+
const findNestedScriptComponent = (node) => {
|
1092
|
+
if (node.type !== "JSXElement") {
|
1093
|
+
return null;
|
1094
|
+
}
|
1095
|
+
if (node.openingElement.name.type === "JSXIdentifier" && node.openingElement.name.name === "Script") {
|
1096
|
+
return node;
|
1097
|
+
}
|
1098
|
+
for (const child of node.children) {
|
1099
|
+
const scriptComponent = findNestedScriptComponent(child);
|
1100
|
+
if (scriptComponent) {
|
1101
|
+
return scriptComponent;
|
1102
|
+
}
|
1103
|
+
}
|
1104
|
+
return null;
|
1105
|
+
};
|
987
1106
|
return {
|
988
1107
|
ImportDeclaration: (node) => {
|
989
1108
|
if (node.source.value === "next/head") {
|
@@ -994,15 +1113,14 @@ var noScriptComponentInHead = defineRule({
|
|
994
1113
|
if (!isNextHead) {
|
995
1114
|
return;
|
996
1115
|
}
|
997
|
-
if (node.openingElement
|
1116
|
+
if (node.openingElement.name.type !== "JSXIdentifier" || node.openingElement.name.name !== "Head") {
|
998
1117
|
return;
|
999
1118
|
}
|
1000
|
-
const scriptTag = node
|
1001
|
-
(child) => child.openingElement?.name && child.openingElement.name.name === "Script"
|
1002
|
-
);
|
1119
|
+
const scriptTag = findNestedScriptComponent(node);
|
1003
1120
|
if (scriptTag) {
|
1004
1121
|
context.report({
|
1005
|
-
|
1122
|
+
data: { url: url16 },
|
1123
|
+
messageId: "noScriptComponentInHead",
|
1006
1124
|
node
|
1007
1125
|
});
|
1008
1126
|
}
|
@@ -1015,30 +1133,35 @@ var noScriptComponentInHead = defineRule({
|
|
1015
1133
|
recommended: true,
|
1016
1134
|
url: url16
|
1017
1135
|
},
|
1136
|
+
messages: {
|
1137
|
+
noScriptComponentInHead: "`next/script` should not be used in `next/head` component. Move `<Script />` outside of `<Head>` instead. See: {{url}}"
|
1138
|
+
},
|
1018
1139
|
schema: [],
|
1019
1140
|
type: "problem"
|
1020
1141
|
}
|
1021
|
-
}
|
1142
|
+
};
|
1022
1143
|
|
1023
1144
|
// src/rules/no-styled-jsx-in-document.ts
|
1024
1145
|
import * as path8 from "node:path";
|
1025
|
-
var
|
1026
|
-
var
|
1146
|
+
var name17 = "no-styled-jsx-in-document";
|
1147
|
+
var url17 = `https://nextjs.org/docs/messages/${name17}`;
|
1148
|
+
var noStyledJsxInDocument = {
|
1027
1149
|
create: (context) => ({
|
1028
1150
|
JSXOpeningElement: (node) => {
|
1029
1151
|
const document = context.filename.split("pages", 2)[1];
|
1030
1152
|
if (!document) {
|
1031
1153
|
return;
|
1032
1154
|
}
|
1033
|
-
const { dir, name } = path8.parse(document);
|
1034
|
-
if (!(
|
1155
|
+
const { dir, name: name22 } = path8.parse(document);
|
1156
|
+
if (!(name22.startsWith("_document") || dir === "/_document" && name22 === "index")) {
|
1035
1157
|
return;
|
1036
1158
|
}
|
1037
|
-
if (node.name.name === "style" && node.attributes.find(
|
1038
|
-
(attr) => attr.type === "JSXAttribute" && attr.name.name === "jsx"
|
1159
|
+
if (node.name.type === "JSXIdentifier" && node.name.name === "style" && node.attributes.find(
|
1160
|
+
(attr) => attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && attr.name.name === "jsx"
|
1039
1161
|
)) {
|
1040
1162
|
context.report({
|
1041
|
-
|
1163
|
+
data: { url: url17 },
|
1164
|
+
messageId: "noStyledJsxInDocument",
|
1042
1165
|
node
|
1043
1166
|
});
|
1044
1167
|
}
|
@@ -1050,26 +1173,33 @@ var noStyledJsxInDocument = defineRule({
|
|
1050
1173
|
recommended: true,
|
1051
1174
|
url: url17
|
1052
1175
|
},
|
1176
|
+
messages: {
|
1177
|
+
noStyledJsxInDocument: "`styled-jsx` should not be used in `pages/_document.js`. See: {{url}}"
|
1178
|
+
},
|
1053
1179
|
schema: [],
|
1054
1180
|
type: "problem"
|
1055
1181
|
}
|
1056
|
-
}
|
1182
|
+
};
|
1057
1183
|
|
1058
1184
|
// src/rules/no-sync-scripts.ts
|
1059
|
-
var
|
1060
|
-
var
|
1185
|
+
var name18 = "no-sync-scripts";
|
1186
|
+
var url18 = `https://nextjs.org/docs/messages/${name18}`;
|
1187
|
+
var noSyncScripts = {
|
1061
1188
|
create: (context) => ({
|
1062
1189
|
JSXOpeningElement: (node) => {
|
1063
|
-
if (node.name.name !== "script") {
|
1190
|
+
if (node.name.type !== "JSXIdentifier" || node.name.name !== "script") {
|
1064
1191
|
return;
|
1065
1192
|
}
|
1066
1193
|
if (node.attributes.length === 0) {
|
1067
1194
|
return;
|
1068
1195
|
}
|
1069
|
-
const attributeNames = node.attributes.filter(
|
1196
|
+
const attributeNames = node.attributes.filter(
|
1197
|
+
(attr) => attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier"
|
1198
|
+
).map((attr) => attr.name.name);
|
1070
1199
|
if (attributeNames.includes("src") && !attributeNames.includes("async") && !attributeNames.includes("defer")) {
|
1071
1200
|
context.report({
|
1072
|
-
|
1201
|
+
data: { url: url18 },
|
1202
|
+
messageId: "noSyncScripts",
|
1073
1203
|
node
|
1074
1204
|
});
|
1075
1205
|
}
|
@@ -1081,21 +1211,25 @@ var noSyncScripts = defineRule({
|
|
1081
1211
|
recommended: true,
|
1082
1212
|
url: url18
|
1083
1213
|
},
|
1214
|
+
messages: {
|
1215
|
+
noSyncScripts: "Synchronous scripts should not be used. See: {{url}}"
|
1216
|
+
},
|
1084
1217
|
schema: [],
|
1085
1218
|
type: "problem"
|
1086
1219
|
}
|
1087
|
-
}
|
1220
|
+
};
|
1088
1221
|
|
1089
1222
|
// src/rules/no-title-in-document-head.ts
|
1090
|
-
var
|
1091
|
-
var
|
1223
|
+
var name19 = "no-title-in-document-head";
|
1224
|
+
var url19 = `https://nextjs.org/docs/messages/${name19}`;
|
1225
|
+
var noTitleInDocumentHead = {
|
1092
1226
|
create: (context) => {
|
1093
1227
|
let headFromNextDocument = false;
|
1094
1228
|
return {
|
1095
1229
|
ImportDeclaration: (node) => {
|
1096
1230
|
if (node.source.value === "next/document") {
|
1097
1231
|
if (node.specifiers.some(
|
1098
|
-
(
|
1232
|
+
(specifier) => specifier.type === "ImportSpecifier" && specifier.local.name === "Head"
|
1099
1233
|
)) {
|
1100
1234
|
headFromNextDocument = true;
|
1101
1235
|
}
|
@@ -1105,15 +1239,16 @@ var noTitleInDocumentHead = defineRule({
|
|
1105
1239
|
if (!headFromNextDocument) {
|
1106
1240
|
return;
|
1107
1241
|
}
|
1108
|
-
if (node.openingElement
|
1242
|
+
if (node.openingElement.name.type !== "JSXIdentifier" || node.openingElement.name.name !== "Head") {
|
1109
1243
|
return;
|
1110
1244
|
}
|
1111
1245
|
const titleTag = node.children.find(
|
1112
|
-
(child) => child.
|
1246
|
+
(child) => child.type === "JSXElement" && child.openingElement.name.type === "JSXIdentifier" && child.openingElement.name.name === "title"
|
1113
1247
|
);
|
1114
1248
|
if (titleTag) {
|
1115
1249
|
context.report({
|
1116
|
-
|
1250
|
+
data: { url: url19 },
|
1251
|
+
messageId: "noTitleInDocumentHead",
|
1117
1252
|
node: titleTag
|
1118
1253
|
});
|
1119
1254
|
}
|
@@ -1126,10 +1261,13 @@ var noTitleInDocumentHead = defineRule({
|
|
1126
1261
|
recommended: true,
|
1127
1262
|
url: url19
|
1128
1263
|
},
|
1264
|
+
messages: {
|
1265
|
+
noTitleInDocumentHead: "Do not use `<title>` element with `<Head />` component from `next/document`. Titles should defined at the page-level using `<Head />` from `next/head` instead. See: {{url}}"
|
1266
|
+
},
|
1129
1267
|
schema: [],
|
1130
1268
|
type: "problem"
|
1131
1269
|
}
|
1132
|
-
}
|
1270
|
+
};
|
1133
1271
|
|
1134
1272
|
// src/rules/no-typos.ts
|
1135
1273
|
import * as path9 from "node:path";
|
@@ -1139,6 +1277,8 @@ var NEXT_EXPORT_FUNCTIONS = [
|
|
1139
1277
|
"getServerSideProps"
|
1140
1278
|
];
|
1141
1279
|
var THRESHOLD = 1;
|
1280
|
+
var name20 = "no-typos";
|
1281
|
+
var url20 = `https://nextjs.org/docs/messages/${name20}`;
|
1142
1282
|
var minDistance = (a, b) => {
|
1143
1283
|
const m = a.length;
|
1144
1284
|
const n = b.length;
|
@@ -1154,28 +1294,29 @@ var minDistance = (a, b) => {
|
|
1154
1294
|
const currentRow = [i + 1];
|
1155
1295
|
for (let j = 0; j < n; j++) {
|
1156
1296
|
const s2 = b[j];
|
1157
|
-
const insertions = previousRow[j + 1] + 1;
|
1158
|
-
const deletions = currentRow[j] + 1;
|
1159
|
-
const substitutions = previousRow[j] + Number(s1 !== s2);
|
1297
|
+
const insertions = (previousRow[j + 1] ?? Infinity) + 1;
|
1298
|
+
const deletions = (currentRow[j] ?? Infinity) + 1;
|
1299
|
+
const substitutions = (previousRow[j] ?? Infinity) + Number(s1 !== s2);
|
1160
1300
|
currentRow.push(Math.min(insertions, deletions, substitutions));
|
1161
1301
|
}
|
1162
1302
|
previousRow = currentRow;
|
1163
1303
|
}
|
1164
1304
|
return previousRow[previousRow.length - 1];
|
1165
1305
|
};
|
1166
|
-
var noTypos =
|
1306
|
+
var noTypos = {
|
1167
1307
|
create: (context) => {
|
1168
|
-
const checkTypos = (node,
|
1169
|
-
if (NEXT_EXPORT_FUNCTIONS.includes(
|
1308
|
+
const checkTypos = (node, functionName) => {
|
1309
|
+
if (NEXT_EXPORT_FUNCTIONS.includes(functionName)) {
|
1170
1310
|
return;
|
1171
1311
|
}
|
1172
1312
|
const potentialTypos = NEXT_EXPORT_FUNCTIONS.map((o) => ({
|
1173
|
-
distance: minDistance(o,
|
1313
|
+
distance: minDistance(o, functionName) ?? Infinity,
|
1174
1314
|
option: o
|
1175
1315
|
})).filter(({ distance }) => distance <= THRESHOLD && distance > 0).sort((a, b) => a.distance - b.distance);
|
1176
1316
|
if (potentialTypos.length) {
|
1177
1317
|
context.report({
|
1178
|
-
|
1318
|
+
data: { functionName, suggestion: potentialTypos[0]?.option ?? "" },
|
1319
|
+
messageId: "noTypos",
|
1179
1320
|
node
|
1180
1321
|
});
|
1181
1322
|
}
|
@@ -1192,15 +1333,16 @@ var noTypos = defineRule({
|
|
1192
1333
|
}
|
1193
1334
|
switch (decl.type) {
|
1194
1335
|
case "FunctionDeclaration": {
|
1195
|
-
|
1336
|
+
if (decl.id) {
|
1337
|
+
checkTypos(node, decl.id.name);
|
1338
|
+
}
|
1196
1339
|
break;
|
1197
1340
|
}
|
1198
1341
|
case "VariableDeclaration": {
|
1199
1342
|
decl.declarations.forEach((d) => {
|
1200
|
-
if (d.id.type
|
1201
|
-
|
1343
|
+
if (d.id.type === "Identifier") {
|
1344
|
+
checkTypos(node, d.id.name);
|
1202
1345
|
}
|
1203
|
-
checkTypos(node, d.id.name);
|
1204
1346
|
});
|
1205
1347
|
break;
|
1206
1348
|
}
|
@@ -1214,14 +1356,20 @@ var noTypos = defineRule({
|
|
1214
1356
|
meta: {
|
1215
1357
|
docs: {
|
1216
1358
|
description: "Prevent common typos in Next.js data fetching functions.",
|
1217
|
-
recommended: true
|
1359
|
+
recommended: true,
|
1360
|
+
url: url20
|
1361
|
+
},
|
1362
|
+
messages: {
|
1363
|
+
noTypos: "{{functionName}} may be a typo. Did you mean {{suggestion}}?"
|
1218
1364
|
},
|
1219
1365
|
schema: [],
|
1220
1366
|
type: "problem"
|
1221
1367
|
}
|
1222
|
-
}
|
1368
|
+
};
|
1223
1369
|
|
1224
1370
|
// src/rules/no-unwanted-polyfillio.ts
|
1371
|
+
var name21 = "no-unwanted-polyfillio";
|
1372
|
+
var url21 = `https://nextjs.org/docs/messages/${name21}`;
|
1225
1373
|
var NEXT_POLYFILLED_FEATURES = [
|
1226
1374
|
"Array.prototype.@@iterator",
|
1227
1375
|
"Array.prototype.at",
|
@@ -1296,27 +1444,29 @@ var NEXT_POLYFILLED_FEATURES = [
|
|
1296
1444
|
"es7"
|
1297
1445
|
// contains polyfilled 'Array.prototype.includes', 'String.prototype.padEnd' and 'String.prototype.padStart'
|
1298
1446
|
];
|
1299
|
-
var
|
1300
|
-
var noUnwantedPolyfillio = defineRule({
|
1447
|
+
var noUnwantedPolyfillio = {
|
1301
1448
|
create: (context) => {
|
1302
1449
|
let scriptImport = null;
|
1303
1450
|
return {
|
1304
1451
|
ImportDeclaration: (node) => {
|
1305
|
-
if (node.source
|
1306
|
-
|
1452
|
+
if (node.source.value === "next/script" && node.specifiers.length > 0) {
|
1453
|
+
const specifier = node.specifiers[0];
|
1454
|
+
if (specifier && specifier.type === "ImportDefaultSpecifier") {
|
1455
|
+
scriptImport = specifier.local.name;
|
1456
|
+
}
|
1307
1457
|
}
|
1308
1458
|
},
|
1309
1459
|
JSXOpeningElement: (node) => {
|
1310
|
-
if (node.name
|
1460
|
+
if (node.name.type !== "JSXIdentifier" || node.name.name !== "script" && node.name.name !== scriptImport) {
|
1311
1461
|
return;
|
1312
1462
|
}
|
1313
1463
|
if (node.attributes.length === 0) {
|
1314
1464
|
return;
|
1315
1465
|
}
|
1316
1466
|
const srcNode = node.attributes.find(
|
1317
|
-
(attr) => attr.type === "JSXAttribute" && attr.name.name === "src"
|
1467
|
+
(attr) => attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && attr.name.name === "src"
|
1318
1468
|
);
|
1319
|
-
if (!srcNode || srcNode.value.type !== "Literal") {
|
1469
|
+
if (!srcNode?.value || srcNode.value.type !== "Literal" || typeof srcNode.value.value !== "string") {
|
1320
1470
|
return;
|
1321
1471
|
}
|
1322
1472
|
const src = srcNode.value.value;
|
@@ -1324,15 +1474,18 @@ var noUnwantedPolyfillio = defineRule({
|
|
1324
1474
|
src.startsWith("https://polyfill-fastly.net/") || src.startsWith("https://polyfill-fastly.io/") || // https://blog.cloudflare.com/polyfill-io-now-available-on-cdnjs-reduce-your-supply-chain-risk
|
1325
1475
|
src.startsWith("https://cdnjs.cloudflare.com/polyfill/")) {
|
1326
1476
|
const featureQueryString = new URL(src).searchParams.get("features");
|
1327
|
-
const featuresRequested =
|
1477
|
+
const featuresRequested = featureQueryString?.split(",") ?? [""];
|
1328
1478
|
const unwantedFeatures = featuresRequested.filter(
|
1329
1479
|
(feature) => NEXT_POLYFILLED_FEATURES.includes(feature)
|
1330
1480
|
);
|
1331
1481
|
if (unwantedFeatures.length > 0) {
|
1332
1482
|
context.report({
|
1333
|
-
|
1334
|
-
", "
|
1335
|
-
|
1483
|
+
data: {
|
1484
|
+
features: unwantedFeatures.join(", "),
|
1485
|
+
url: url21,
|
1486
|
+
verb: unwantedFeatures.length > 1 ? "are" : "is"
|
1487
|
+
},
|
1488
|
+
messageId: "noUnwantedPolyfillio",
|
1336
1489
|
node
|
1337
1490
|
});
|
1338
1491
|
}
|
@@ -1342,18 +1495,27 @@ var noUnwantedPolyfillio = defineRule({
|
|
1342
1495
|
},
|
1343
1496
|
meta: {
|
1344
1497
|
docs: {
|
1345
|
-
category: "HTML",
|
1346
1498
|
description: "Prevent duplicate polyfills from Polyfill.io.",
|
1347
|
-
|
1348
|
-
|
1499
|
+
url: url21
|
1500
|
+
},
|
1501
|
+
messages: {
|
1502
|
+
noUnwantedPolyfillio: "No duplicate polyfills from Polyfill.io are allowed. {{features}} {{verb}} already shipped with Next.js. See: {{url}}"
|
1349
1503
|
},
|
1350
1504
|
schema: [],
|
1351
1505
|
type: "problem"
|
1352
1506
|
}
|
1353
|
-
}
|
1507
|
+
};
|
1354
1508
|
|
1355
1509
|
// src/index.ts
|
1510
|
+
var pkg = JSON.parse(
|
1511
|
+
fs3.readFileSync(new URL("../package.json", import.meta.url), "utf8")
|
1512
|
+
);
|
1356
1513
|
var plugin = {
|
1514
|
+
meta: {
|
1515
|
+
name: pkg.name,
|
1516
|
+
version: pkg.version
|
1517
|
+
},
|
1518
|
+
// rule definitions
|
1357
1519
|
rules: {
|
1358
1520
|
"google-font-display": googleFontDisplay,
|
1359
1521
|
"google-font-preconnect": googleFontPreconnect,
|
@@ -1379,70 +1541,43 @@ var plugin = {
|
|
1379
1541
|
}
|
1380
1542
|
};
|
1381
1543
|
var recommendedRules = {
|
1382
|
-
|
1383
|
-
"google-font-
|
1384
|
-
"
|
1385
|
-
|
1386
|
-
"
|
1387
|
-
"
|
1388
|
-
"no-
|
1389
|
-
"no-
|
1390
|
-
"no-
|
1391
|
-
"no-
|
1392
|
-
"no-
|
1393
|
-
"no-
|
1394
|
-
"no-
|
1395
|
-
"no-
|
1396
|
-
"no-
|
1397
|
-
"no-
|
1398
|
-
"no-
|
1399
|
-
"no-
|
1400
|
-
"no-
|
1401
|
-
"no-
|
1402
|
-
"no-
|
1403
|
-
"no-typos": "warn",
|
1404
|
-
"no-unwanted-polyfillio": "warn"
|
1405
|
-
};
|
1406
|
-
var coreWebVitalsRules = {
|
1407
|
-
...recommendedRules,
|
1408
|
-
"no-html-link-for-pages": "error",
|
1409
|
-
"no-sync-scripts": "error"
|
1544
|
+
"nextjs/google-font-display": "warn",
|
1545
|
+
"nextjs/google-font-preconnect": "warn",
|
1546
|
+
"nextjs/inline-script-id": "warn",
|
1547
|
+
"nextjs/next-script-for-ga": "warn",
|
1548
|
+
"nextjs/no-assign-module-variable": "warn",
|
1549
|
+
"nextjs/no-async-client-component": "warn",
|
1550
|
+
"nextjs/no-before-interactive-script-outside-document": "warn",
|
1551
|
+
"nextjs/no-css-tags": "warn",
|
1552
|
+
"nextjs/no-document-import-in-page": "warn",
|
1553
|
+
"nextjs/no-duplicate-head": "warn",
|
1554
|
+
"nextjs/no-head-element": "warn",
|
1555
|
+
"nextjs/no-head-import-in-document": "warn",
|
1556
|
+
"nextjs/no-html-link-for-pages": "warn",
|
1557
|
+
"nextjs/no-img-element": "warn",
|
1558
|
+
"nextjs/no-page-custom-font": "warn",
|
1559
|
+
"nextjs/no-script-component-in-head": "warn",
|
1560
|
+
"nextjs/no-styled-jsx-in-document": "warn",
|
1561
|
+
"nextjs/no-sync-scripts": "warn",
|
1562
|
+
"nextjs/no-title-in-document-head": "warn",
|
1563
|
+
"nextjs/no-typos": "warn",
|
1564
|
+
"nextjs/no-unwanted-polyfillio": "warn"
|
1410
1565
|
};
|
1411
|
-
var
|
1412
|
-
|
1413
|
-
|
1414
|
-
|
1415
|
-
}
|
1566
|
+
var recommendedConfig = {
|
1567
|
+
files: ["**/*.{js,jsx,ts,tsx}"],
|
1568
|
+
plugins: {
|
1569
|
+
nextjs: plugin
|
1570
|
+
},
|
1571
|
+
rules: recommendedRules
|
1416
1572
|
};
|
1417
|
-
var
|
1418
|
-
var recommendedLegacyConfig = createRuleConfig(recommendedRules, false);
|
1419
|
-
var coreWebVitalsFlatConfig = createRuleConfig(coreWebVitalsRules, true);
|
1420
|
-
var coreWebVitalsLegacyConfig = createRuleConfig(coreWebVitalsRules, false);
|
1421
|
-
var index_default = {
|
1573
|
+
var nextjsPlugin = {
|
1422
1574
|
...plugin,
|
1423
1575
|
configs: {
|
1424
|
-
|
1425
|
-
|
1426
|
-
*/
|
1427
|
-
"core-web-vitals": coreWebVitalsLegacyConfig,
|
1428
|
-
/**
|
1429
|
-
* Flat config (ESLint v9+) with Core Web Vitals rules (recommended with some warnings upgrade to errors)
|
1430
|
-
*/
|
1431
|
-
"core-web-vitals/flat": coreWebVitalsFlatConfig,
|
1432
|
-
/**
|
1433
|
-
* Legacy config (ESLint < v9) with recommended rules
|
1434
|
-
*/
|
1435
|
-
recommended: recommendedLegacyConfig,
|
1436
|
-
/**
|
1437
|
-
* Flat config (ESLint v9+) with recommended rules
|
1438
|
-
*/
|
1439
|
-
"recommended/flat": recommendedFlatConfig
|
1440
|
-
},
|
1441
|
-
name: "nextjs"
|
1576
|
+
recommended: recommendedConfig
|
1577
|
+
}
|
1442
1578
|
};
|
1443
|
-
var
|
1579
|
+
var index_default = nextjsPlugin;
|
1444
1580
|
export {
|
1445
|
-
index_default as default
|
1446
|
-
rules
|
1581
|
+
index_default as default
|
1447
1582
|
};
|
1448
1583
|
//# sourceMappingURL=index.js.map
|