eslint-plugin-nextjs 0.1.2 → 1.0.0
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 +398 -260
- package/dist/index.js.map +1 -1
- package/package.json +15 -10
- 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";
|
@@ -649,18 +726,18 @@ var parseUrlForAppDir = (urlprefix, directory) => {
|
|
649
726
|
});
|
650
727
|
return res;
|
651
728
|
};
|
652
|
-
var normalizeURL = (
|
653
|
-
if (!
|
729
|
+
var normalizeURL = (url22) => {
|
730
|
+
if (!url22) {
|
654
731
|
return;
|
655
732
|
}
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
if (
|
660
|
-
return
|
733
|
+
url22 = url22.split("?", 1)[0];
|
734
|
+
url22 = url22.split("#", 1)[0];
|
735
|
+
url22 = url22.replace(/(?<temp1>\/index\.html)$/, "/");
|
736
|
+
if (url22 === "") {
|
737
|
+
return url22;
|
661
738
|
}
|
662
|
-
|
663
|
-
return
|
739
|
+
url22 = url22.endsWith("/") ? url22 : `${url22}/`;
|
740
|
+
return url22;
|
664
741
|
};
|
665
742
|
var normalizeAppPath = (route) => ensureLeadingSlash(
|
666
743
|
route.split("/").reduce((pathname, segment, index, segments) => {
|
@@ -684,7 +761,7 @@ var getUrlFromPagesDirectories = (urlPrefix, directories) => Array.from(
|
|
684
761
|
new Set(
|
685
762
|
directories.flatMap((directory) => parseUrlForPages(urlPrefix, directory)).map(
|
686
763
|
// Since the URLs are normalized we add `^` and `$` to the RegExp to make sure they match exactly.
|
687
|
-
(
|
764
|
+
(url22) => `^${normalizeURL(url22)}$`
|
688
765
|
)
|
689
766
|
)
|
690
767
|
).map((urlReg) => {
|
@@ -696,7 +773,7 @@ var getUrlFromAppDirectory = (urlPrefix, directories) => Array.from(
|
|
696
773
|
new Set(
|
697
774
|
directories.map((directory) => parseUrlForAppDir(urlPrefix, directory)).flat().map(
|
698
775
|
// Since the URLs are normalized we add `^` and `$` to the RegExp to make sure they match exactly.
|
699
|
-
(
|
776
|
+
(url22) => `^${normalizeAppPath(url22)}$`
|
700
777
|
)
|
701
778
|
)
|
702
779
|
).map((urlReg) => {
|
@@ -725,23 +802,27 @@ var pagesDirWarning = execOnce((pagesDirs) => {
|
|
725
802
|
});
|
726
803
|
var fsExistsSyncCache = {};
|
727
804
|
var memoize = (fn) => {
|
728
|
-
const cache =
|
729
|
-
|
805
|
+
const cache = /* @__PURE__ */ new Map();
|
806
|
+
const memoized = (...args) => {
|
730
807
|
const key = JSON.stringify(args);
|
731
|
-
cache
|
732
|
-
|
808
|
+
if (!cache.has(key)) {
|
809
|
+
cache.set(key, fn(...args));
|
810
|
+
}
|
811
|
+
const value = cache.get(key);
|
812
|
+
return value;
|
733
813
|
};
|
814
|
+
return memoized;
|
734
815
|
};
|
735
816
|
var cachedGetUrlFromPagesDirectories = memoize(getUrlFromPagesDirectories);
|
736
817
|
var cachedGetUrlFromAppDirectory = memoize(getUrlFromAppDirectory);
|
737
|
-
var
|
738
|
-
var
|
818
|
+
var name13 = "no-html-link-for-pages";
|
819
|
+
var url13 = `https://nextjs.org/docs/messages/${name13}`;
|
820
|
+
var noHtmlLinkForPages = {
|
739
821
|
/**
|
740
822
|
* Creates an ESLint rule listener.
|
741
823
|
*/
|
742
824
|
create: (context) => {
|
743
|
-
const
|
744
|
-
const [customPagesDirectory] = ruleOptions;
|
825
|
+
const [customPagesDirectory] = context.options;
|
745
826
|
const rootDirs = getRootDirs(context);
|
746
827
|
const pagesDirs = (customPagesDirectory ? [customPagesDirectory] : rootDirs.map((dir) => [
|
747
828
|
path6.join(dir, "pages"),
|
@@ -765,26 +846,26 @@ var noHtmlLinkForPages = defineRule({
|
|
765
846
|
const allUrlRegex = [...pageUrls, ...appDirUrls];
|
766
847
|
return {
|
767
848
|
JSXOpeningElement: (node) => {
|
768
|
-
if (node.name.name !== "a") {
|
849
|
+
if (node.name.type !== "JSXIdentifier" || node.name.name !== "a") {
|
769
850
|
return;
|
770
851
|
}
|
771
852
|
if (node.attributes.length === 0) {
|
772
853
|
return;
|
773
854
|
}
|
774
855
|
const target = node.attributes.find(
|
775
|
-
(attr) => attr.type === "JSXAttribute" && attr.name.name === "target"
|
856
|
+
(attr) => attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && attr.name.name === "target"
|
776
857
|
);
|
777
|
-
if (target && target.value.value === "_blank") {
|
858
|
+
if (target?.value?.type === "Literal" && target.value.value === "_blank") {
|
778
859
|
return;
|
779
860
|
}
|
780
861
|
const href = node.attributes.find(
|
781
|
-
(attr) => attr.type === "JSXAttribute" && attr.name.name === "href"
|
862
|
+
(attr) => attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && attr.name.name === "href"
|
782
863
|
);
|
783
|
-
if (!href || href.value
|
864
|
+
if (!href?.value || href.value.type !== "Literal") {
|
784
865
|
return;
|
785
866
|
}
|
786
867
|
const hasDownloadAttr = node.attributes.find(
|
787
|
-
(attr) => attr.type === "JSXAttribute" && attr.name.name === "download"
|
868
|
+
(attr) => attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && attr.name.name === "download"
|
788
869
|
);
|
789
870
|
if (hasDownloadAttr) {
|
790
871
|
return;
|
@@ -796,7 +877,8 @@ var noHtmlLinkForPages = defineRule({
|
|
796
877
|
allUrlRegex.forEach((foundUrl) => {
|
797
878
|
if (hrefPath && foundUrl.test(normalizeURL(hrefPath))) {
|
798
879
|
context.report({
|
799
|
-
|
880
|
+
data: { hrefPath, url: url13 },
|
881
|
+
messageId: "noHtmlLinkForPages",
|
800
882
|
node
|
801
883
|
});
|
802
884
|
}
|
@@ -811,6 +893,9 @@ var noHtmlLinkForPages = defineRule({
|
|
811
893
|
recommended: true,
|
812
894
|
url: url13
|
813
895
|
},
|
896
|
+
messages: {
|
897
|
+
noHtmlLinkForPages: "Do not use an `<a>` element to navigate to `{{hrefPath}}`. Use `<Link />` from `next/link` instead. See: {{url}}"
|
898
|
+
},
|
814
899
|
schema: [
|
815
900
|
{
|
816
901
|
oneOf: [
|
@@ -829,31 +914,35 @@ var noHtmlLinkForPages = defineRule({
|
|
829
914
|
],
|
830
915
|
type: "problem"
|
831
916
|
}
|
832
|
-
}
|
917
|
+
};
|
833
918
|
|
834
919
|
// src/rules/no-img-element.ts
|
835
920
|
import path7 from "node:path";
|
836
|
-
var
|
837
|
-
var
|
921
|
+
var name14 = "no-img-element";
|
922
|
+
var url14 = `https://nextjs.org/docs/messages/${name14}`;
|
923
|
+
var noImgElement = {
|
838
924
|
create: (context) => {
|
839
925
|
const relativePath = context.filename.replace(path7.sep, "/").replace(context.cwd, "").replace(/^\//, "");
|
840
926
|
const isAppDir = /^(?<temp1>src\/)?app\//.test(relativePath);
|
841
927
|
return {
|
842
928
|
JSXOpeningElement: (node) => {
|
843
|
-
if (node.name.name !== "img") {
|
929
|
+
if (node.name.type !== "JSXIdentifier" || node.name.name !== "img") {
|
844
930
|
return;
|
845
931
|
}
|
846
932
|
if (node.attributes.length === 0) {
|
847
933
|
return;
|
848
934
|
}
|
849
|
-
|
935
|
+
const parentJSXElement = node.parent;
|
936
|
+
const grandParentJSXElement = parentJSXElement?.parent;
|
937
|
+
if (grandParentJSXElement?.openingElement?.name?.type === "JSXIdentifier" && grandParentJSXElement?.openingElement?.name?.name === "picture") {
|
850
938
|
return;
|
851
939
|
}
|
852
940
|
if (isAppDir && /\/opengraph-image|twitter-image|icon\.\w+$/.test(relativePath)) {
|
853
941
|
return;
|
854
942
|
}
|
855
943
|
context.report({
|
856
|
-
|
944
|
+
data: { url: url14 },
|
945
|
+
messageId: "noImgElement",
|
857
946
|
node
|
858
947
|
});
|
859
948
|
}
|
@@ -866,16 +955,20 @@ var noImgElement = defineRule({
|
|
866
955
|
recommended: true,
|
867
956
|
url: url14
|
868
957
|
},
|
958
|
+
messages: {
|
959
|
+
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}}"
|
960
|
+
},
|
869
961
|
schema: [],
|
870
962
|
type: "problem"
|
871
963
|
}
|
872
|
-
}
|
964
|
+
};
|
873
965
|
|
874
966
|
// src/rules/no-page-custom-font.ts
|
875
967
|
import { posix as posix2, sep as sep3 } from "node:path";
|
876
|
-
var
|
968
|
+
var name15 = "no-page-custom-font";
|
969
|
+
var url15 = `https://nextjs.org/docs/messages/${name15}`;
|
877
970
|
var isIdentifierMatch = (id1, id2) => id1 === null && id2 === null || id1 && id2 && id1.name === id2.name;
|
878
|
-
var noPageCustomFont =
|
971
|
+
var noPageCustomFont = {
|
879
972
|
create: (context) => {
|
880
973
|
const { sourceCode } = context;
|
881
974
|
const paths = context.filename.split("pages");
|
@@ -883,12 +976,9 @@ var noPageCustomFont = defineRule({
|
|
883
976
|
if (!page) {
|
884
977
|
return {};
|
885
978
|
}
|
886
|
-
const isDocument = (
|
887
|
-
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
888
|
-
page.startsWith(`${sep3}_document`) || page.startsWith(`${posix2.sep}_document`)
|
889
|
-
);
|
979
|
+
const isDocument = page.startsWith(`${sep3}_document`) || page.startsWith(`${posix2.sep}_document`);
|
890
980
|
let documentImportName;
|
891
|
-
let localDefaultExportId;
|
981
|
+
let localDefaultExportId = null;
|
892
982
|
let exportDeclarationType;
|
893
983
|
return {
|
894
984
|
ExportDefaultDeclaration: (node) => {
|
@@ -897,14 +987,14 @@ var noPageCustomFont = defineRule({
|
|
897
987
|
localDefaultExportId = node.declaration.id;
|
898
988
|
return;
|
899
989
|
}
|
900
|
-
if (node.declaration.type === "ClassDeclaration" && node.declaration.superClass &&
|
990
|
+
if (node.declaration.type === "ClassDeclaration" && node.declaration.superClass && node.declaration.superClass.type === "Identifier" && node.declaration.superClass.name === documentImportName) {
|
901
991
|
localDefaultExportId = node.declaration.id;
|
902
992
|
}
|
903
993
|
},
|
904
994
|
ImportDeclaration: (node) => {
|
905
995
|
if (node.source.value === "next/document") {
|
906
996
|
const documentImport = node.specifiers.find(
|
907
|
-
(
|
997
|
+
(specifier) => specifier.type === "ImportDefaultSpecifier"
|
908
998
|
);
|
909
999
|
if (documentImport?.local) {
|
910
1000
|
documentImportName = documentImport.local.name;
|
@@ -912,7 +1002,7 @@ var noPageCustomFont = defineRule({
|
|
912
1002
|
}
|
913
1003
|
},
|
914
1004
|
JSXOpeningElement: (node) => {
|
915
|
-
if (node.name.name !== "link") {
|
1005
|
+
if (node.name.type !== "JSXIdentifier" || node.name.name !== "link") {
|
916
1006
|
return;
|
917
1007
|
}
|
918
1008
|
const ancestors = sourceCode.getAncestors(node);
|
@@ -920,6 +1010,9 @@ var noPageCustomFont = defineRule({
|
|
920
1010
|
const program = ancestors.find(
|
921
1011
|
(ancestor) => ancestor.type === "Program"
|
922
1012
|
);
|
1013
|
+
if (!program?.tokens) {
|
1014
|
+
return;
|
1015
|
+
}
|
923
1016
|
for (let i = 0; i <= program.tokens.length - 1; i++) {
|
924
1017
|
if (localDefaultExportId) {
|
925
1018
|
break;
|
@@ -927,10 +1020,20 @@ var noPageCustomFont = defineRule({
|
|
927
1020
|
const token = program.tokens[i];
|
928
1021
|
if (token?.type === "Keyword" && token.value === "export") {
|
929
1022
|
const nextToken = program.tokens[i + 1];
|
930
|
-
if (nextToken && nextToken.
|
1023
|
+
if (nextToken && nextToken.value === "default") {
|
931
1024
|
const maybeIdentifier = program.tokens[i + 2];
|
932
1025
|
if (maybeIdentifier && maybeIdentifier.type === "Identifier") {
|
933
|
-
localDefaultExportId = {
|
1026
|
+
localDefaultExportId = {
|
1027
|
+
decorators: [],
|
1028
|
+
loc: {
|
1029
|
+
end: { column: 0, line: 0 },
|
1030
|
+
start: { column: 0, line: 0 }
|
1031
|
+
},
|
1032
|
+
name: maybeIdentifier.value,
|
1033
|
+
optional: false,
|
1034
|
+
range: [0, 0],
|
1035
|
+
type: "Identifier"
|
1036
|
+
};
|
934
1037
|
}
|
935
1038
|
}
|
936
1039
|
}
|
@@ -938,7 +1041,7 @@ var noPageCustomFont = defineRule({
|
|
938
1041
|
}
|
939
1042
|
const parentComponent = ancestors.find((ancestor) => {
|
940
1043
|
if (exportDeclarationType === "ClassDeclaration") {
|
941
|
-
return ancestor.type === exportDeclarationType && "superClass" in ancestor && ancestor.superClass &&
|
1044
|
+
return ancestor.type === exportDeclarationType && "superClass" in ancestor && ancestor.superClass && ancestor.superClass.type === "Identifier" && ancestor.superClass.name === documentImportName;
|
942
1045
|
}
|
943
1046
|
if ("id" in ancestor) {
|
944
1047
|
if (exportDeclarationType === "FunctionDeclaration") {
|
@@ -958,10 +1061,9 @@ var noPageCustomFont = defineRule({
|
|
958
1061
|
const hrefValue = attributes.value("href");
|
959
1062
|
const isGoogleFont = typeof hrefValue === "string" && hrefValue.startsWith("https://fonts.googleapis.com/css");
|
960
1063
|
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
1064
|
context.report({
|
964
|
-
|
1065
|
+
data: { url: url15 },
|
1066
|
+
messageId: isDocument ? "noPageCustomFontOutsideHead" : "noPageCustomFont",
|
965
1067
|
node
|
966
1068
|
});
|
967
1069
|
}
|
@@ -974,16 +1076,36 @@ var noPageCustomFont = defineRule({
|
|
974
1076
|
recommended: true,
|
975
1077
|
url: url15
|
976
1078
|
},
|
1079
|
+
messages: {
|
1080
|
+
noPageCustomFont: "Custom fonts not added in `pages/_document.js` will only load for a single page. This is discouraged. See: {{url}}",
|
1081
|
+
noPageCustomFontOutsideHead: "Using `<link />` outside of `<Head>` will disable automatic font optimization. This is discouraged. See: {{url}}"
|
1082
|
+
},
|
977
1083
|
schema: [],
|
978
1084
|
type: "problem"
|
979
1085
|
}
|
980
|
-
}
|
1086
|
+
};
|
981
1087
|
|
982
1088
|
// src/rules/no-script-component-in-head.ts
|
983
|
-
var
|
984
|
-
var
|
1089
|
+
var name16 = "no-script-component-in-head";
|
1090
|
+
var url16 = `https://nextjs.org/docs/messages/${name16}`;
|
1091
|
+
var noScriptComponentInHead = {
|
985
1092
|
create: (context) => {
|
986
1093
|
let isNextHead = null;
|
1094
|
+
const findNestedScriptComponent = (node) => {
|
1095
|
+
if (node.type !== "JSXElement") {
|
1096
|
+
return null;
|
1097
|
+
}
|
1098
|
+
if (node.openingElement.name.type === "JSXIdentifier" && node.openingElement.name.name === "Script") {
|
1099
|
+
return node;
|
1100
|
+
}
|
1101
|
+
for (const child of node.children) {
|
1102
|
+
const scriptComponent = findNestedScriptComponent(child);
|
1103
|
+
if (scriptComponent) {
|
1104
|
+
return scriptComponent;
|
1105
|
+
}
|
1106
|
+
}
|
1107
|
+
return null;
|
1108
|
+
};
|
987
1109
|
return {
|
988
1110
|
ImportDeclaration: (node) => {
|
989
1111
|
if (node.source.value === "next/head") {
|
@@ -994,15 +1116,14 @@ var noScriptComponentInHead = defineRule({
|
|
994
1116
|
if (!isNextHead) {
|
995
1117
|
return;
|
996
1118
|
}
|
997
|
-
if (node.openingElement
|
1119
|
+
if (node.openingElement.name.type !== "JSXIdentifier" || node.openingElement.name.name !== "Head") {
|
998
1120
|
return;
|
999
1121
|
}
|
1000
|
-
const scriptTag = node
|
1001
|
-
(child) => child.openingElement?.name && child.openingElement.name.name === "Script"
|
1002
|
-
);
|
1122
|
+
const scriptTag = findNestedScriptComponent(node);
|
1003
1123
|
if (scriptTag) {
|
1004
1124
|
context.report({
|
1005
|
-
|
1125
|
+
data: { url: url16 },
|
1126
|
+
messageId: "noScriptComponentInHead",
|
1006
1127
|
node
|
1007
1128
|
});
|
1008
1129
|
}
|
@@ -1015,30 +1136,35 @@ var noScriptComponentInHead = defineRule({
|
|
1015
1136
|
recommended: true,
|
1016
1137
|
url: url16
|
1017
1138
|
},
|
1139
|
+
messages: {
|
1140
|
+
noScriptComponentInHead: "`next/script` should not be used in `next/head` component. Move `<Script />` outside of `<Head>` instead. See: {{url}}"
|
1141
|
+
},
|
1018
1142
|
schema: [],
|
1019
1143
|
type: "problem"
|
1020
1144
|
}
|
1021
|
-
}
|
1145
|
+
};
|
1022
1146
|
|
1023
1147
|
// src/rules/no-styled-jsx-in-document.ts
|
1024
1148
|
import * as path8 from "node:path";
|
1025
|
-
var
|
1026
|
-
var
|
1149
|
+
var name17 = "no-styled-jsx-in-document";
|
1150
|
+
var url17 = `https://nextjs.org/docs/messages/${name17}`;
|
1151
|
+
var noStyledJsxInDocument = {
|
1027
1152
|
create: (context) => ({
|
1028
1153
|
JSXOpeningElement: (node) => {
|
1029
1154
|
const document = context.filename.split("pages", 2)[1];
|
1030
1155
|
if (!document) {
|
1031
1156
|
return;
|
1032
1157
|
}
|
1033
|
-
const { dir, name } = path8.parse(document);
|
1034
|
-
if (!(
|
1158
|
+
const { dir, name: name22 } = path8.parse(document);
|
1159
|
+
if (!(name22.startsWith("_document") || dir === "/_document" && name22 === "index")) {
|
1035
1160
|
return;
|
1036
1161
|
}
|
1037
|
-
if (node.name.name === "style" && node.attributes.find(
|
1038
|
-
(attr) => attr.type === "JSXAttribute" && attr.name.name === "jsx"
|
1162
|
+
if (node.name.type === "JSXIdentifier" && node.name.name === "style" && node.attributes.find(
|
1163
|
+
(attr) => attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && attr.name.name === "jsx"
|
1039
1164
|
)) {
|
1040
1165
|
context.report({
|
1041
|
-
|
1166
|
+
data: { url: url17 },
|
1167
|
+
messageId: "noStyledJsxInDocument",
|
1042
1168
|
node
|
1043
1169
|
});
|
1044
1170
|
}
|
@@ -1050,26 +1176,33 @@ var noStyledJsxInDocument = defineRule({
|
|
1050
1176
|
recommended: true,
|
1051
1177
|
url: url17
|
1052
1178
|
},
|
1179
|
+
messages: {
|
1180
|
+
noStyledJsxInDocument: "`styled-jsx` should not be used in `pages/_document.js`. See: {{url}}"
|
1181
|
+
},
|
1053
1182
|
schema: [],
|
1054
1183
|
type: "problem"
|
1055
1184
|
}
|
1056
|
-
}
|
1185
|
+
};
|
1057
1186
|
|
1058
1187
|
// src/rules/no-sync-scripts.ts
|
1059
|
-
var
|
1060
|
-
var
|
1188
|
+
var name18 = "no-sync-scripts";
|
1189
|
+
var url18 = `https://nextjs.org/docs/messages/${name18}`;
|
1190
|
+
var noSyncScripts = {
|
1061
1191
|
create: (context) => ({
|
1062
1192
|
JSXOpeningElement: (node) => {
|
1063
|
-
if (node.name.name !== "script") {
|
1193
|
+
if (node.name.type !== "JSXIdentifier" || node.name.name !== "script") {
|
1064
1194
|
return;
|
1065
1195
|
}
|
1066
1196
|
if (node.attributes.length === 0) {
|
1067
1197
|
return;
|
1068
1198
|
}
|
1069
|
-
const attributeNames = node.attributes.filter(
|
1199
|
+
const attributeNames = node.attributes.filter(
|
1200
|
+
(attr) => attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier"
|
1201
|
+
).map((attr) => attr.name.name);
|
1070
1202
|
if (attributeNames.includes("src") && !attributeNames.includes("async") && !attributeNames.includes("defer")) {
|
1071
1203
|
context.report({
|
1072
|
-
|
1204
|
+
data: { url: url18 },
|
1205
|
+
messageId: "noSyncScripts",
|
1073
1206
|
node
|
1074
1207
|
});
|
1075
1208
|
}
|
@@ -1081,21 +1214,25 @@ var noSyncScripts = defineRule({
|
|
1081
1214
|
recommended: true,
|
1082
1215
|
url: url18
|
1083
1216
|
},
|
1217
|
+
messages: {
|
1218
|
+
noSyncScripts: "Synchronous scripts should not be used. See: {{url}}"
|
1219
|
+
},
|
1084
1220
|
schema: [],
|
1085
1221
|
type: "problem"
|
1086
1222
|
}
|
1087
|
-
}
|
1223
|
+
};
|
1088
1224
|
|
1089
1225
|
// src/rules/no-title-in-document-head.ts
|
1090
|
-
var
|
1091
|
-
var
|
1226
|
+
var name19 = "no-title-in-document-head";
|
1227
|
+
var url19 = `https://nextjs.org/docs/messages/${name19}`;
|
1228
|
+
var noTitleInDocumentHead = {
|
1092
1229
|
create: (context) => {
|
1093
1230
|
let headFromNextDocument = false;
|
1094
1231
|
return {
|
1095
1232
|
ImportDeclaration: (node) => {
|
1096
1233
|
if (node.source.value === "next/document") {
|
1097
1234
|
if (node.specifiers.some(
|
1098
|
-
(
|
1235
|
+
(specifier) => specifier.type === "ImportSpecifier" && specifier.local.name === "Head"
|
1099
1236
|
)) {
|
1100
1237
|
headFromNextDocument = true;
|
1101
1238
|
}
|
@@ -1105,15 +1242,16 @@ var noTitleInDocumentHead = defineRule({
|
|
1105
1242
|
if (!headFromNextDocument) {
|
1106
1243
|
return;
|
1107
1244
|
}
|
1108
|
-
if (node.openingElement
|
1245
|
+
if (node.openingElement.name.type !== "JSXIdentifier" || node.openingElement.name.name !== "Head") {
|
1109
1246
|
return;
|
1110
1247
|
}
|
1111
1248
|
const titleTag = node.children.find(
|
1112
|
-
(child) => child.
|
1249
|
+
(child) => child.type === "JSXElement" && child.openingElement.name.type === "JSXIdentifier" && child.openingElement.name.name === "title"
|
1113
1250
|
);
|
1114
1251
|
if (titleTag) {
|
1115
1252
|
context.report({
|
1116
|
-
|
1253
|
+
data: { url: url19 },
|
1254
|
+
messageId: "noTitleInDocumentHead",
|
1117
1255
|
node: titleTag
|
1118
1256
|
});
|
1119
1257
|
}
|
@@ -1126,10 +1264,13 @@ var noTitleInDocumentHead = defineRule({
|
|
1126
1264
|
recommended: true,
|
1127
1265
|
url: url19
|
1128
1266
|
},
|
1267
|
+
messages: {
|
1268
|
+
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}}"
|
1269
|
+
},
|
1129
1270
|
schema: [],
|
1130
1271
|
type: "problem"
|
1131
1272
|
}
|
1132
|
-
}
|
1273
|
+
};
|
1133
1274
|
|
1134
1275
|
// src/rules/no-typos.ts
|
1135
1276
|
import * as path9 from "node:path";
|
@@ -1139,6 +1280,8 @@ var NEXT_EXPORT_FUNCTIONS = [
|
|
1139
1280
|
"getServerSideProps"
|
1140
1281
|
];
|
1141
1282
|
var THRESHOLD = 1;
|
1283
|
+
var name20 = "no-typos";
|
1284
|
+
var url20 = `https://nextjs.org/docs/messages/${name20}`;
|
1142
1285
|
var minDistance = (a, b) => {
|
1143
1286
|
const m = a.length;
|
1144
1287
|
const n = b.length;
|
@@ -1154,28 +1297,29 @@ var minDistance = (a, b) => {
|
|
1154
1297
|
const currentRow = [i + 1];
|
1155
1298
|
for (let j = 0; j < n; j++) {
|
1156
1299
|
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);
|
1300
|
+
const insertions = (previousRow[j + 1] ?? Infinity) + 1;
|
1301
|
+
const deletions = (currentRow[j] ?? Infinity) + 1;
|
1302
|
+
const substitutions = (previousRow[j] ?? Infinity) + Number(s1 !== s2);
|
1160
1303
|
currentRow.push(Math.min(insertions, deletions, substitutions));
|
1161
1304
|
}
|
1162
1305
|
previousRow = currentRow;
|
1163
1306
|
}
|
1164
1307
|
return previousRow[previousRow.length - 1];
|
1165
1308
|
};
|
1166
|
-
var noTypos =
|
1309
|
+
var noTypos = {
|
1167
1310
|
create: (context) => {
|
1168
|
-
const checkTypos = (node,
|
1169
|
-
if (NEXT_EXPORT_FUNCTIONS.includes(
|
1311
|
+
const checkTypos = (node, functionName) => {
|
1312
|
+
if (NEXT_EXPORT_FUNCTIONS.includes(functionName)) {
|
1170
1313
|
return;
|
1171
1314
|
}
|
1172
1315
|
const potentialTypos = NEXT_EXPORT_FUNCTIONS.map((o) => ({
|
1173
|
-
distance: minDistance(o,
|
1316
|
+
distance: minDistance(o, functionName) ?? Infinity,
|
1174
1317
|
option: o
|
1175
1318
|
})).filter(({ distance }) => distance <= THRESHOLD && distance > 0).sort((a, b) => a.distance - b.distance);
|
1176
1319
|
if (potentialTypos.length) {
|
1177
1320
|
context.report({
|
1178
|
-
|
1321
|
+
data: { functionName, suggestion: potentialTypos[0]?.option ?? "" },
|
1322
|
+
messageId: "noTypos",
|
1179
1323
|
node
|
1180
1324
|
});
|
1181
1325
|
}
|
@@ -1192,15 +1336,16 @@ var noTypos = defineRule({
|
|
1192
1336
|
}
|
1193
1337
|
switch (decl.type) {
|
1194
1338
|
case "FunctionDeclaration": {
|
1195
|
-
|
1339
|
+
if (decl.id) {
|
1340
|
+
checkTypos(node, decl.id.name);
|
1341
|
+
}
|
1196
1342
|
break;
|
1197
1343
|
}
|
1198
1344
|
case "VariableDeclaration": {
|
1199
1345
|
decl.declarations.forEach((d) => {
|
1200
|
-
if (d.id.type
|
1201
|
-
|
1346
|
+
if (d.id.type === "Identifier") {
|
1347
|
+
checkTypos(node, d.id.name);
|
1202
1348
|
}
|
1203
|
-
checkTypos(node, d.id.name);
|
1204
1349
|
});
|
1205
1350
|
break;
|
1206
1351
|
}
|
@@ -1214,14 +1359,20 @@ var noTypos = defineRule({
|
|
1214
1359
|
meta: {
|
1215
1360
|
docs: {
|
1216
1361
|
description: "Prevent common typos in Next.js data fetching functions.",
|
1217
|
-
recommended: true
|
1362
|
+
recommended: true,
|
1363
|
+
url: url20
|
1364
|
+
},
|
1365
|
+
messages: {
|
1366
|
+
noTypos: "{{functionName}} may be a typo. Did you mean {{suggestion}}?"
|
1218
1367
|
},
|
1219
1368
|
schema: [],
|
1220
1369
|
type: "problem"
|
1221
1370
|
}
|
1222
|
-
}
|
1371
|
+
};
|
1223
1372
|
|
1224
1373
|
// src/rules/no-unwanted-polyfillio.ts
|
1374
|
+
var name21 = "no-unwanted-polyfillio";
|
1375
|
+
var url21 = `https://nextjs.org/docs/messages/${name21}`;
|
1225
1376
|
var NEXT_POLYFILLED_FEATURES = [
|
1226
1377
|
"Array.prototype.@@iterator",
|
1227
1378
|
"Array.prototype.at",
|
@@ -1296,27 +1447,29 @@ var NEXT_POLYFILLED_FEATURES = [
|
|
1296
1447
|
"es7"
|
1297
1448
|
// contains polyfilled 'Array.prototype.includes', 'String.prototype.padEnd' and 'String.prototype.padStart'
|
1298
1449
|
];
|
1299
|
-
var
|
1300
|
-
var noUnwantedPolyfillio = defineRule({
|
1450
|
+
var noUnwantedPolyfillio = {
|
1301
1451
|
create: (context) => {
|
1302
1452
|
let scriptImport = null;
|
1303
1453
|
return {
|
1304
1454
|
ImportDeclaration: (node) => {
|
1305
|
-
if (node.source
|
1306
|
-
|
1455
|
+
if (node.source.value === "next/script" && node.specifiers.length > 0) {
|
1456
|
+
const specifier = node.specifiers[0];
|
1457
|
+
if (specifier && specifier.type === "ImportDefaultSpecifier") {
|
1458
|
+
scriptImport = specifier.local.name;
|
1459
|
+
}
|
1307
1460
|
}
|
1308
1461
|
},
|
1309
1462
|
JSXOpeningElement: (node) => {
|
1310
|
-
if (node.name
|
1463
|
+
if (node.name.type !== "JSXIdentifier" || node.name.name !== "script" && node.name.name !== scriptImport) {
|
1311
1464
|
return;
|
1312
1465
|
}
|
1313
1466
|
if (node.attributes.length === 0) {
|
1314
1467
|
return;
|
1315
1468
|
}
|
1316
1469
|
const srcNode = node.attributes.find(
|
1317
|
-
(attr) => attr.type === "JSXAttribute" && attr.name.name === "src"
|
1470
|
+
(attr) => attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && attr.name.name === "src"
|
1318
1471
|
);
|
1319
|
-
if (!srcNode || srcNode.value.type !== "Literal") {
|
1472
|
+
if (!srcNode?.value || srcNode.value.type !== "Literal" || typeof srcNode.value.value !== "string") {
|
1320
1473
|
return;
|
1321
1474
|
}
|
1322
1475
|
const src = srcNode.value.value;
|
@@ -1324,15 +1477,18 @@ var noUnwantedPolyfillio = defineRule({
|
|
1324
1477
|
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
1478
|
src.startsWith("https://cdnjs.cloudflare.com/polyfill/")) {
|
1326
1479
|
const featureQueryString = new URL(src).searchParams.get("features");
|
1327
|
-
const featuresRequested =
|
1480
|
+
const featuresRequested = featureQueryString?.split(",") ?? [""];
|
1328
1481
|
const unwantedFeatures = featuresRequested.filter(
|
1329
1482
|
(feature) => NEXT_POLYFILLED_FEATURES.includes(feature)
|
1330
1483
|
);
|
1331
1484
|
if (unwantedFeatures.length > 0) {
|
1332
1485
|
context.report({
|
1333
|
-
|
1334
|
-
", "
|
1335
|
-
|
1486
|
+
data: {
|
1487
|
+
features: unwantedFeatures.join(", "),
|
1488
|
+
url: url21,
|
1489
|
+
verb: unwantedFeatures.length > 1 ? "are" : "is"
|
1490
|
+
},
|
1491
|
+
messageId: "noUnwantedPolyfillio",
|
1336
1492
|
node
|
1337
1493
|
});
|
1338
1494
|
}
|
@@ -1342,18 +1498,27 @@ var noUnwantedPolyfillio = defineRule({
|
|
1342
1498
|
},
|
1343
1499
|
meta: {
|
1344
1500
|
docs: {
|
1345
|
-
category: "HTML",
|
1346
1501
|
description: "Prevent duplicate polyfills from Polyfill.io.",
|
1347
|
-
|
1348
|
-
|
1502
|
+
url: url21
|
1503
|
+
},
|
1504
|
+
messages: {
|
1505
|
+
noUnwantedPolyfillio: "No duplicate polyfills from Polyfill.io are allowed. {{features}} {{verb}} already shipped with Next.js. See: {{url}}"
|
1349
1506
|
},
|
1350
1507
|
schema: [],
|
1351
1508
|
type: "problem"
|
1352
1509
|
}
|
1353
|
-
}
|
1510
|
+
};
|
1354
1511
|
|
1355
1512
|
// src/index.ts
|
1513
|
+
var pkg = JSON.parse(
|
1514
|
+
fs3.readFileSync(new URL("../package.json", import.meta.url), "utf8")
|
1515
|
+
);
|
1356
1516
|
var plugin = {
|
1517
|
+
meta: {
|
1518
|
+
name: pkg.name,
|
1519
|
+
version: pkg.version
|
1520
|
+
},
|
1521
|
+
// rule definitions
|
1357
1522
|
rules: {
|
1358
1523
|
"google-font-display": googleFontDisplay,
|
1359
1524
|
"google-font-preconnect": googleFontPreconnect,
|
@@ -1379,70 +1544,43 @@ var plugin = {
|
|
1379
1544
|
}
|
1380
1545
|
};
|
1381
1546
|
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"
|
1547
|
+
"nextjs/google-font-display": "warn",
|
1548
|
+
"nextjs/google-font-preconnect": "warn",
|
1549
|
+
"nextjs/inline-script-id": "warn",
|
1550
|
+
"nextjs/next-script-for-ga": "warn",
|
1551
|
+
"nextjs/no-assign-module-variable": "warn",
|
1552
|
+
"nextjs/no-async-client-component": "warn",
|
1553
|
+
"nextjs/no-before-interactive-script-outside-document": "warn",
|
1554
|
+
"nextjs/no-css-tags": "warn",
|
1555
|
+
"nextjs/no-document-import-in-page": "warn",
|
1556
|
+
"nextjs/no-duplicate-head": "warn",
|
1557
|
+
"nextjs/no-head-element": "warn",
|
1558
|
+
"nextjs/no-head-import-in-document": "warn",
|
1559
|
+
"nextjs/no-html-link-for-pages": "warn",
|
1560
|
+
"nextjs/no-img-element": "warn",
|
1561
|
+
"nextjs/no-page-custom-font": "warn",
|
1562
|
+
"nextjs/no-script-component-in-head": "warn",
|
1563
|
+
"nextjs/no-styled-jsx-in-document": "warn",
|
1564
|
+
"nextjs/no-sync-scripts": "warn",
|
1565
|
+
"nextjs/no-title-in-document-head": "warn",
|
1566
|
+
"nextjs/no-typos": "warn",
|
1567
|
+
"nextjs/no-unwanted-polyfillio": "warn"
|
1410
1568
|
};
|
1411
|
-
var
|
1412
|
-
|
1413
|
-
|
1414
|
-
|
1415
|
-
}
|
1569
|
+
var recommendedConfig = {
|
1570
|
+
files: ["**/*.{js,jsx,ts,tsx}"],
|
1571
|
+
plugins: {
|
1572
|
+
nextjs: plugin
|
1573
|
+
},
|
1574
|
+
rules: recommendedRules
|
1416
1575
|
};
|
1417
|
-
var
|
1418
|
-
var recommendedLegacyConfig = createRuleConfig(recommendedRules, false);
|
1419
|
-
var coreWebVitalsFlatConfig = createRuleConfig(coreWebVitalsRules, true);
|
1420
|
-
var coreWebVitalsLegacyConfig = createRuleConfig(coreWebVitalsRules, false);
|
1421
|
-
var index_default = {
|
1576
|
+
var nextjsPlugin = {
|
1422
1577
|
...plugin,
|
1423
1578
|
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"
|
1579
|
+
recommended: recommendedConfig
|
1580
|
+
}
|
1442
1581
|
};
|
1443
|
-
var
|
1582
|
+
var index_default = nextjsPlugin;
|
1444
1583
|
export {
|
1445
|
-
index_default as default
|
1446
|
-
rules
|
1584
|
+
index_default as default
|
1447
1585
|
};
|
1448
1586
|
//# sourceMappingURL=index.js.map
|