eslint-plugin-nextfriday 1.5.2 → 1.6.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/CHANGELOG.md +15 -0
- package/README.md +4 -0
- package/docs/rules/ENFORCE_SORTED_DESTRUCTURING.md +122 -0
- package/docs/rules/JSX_NO_NON_COMPONENT_FUNCTION.md +114 -0
- package/docs/rules/JSX_NO_VARIABLE_IN_CALLBACK.md +144 -0
- package/docs/rules/PREFER_JSX_TEMPLATE_LITERALS.md +78 -0
- package/lib/index.cjs +1686 -0
- package/lib/index.cjs.map +1 -0
- package/lib/index.d.cts +444 -0
- package/lib/index.d.ts +444 -0
- package/lib/index.js +1647 -0
- package/lib/index.js.map +1 -0
- package/package.json +2 -1
package/lib/index.cjs
ADDED
|
@@ -0,0 +1,1686 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
configs: () => configs,
|
|
34
|
+
default: () => index_default,
|
|
35
|
+
meta: () => meta,
|
|
36
|
+
rules: () => rules
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(index_exports);
|
|
39
|
+
|
|
40
|
+
// package.json
|
|
41
|
+
var package_default = {
|
|
42
|
+
name: "eslint-plugin-nextfriday",
|
|
43
|
+
version: "1.6.0",
|
|
44
|
+
description: "A comprehensive ESLint plugin providing custom rules and configurations for Next Friday development workflows.",
|
|
45
|
+
keywords: [
|
|
46
|
+
"eslint",
|
|
47
|
+
"eslintplugin",
|
|
48
|
+
"eslint-plugin",
|
|
49
|
+
"nextfriday",
|
|
50
|
+
"next-friday",
|
|
51
|
+
"linting",
|
|
52
|
+
"code-quality",
|
|
53
|
+
"javascript",
|
|
54
|
+
"typescript",
|
|
55
|
+
"development-tools"
|
|
56
|
+
],
|
|
57
|
+
homepage: "https://github.com/next-friday/eslint-plugin-nextfriday",
|
|
58
|
+
bugs: {
|
|
59
|
+
url: "https://github.com/next-friday/eslint-plugin-nextfriday/issues"
|
|
60
|
+
},
|
|
61
|
+
repository: {
|
|
62
|
+
type: "git",
|
|
63
|
+
url: "https://github.com/next-friday/eslint-plugin-nextfriday.git"
|
|
64
|
+
},
|
|
65
|
+
license: "MIT",
|
|
66
|
+
author: "Next Friday <nextfriday.developer@gmail.com>",
|
|
67
|
+
contributors: [
|
|
68
|
+
"@joetakara"
|
|
69
|
+
],
|
|
70
|
+
type: "module",
|
|
71
|
+
exports: {
|
|
72
|
+
".": {
|
|
73
|
+
types: "./lib/index.d.ts",
|
|
74
|
+
import: "./lib/index.js",
|
|
75
|
+
require: "./lib/index.cjs"
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
main: "lib/index.js",
|
|
79
|
+
types: "lib/index.d.ts",
|
|
80
|
+
files: [
|
|
81
|
+
"LICENSE",
|
|
82
|
+
"README.md",
|
|
83
|
+
"CHANGELOG.md",
|
|
84
|
+
"docs",
|
|
85
|
+
"lib"
|
|
86
|
+
],
|
|
87
|
+
scripts: {
|
|
88
|
+
build: "tsup",
|
|
89
|
+
changeset: "changeset",
|
|
90
|
+
"changeset:publish": "npm publish --provenance --access public",
|
|
91
|
+
"changeset:version": "changeset version",
|
|
92
|
+
clear: "rm -rf lib node_modules/.cache .eslintcache",
|
|
93
|
+
eslint: "eslint src --ext .js,.ts --fix",
|
|
94
|
+
"eslint:check": "eslint src --ext .js,.ts",
|
|
95
|
+
prepare: "husky",
|
|
96
|
+
prepublishOnly: "pnpm build",
|
|
97
|
+
prettier: "prettier --write .",
|
|
98
|
+
"prettier:check": "prettier --check .",
|
|
99
|
+
"sort-package-json": "pnpm exec sort-package-json",
|
|
100
|
+
"sort-package-json:check": "pnpm exec sort-package-json --check",
|
|
101
|
+
test: "jest",
|
|
102
|
+
"test:coverage": "jest --coverage",
|
|
103
|
+
"test:watch": "jest --watch",
|
|
104
|
+
typecheck: "tsc --noEmit"
|
|
105
|
+
},
|
|
106
|
+
dependencies: {
|
|
107
|
+
"@typescript-eslint/utils": "^8.42.0",
|
|
108
|
+
"emoji-regex": "^10.5.0",
|
|
109
|
+
tsup: "^8.5.0"
|
|
110
|
+
},
|
|
111
|
+
devDependencies: {
|
|
112
|
+
"@changesets/changelog-github": "^0.5.1",
|
|
113
|
+
"@changesets/cli": "^2.29.6",
|
|
114
|
+
"@commitlint/cli": "^19.8.1",
|
|
115
|
+
"@commitlint/config-conventional": "^19.8.1",
|
|
116
|
+
"@eslint/js": "^9.35.0",
|
|
117
|
+
"@jest/globals": "^30.1.2",
|
|
118
|
+
"@stylistic/eslint-plugin": "^3.1.0",
|
|
119
|
+
"@swc/core": "^1.13.5",
|
|
120
|
+
"@types/eslint": "^9.6.1",
|
|
121
|
+
"@types/jest": "^30.0.0",
|
|
122
|
+
"@types/node": "^22.5.4",
|
|
123
|
+
"@types/ramda": "^0.31.0",
|
|
124
|
+
"@typescript-eslint/parser": "^8.42.0",
|
|
125
|
+
"@typescript-eslint/rule-tester": "^8.42.0",
|
|
126
|
+
eslint: "^9.35.0",
|
|
127
|
+
"eslint-config-airbnb-extended": "^2.2.0",
|
|
128
|
+
"eslint-config-prettier": "^10.1.8",
|
|
129
|
+
"eslint-import-resolver-typescript": "^4.4.4",
|
|
130
|
+
"eslint-plugin-import-x": "^4.16.1",
|
|
131
|
+
"eslint-plugin-jest": "^29.0.1",
|
|
132
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
133
|
+
"eslint-plugin-sonarjs": "^3.0.5",
|
|
134
|
+
husky: "^9.1.7",
|
|
135
|
+
jest: "^29.7.0",
|
|
136
|
+
"lint-staged": "^16.1.6",
|
|
137
|
+
prettier: "^3.6.2",
|
|
138
|
+
"sort-package-json": "^3.4.0",
|
|
139
|
+
"ts-jest": "^29.4.1",
|
|
140
|
+
"ts-node": "^10.9.2",
|
|
141
|
+
typescript: "^5.6.2",
|
|
142
|
+
"typescript-eslint": "^8.42.0"
|
|
143
|
+
},
|
|
144
|
+
peerDependencies: {
|
|
145
|
+
eslint: "^9.0.0"
|
|
146
|
+
},
|
|
147
|
+
packageManager: "pnpm@9.12.0",
|
|
148
|
+
engines: {
|
|
149
|
+
node: ">=22.0.0",
|
|
150
|
+
pnpm: ">=9.0.0"
|
|
151
|
+
},
|
|
152
|
+
publishConfig: {
|
|
153
|
+
access: "public"
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// src/rules/enforce-readonly-component-props.ts
|
|
158
|
+
var import_utils = require("@typescript-eslint/utils");
|
|
159
|
+
var createRule = import_utils.ESLintUtils.RuleCreator(
|
|
160
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
161
|
+
);
|
|
162
|
+
var enforceReadonlyComponentProps = createRule({
|
|
163
|
+
name: "enforce-readonly-component-props",
|
|
164
|
+
meta: {
|
|
165
|
+
type: "suggestion",
|
|
166
|
+
docs: {
|
|
167
|
+
description: "Enforce Readonly wrapper for React component props when using named types or interfaces"
|
|
168
|
+
},
|
|
169
|
+
fixable: "code",
|
|
170
|
+
schema: [],
|
|
171
|
+
messages: {
|
|
172
|
+
useReadonly: "Component props should be wrapped with Readonly<> for immutability"
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
defaultOptions: [],
|
|
176
|
+
create(context) {
|
|
177
|
+
function hasJSXInConditional(node) {
|
|
178
|
+
return node.consequent.type === import_utils.AST_NODE_TYPES.JSXElement || node.consequent.type === import_utils.AST_NODE_TYPES.JSXFragment || node.alternate.type === import_utils.AST_NODE_TYPES.JSXElement || node.alternate.type === import_utils.AST_NODE_TYPES.JSXFragment;
|
|
179
|
+
}
|
|
180
|
+
function hasJSXInLogical(node) {
|
|
181
|
+
return node.right.type === import_utils.AST_NODE_TYPES.JSXElement || node.right.type === import_utils.AST_NODE_TYPES.JSXFragment;
|
|
182
|
+
}
|
|
183
|
+
function hasJSXReturn(block) {
|
|
184
|
+
return block.body.some((stmt) => {
|
|
185
|
+
if (stmt.type === import_utils.AST_NODE_TYPES.ReturnStatement && stmt.argument) {
|
|
186
|
+
return stmt.argument.type === import_utils.AST_NODE_TYPES.JSXElement || stmt.argument.type === import_utils.AST_NODE_TYPES.JSXFragment || stmt.argument.type === import_utils.AST_NODE_TYPES.ConditionalExpression && hasJSXInConditional(stmt.argument) || stmt.argument.type === import_utils.AST_NODE_TYPES.LogicalExpression && hasJSXInLogical(stmt.argument);
|
|
187
|
+
}
|
|
188
|
+
return false;
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
function isReactComponent(node) {
|
|
192
|
+
if (node.type === import_utils.AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
193
|
+
if (node.body.type === import_utils.AST_NODE_TYPES.JSXElement || node.body.type === import_utils.AST_NODE_TYPES.JSXFragment) {
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
if (node.body.type === import_utils.AST_NODE_TYPES.BlockStatement) {
|
|
197
|
+
return hasJSXReturn(node.body);
|
|
198
|
+
}
|
|
199
|
+
} else if (node.type === import_utils.AST_NODE_TYPES.FunctionExpression || node.type === import_utils.AST_NODE_TYPES.FunctionDeclaration) {
|
|
200
|
+
if (node.body && node.body.type === import_utils.AST_NODE_TYPES.BlockStatement) {
|
|
201
|
+
return hasJSXReturn(node.body);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
function isNamedType(node) {
|
|
207
|
+
return node.type === import_utils.AST_NODE_TYPES.TSTypeReference;
|
|
208
|
+
}
|
|
209
|
+
function isAlreadyReadonly(node) {
|
|
210
|
+
if (node.type === import_utils.AST_NODE_TYPES.TSTypeReference && node.typeName) {
|
|
211
|
+
if (node.typeName.type === import_utils.AST_NODE_TYPES.Identifier && node.typeName.name === "Readonly") {
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
function checkFunction(node) {
|
|
218
|
+
if (!isReactComponent(node)) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
if (node.params.length !== 1) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const param = node.params[0];
|
|
225
|
+
if (param.type === import_utils.AST_NODE_TYPES.Identifier && param.typeAnnotation) {
|
|
226
|
+
const { typeAnnotation } = param.typeAnnotation;
|
|
227
|
+
if (isNamedType(typeAnnotation) && !isAlreadyReadonly(typeAnnotation)) {
|
|
228
|
+
const { sourceCode } = context;
|
|
229
|
+
const typeText = sourceCode.getText(typeAnnotation);
|
|
230
|
+
context.report({
|
|
231
|
+
node: param.typeAnnotation,
|
|
232
|
+
messageId: "useReadonly",
|
|
233
|
+
fix(fixer) {
|
|
234
|
+
return fixer.replaceText(typeAnnotation, `Readonly<${typeText}>`);
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return {
|
|
241
|
+
ArrowFunctionExpression: checkFunction,
|
|
242
|
+
FunctionExpression: checkFunction,
|
|
243
|
+
FunctionDeclaration: checkFunction
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
var enforce_readonly_component_props_default = enforceReadonlyComponentProps;
|
|
248
|
+
|
|
249
|
+
// src/rules/enforce-sorted-destructuring.ts
|
|
250
|
+
var import_utils2 = require("@typescript-eslint/utils");
|
|
251
|
+
var createRule2 = import_utils2.ESLintUtils.RuleCreator(
|
|
252
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
253
|
+
);
|
|
254
|
+
var enforceSortedDestructuring = createRule2({
|
|
255
|
+
name: "enforce-sorted-destructuring",
|
|
256
|
+
meta: {
|
|
257
|
+
type: "suggestion",
|
|
258
|
+
docs: {
|
|
259
|
+
description: "Enforce alphabetical sorting of destructured properties with defaults first"
|
|
260
|
+
},
|
|
261
|
+
schema: [],
|
|
262
|
+
messages: {
|
|
263
|
+
unsortedDestructuring: "Destructured properties should be sorted alphabetically. Properties with defaults should come first, sorted by type (string, number, boolean, object) then alphabetically."
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
defaultOptions: [],
|
|
267
|
+
create(context) {
|
|
268
|
+
function getPropertyName(property) {
|
|
269
|
+
if (property.type === import_utils2.AST_NODE_TYPES.RestElement) {
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
if (property.key.type === import_utils2.AST_NODE_TYPES.Identifier) {
|
|
273
|
+
return property.key.name;
|
|
274
|
+
}
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
function hasDefaultValue(property) {
|
|
278
|
+
return property.value.type === import_utils2.AST_NODE_TYPES.AssignmentPattern && Boolean(property.value.right);
|
|
279
|
+
}
|
|
280
|
+
function getDefaultValueType(property) {
|
|
281
|
+
if (!hasDefaultValue(property)) {
|
|
282
|
+
return "none";
|
|
283
|
+
}
|
|
284
|
+
const assignmentPattern = property.value;
|
|
285
|
+
const { right } = assignmentPattern;
|
|
286
|
+
if (!right) {
|
|
287
|
+
return "none";
|
|
288
|
+
}
|
|
289
|
+
switch (right.type) {
|
|
290
|
+
case import_utils2.AST_NODE_TYPES.Literal:
|
|
291
|
+
if (typeof right.value === "string") {
|
|
292
|
+
return "string";
|
|
293
|
+
}
|
|
294
|
+
if (typeof right.value === "number") {
|
|
295
|
+
return "number";
|
|
296
|
+
}
|
|
297
|
+
if (typeof right.value === "boolean") {
|
|
298
|
+
return "boolean";
|
|
299
|
+
}
|
|
300
|
+
return "other";
|
|
301
|
+
case import_utils2.AST_NODE_TYPES.TemplateLiteral:
|
|
302
|
+
return "string";
|
|
303
|
+
case import_utils2.AST_NODE_TYPES.ObjectExpression:
|
|
304
|
+
case import_utils2.AST_NODE_TYPES.ArrayExpression:
|
|
305
|
+
return "object";
|
|
306
|
+
default:
|
|
307
|
+
return "other";
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
function getTypeSortOrder(type) {
|
|
311
|
+
const order = {
|
|
312
|
+
string: 0,
|
|
313
|
+
number: 1,
|
|
314
|
+
boolean: 2,
|
|
315
|
+
object: 3,
|
|
316
|
+
other: 4,
|
|
317
|
+
none: 5
|
|
318
|
+
};
|
|
319
|
+
return order[type] ?? 5;
|
|
320
|
+
}
|
|
321
|
+
function checkVariableDeclarator(node) {
|
|
322
|
+
if (node.id.type !== import_utils2.AST_NODE_TYPES.ObjectPattern) {
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
const { properties } = node.id;
|
|
326
|
+
if (properties.length < 2) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
const propertyInfo = properties.map((prop) => {
|
|
330
|
+
if (prop.type === import_utils2.AST_NODE_TYPES.RestElement) {
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
return {
|
|
334
|
+
property: prop,
|
|
335
|
+
name: getPropertyName(prop),
|
|
336
|
+
hasDefault: hasDefaultValue(prop),
|
|
337
|
+
defaultType: getDefaultValueType(prop)
|
|
338
|
+
};
|
|
339
|
+
}).filter((info) => info !== null && info.name !== null);
|
|
340
|
+
const sorted = [...propertyInfo].sort((a, b) => {
|
|
341
|
+
if (a.hasDefault && !b.hasDefault) {
|
|
342
|
+
return -1;
|
|
343
|
+
}
|
|
344
|
+
if (!a.hasDefault && b.hasDefault) {
|
|
345
|
+
return 1;
|
|
346
|
+
}
|
|
347
|
+
if (a.hasDefault && b.hasDefault) {
|
|
348
|
+
const typeComparison = getTypeSortOrder(a.defaultType) - getTypeSortOrder(b.defaultType);
|
|
349
|
+
if (typeComparison !== 0) {
|
|
350
|
+
return typeComparison;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return a.name.localeCompare(b.name);
|
|
354
|
+
});
|
|
355
|
+
const isSorted = propertyInfo.every((info, index) => info.name === sorted[index].name);
|
|
356
|
+
if (!isSorted) {
|
|
357
|
+
context.report({
|
|
358
|
+
node: node.id,
|
|
359
|
+
messageId: "unsortedDestructuring"
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
return {
|
|
364
|
+
VariableDeclarator: checkVariableDeclarator
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
var enforce_sorted_destructuring_default = enforceSortedDestructuring;
|
|
369
|
+
|
|
370
|
+
// src/rules/file-kebab-case.ts
|
|
371
|
+
var import_path = __toESM(require("path"), 1);
|
|
372
|
+
var import_utils3 = require("@typescript-eslint/utils");
|
|
373
|
+
var createRule3 = import_utils3.ESLintUtils.RuleCreator(
|
|
374
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
375
|
+
);
|
|
376
|
+
var isKebabCase = (str) => {
|
|
377
|
+
if (/\.(config|rc|setup|spec|test)$/.test(str) || /^[a-z0-9]+(?:-[a-z0-9]+)*\.[a-z0-9]+(?:-[a-z0-9]+)*$/.test(str)) {
|
|
378
|
+
return /^[a-z0-9]+(?:-[a-z0-9]+)*(?:\.[a-z0-9]+(?:-[a-z0-9]+)*)*$/.test(str);
|
|
379
|
+
}
|
|
380
|
+
return /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(str);
|
|
381
|
+
};
|
|
382
|
+
var fileKebabCase = createRule3({
|
|
383
|
+
name: "file-kebab-case",
|
|
384
|
+
meta: {
|
|
385
|
+
type: "problem",
|
|
386
|
+
docs: {
|
|
387
|
+
description: "Enforce kebab-case filenames for .ts and .js files"
|
|
388
|
+
},
|
|
389
|
+
messages: {
|
|
390
|
+
fileKebabCase: "File names must be kebab-case"
|
|
391
|
+
},
|
|
392
|
+
schema: []
|
|
393
|
+
},
|
|
394
|
+
defaultOptions: [],
|
|
395
|
+
create(context) {
|
|
396
|
+
return {
|
|
397
|
+
Program() {
|
|
398
|
+
const { filename } = context;
|
|
399
|
+
const ext = import_path.default.extname(filename);
|
|
400
|
+
if (ext !== ".ts" && ext !== ".js") {
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
const basename2 = import_path.default.basename(filename, ext);
|
|
404
|
+
if (!isKebabCase(basename2)) {
|
|
405
|
+
context.report({
|
|
406
|
+
loc: { line: 1, column: 0 },
|
|
407
|
+
messageId: "fileKebabCase"
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
var file_kebab_case_default = fileKebabCase;
|
|
415
|
+
|
|
416
|
+
// src/rules/jsx-pascal-case.ts
|
|
417
|
+
var import_path2 = __toESM(require("path"), 1);
|
|
418
|
+
var import_utils4 = require("@typescript-eslint/utils");
|
|
419
|
+
var createRule4 = import_utils4.ESLintUtils.RuleCreator(
|
|
420
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
421
|
+
);
|
|
422
|
+
var isPascalCase = (str) => /^[A-Z][a-zA-Z0-9]*$/.test(str) && !/^[A-Z]+$/.test(str);
|
|
423
|
+
var jsxPascalCase = createRule4({
|
|
424
|
+
name: "jsx-pascal-case",
|
|
425
|
+
meta: {
|
|
426
|
+
type: "problem",
|
|
427
|
+
docs: {
|
|
428
|
+
description: "Enforce PascalCase filenames for .jsx and .tsx files"
|
|
429
|
+
},
|
|
430
|
+
messages: {
|
|
431
|
+
jsxPascalCase: "JSX/TSX file names must be PascalCase"
|
|
432
|
+
},
|
|
433
|
+
schema: []
|
|
434
|
+
},
|
|
435
|
+
defaultOptions: [],
|
|
436
|
+
create(context) {
|
|
437
|
+
return {
|
|
438
|
+
Program() {
|
|
439
|
+
const { filename } = context;
|
|
440
|
+
const ext = import_path2.default.extname(filename);
|
|
441
|
+
if (ext !== ".jsx" && ext !== ".tsx") {
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
const basename2 = import_path2.default.basename(filename, ext);
|
|
445
|
+
if (!isPascalCase(basename2)) {
|
|
446
|
+
context.report({
|
|
447
|
+
loc: { line: 1, column: 0 },
|
|
448
|
+
messageId: "jsxPascalCase"
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
var jsx_pascal_case_default = jsxPascalCase;
|
|
456
|
+
|
|
457
|
+
// src/rules/jsx-no-variable-in-callback.ts
|
|
458
|
+
var import_utils5 = require("@typescript-eslint/utils");
|
|
459
|
+
var createRule5 = import_utils5.ESLintUtils.RuleCreator(
|
|
460
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
461
|
+
);
|
|
462
|
+
var jsxNoVariableInCallback = createRule5({
|
|
463
|
+
name: "jsx-no-variable-in-callback",
|
|
464
|
+
meta: {
|
|
465
|
+
type: "suggestion",
|
|
466
|
+
docs: {
|
|
467
|
+
description: "Disallow variable declarations inside callback functions within JSX"
|
|
468
|
+
},
|
|
469
|
+
schema: [],
|
|
470
|
+
messages: {
|
|
471
|
+
noVariableInCallback: "Variable declarations should not be inside callback functions within JSX. Extract the logic to a separate function outside the JSX."
|
|
472
|
+
}
|
|
473
|
+
},
|
|
474
|
+
defaultOptions: [],
|
|
475
|
+
create(context) {
|
|
476
|
+
function isInsideJSX(node) {
|
|
477
|
+
let current = node.parent;
|
|
478
|
+
while (current) {
|
|
479
|
+
if (current.type === import_utils5.AST_NODE_TYPES.JSXElement || current.type === import_utils5.AST_NODE_TYPES.JSXFragment) {
|
|
480
|
+
return true;
|
|
481
|
+
}
|
|
482
|
+
current = current.parent;
|
|
483
|
+
}
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
function isCallbackInJSX(node) {
|
|
487
|
+
if (!node.parent) {
|
|
488
|
+
return false;
|
|
489
|
+
}
|
|
490
|
+
if (!isInsideJSX(node)) {
|
|
491
|
+
return false;
|
|
492
|
+
}
|
|
493
|
+
if (node.parent.type === import_utils5.AST_NODE_TYPES.CallExpression || node.parent.type === import_utils5.AST_NODE_TYPES.JSXExpressionContainer) {
|
|
494
|
+
return true;
|
|
495
|
+
}
|
|
496
|
+
if (node.parent.type === import_utils5.AST_NODE_TYPES.ArrayExpression && node.parent.parent) {
|
|
497
|
+
if (node.parent.parent.type === import_utils5.AST_NODE_TYPES.CallExpression || node.parent.parent.type === import_utils5.AST_NODE_TYPES.JSXExpressionContainer) {
|
|
498
|
+
return true;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return false;
|
|
502
|
+
}
|
|
503
|
+
function checkFunctionBody(node) {
|
|
504
|
+
if (!isCallbackInJSX(node)) {
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
const { body } = node;
|
|
508
|
+
if (body.type !== import_utils5.AST_NODE_TYPES.BlockStatement) {
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
body.body.forEach((statement) => {
|
|
512
|
+
if (statement.type === import_utils5.AST_NODE_TYPES.VariableDeclaration) {
|
|
513
|
+
context.report({
|
|
514
|
+
node: statement,
|
|
515
|
+
messageId: "noVariableInCallback"
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
return {
|
|
521
|
+
ArrowFunctionExpression: checkFunctionBody,
|
|
522
|
+
FunctionExpression: checkFunctionBody
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
var jsx_no_variable_in_callback_default = jsxNoVariableInCallback;
|
|
527
|
+
|
|
528
|
+
// src/rules/md-filename-case-restriction.ts
|
|
529
|
+
var import_path3 = __toESM(require("path"), 1);
|
|
530
|
+
var import_utils6 = require("@typescript-eslint/utils");
|
|
531
|
+
var createRule6 = import_utils6.ESLintUtils.RuleCreator(
|
|
532
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
533
|
+
);
|
|
534
|
+
var mdFilenameCaseRestriction = createRule6({
|
|
535
|
+
name: "md-filename-case-restriction",
|
|
536
|
+
meta: {
|
|
537
|
+
type: "problem",
|
|
538
|
+
docs: {
|
|
539
|
+
description: "Enforce .md filenames to be SNAKE_CASE only"
|
|
540
|
+
},
|
|
541
|
+
messages: {
|
|
542
|
+
invalidFilenameCase: "Markdown filename must be SNAKE_CASE (UPPERCASE with underscores). Found: '{{ filename }}'"
|
|
543
|
+
},
|
|
544
|
+
schema: []
|
|
545
|
+
},
|
|
546
|
+
defaultOptions: [],
|
|
547
|
+
create(context) {
|
|
548
|
+
return {
|
|
549
|
+
Program() {
|
|
550
|
+
const { filename } = context;
|
|
551
|
+
if (!filename.endsWith(".md")) {
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
const basename2 = import_path3.default.basename(filename, ".md");
|
|
555
|
+
function isSnakeCase(text) {
|
|
556
|
+
return /^[A-Z][A-Z0-9_]*$/.test(text);
|
|
557
|
+
}
|
|
558
|
+
function isValidCase(text) {
|
|
559
|
+
return isSnakeCase(text);
|
|
560
|
+
}
|
|
561
|
+
if (!isValidCase(basename2)) {
|
|
562
|
+
context.report({
|
|
563
|
+
node: context.sourceCode.ast,
|
|
564
|
+
messageId: "invalidFilenameCase",
|
|
565
|
+
data: { filename: basename2 }
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
var md_filename_case_restriction_default = mdFilenameCaseRestriction;
|
|
573
|
+
|
|
574
|
+
// src/rules/no-complex-inline-return.ts
|
|
575
|
+
var import_utils7 = require("@typescript-eslint/utils");
|
|
576
|
+
var createRule7 = import_utils7.ESLintUtils.RuleCreator(
|
|
577
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
578
|
+
);
|
|
579
|
+
var noComplexInlineReturn = createRule7({
|
|
580
|
+
name: "no-complex-inline-return",
|
|
581
|
+
meta: {
|
|
582
|
+
type: "suggestion",
|
|
583
|
+
docs: {
|
|
584
|
+
description: "Disallow complex inline expressions in return statements - prefer extracting to a const first"
|
|
585
|
+
},
|
|
586
|
+
messages: {
|
|
587
|
+
noComplexInlineReturn: "Avoid returning complex expressions directly. Extract to a const variable first for better readability."
|
|
588
|
+
},
|
|
589
|
+
schema: []
|
|
590
|
+
},
|
|
591
|
+
defaultOptions: [],
|
|
592
|
+
create(context) {
|
|
593
|
+
const isComplexExpression = (node) => {
|
|
594
|
+
if (!node) return false;
|
|
595
|
+
if (node.type === import_utils7.AST_NODE_TYPES.ConditionalExpression) {
|
|
596
|
+
return true;
|
|
597
|
+
}
|
|
598
|
+
if (node.type === import_utils7.AST_NODE_TYPES.LogicalExpression) {
|
|
599
|
+
return true;
|
|
600
|
+
}
|
|
601
|
+
if (node.type === import_utils7.AST_NODE_TYPES.NewExpression) {
|
|
602
|
+
return true;
|
|
603
|
+
}
|
|
604
|
+
return false;
|
|
605
|
+
};
|
|
606
|
+
return {
|
|
607
|
+
ReturnStatement(node) {
|
|
608
|
+
if (node.argument && isComplexExpression(node.argument)) {
|
|
609
|
+
context.report({
|
|
610
|
+
node: node.argument,
|
|
611
|
+
messageId: "noComplexInlineReturn"
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
});
|
|
618
|
+
var no_complex_inline_return_default = noComplexInlineReturn;
|
|
619
|
+
|
|
620
|
+
// src/rules/no-emoji.ts
|
|
621
|
+
var import_emoji_regex = __toESM(require("emoji-regex"), 1);
|
|
622
|
+
var import_utils8 = require("@typescript-eslint/utils");
|
|
623
|
+
var createRule8 = import_utils8.ESLintUtils.RuleCreator(
|
|
624
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
625
|
+
);
|
|
626
|
+
var noEmoji = createRule8({
|
|
627
|
+
name: "no-emoji",
|
|
628
|
+
meta: {
|
|
629
|
+
type: "problem",
|
|
630
|
+
docs: {
|
|
631
|
+
description: "Disallow emoji characters in source code"
|
|
632
|
+
},
|
|
633
|
+
messages: {
|
|
634
|
+
noEmoji: "Emoji are not allowed in source code"
|
|
635
|
+
},
|
|
636
|
+
schema: []
|
|
637
|
+
},
|
|
638
|
+
defaultOptions: [],
|
|
639
|
+
create(context) {
|
|
640
|
+
const { sourceCode } = context;
|
|
641
|
+
return {
|
|
642
|
+
Program() {
|
|
643
|
+
const text = sourceCode.getText();
|
|
644
|
+
const regex = (0, import_emoji_regex.default)();
|
|
645
|
+
const matches = Array.from(text.matchAll(regex));
|
|
646
|
+
matches.forEach((match) => {
|
|
647
|
+
const loc = sourceCode.getLocFromIndex(match.index);
|
|
648
|
+
context.report({
|
|
649
|
+
loc,
|
|
650
|
+
messageId: "noEmoji"
|
|
651
|
+
});
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
});
|
|
657
|
+
var no_emoji_default = noEmoji;
|
|
658
|
+
|
|
659
|
+
// src/rules/no-env-fallback.ts
|
|
660
|
+
var import_utils9 = require("@typescript-eslint/utils");
|
|
661
|
+
var createRule9 = import_utils9.ESLintUtils.RuleCreator(
|
|
662
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
663
|
+
);
|
|
664
|
+
var noEnvFallback = createRule9({
|
|
665
|
+
name: "no-env-fallback",
|
|
666
|
+
meta: {
|
|
667
|
+
type: "problem",
|
|
668
|
+
docs: {
|
|
669
|
+
description: "Disallow fallback values for environment variables as they can be dangerous in production"
|
|
670
|
+
},
|
|
671
|
+
messages: {
|
|
672
|
+
noEnvFallback: "Avoid using fallback values with process.env. Environment variables should fail explicitly when missing rather than silently using a default value."
|
|
673
|
+
},
|
|
674
|
+
schema: []
|
|
675
|
+
},
|
|
676
|
+
defaultOptions: [],
|
|
677
|
+
create(context) {
|
|
678
|
+
const isProcessEnvAccess = (node) => {
|
|
679
|
+
if (node.type !== import_utils9.AST_NODE_TYPES.MemberExpression) {
|
|
680
|
+
return false;
|
|
681
|
+
}
|
|
682
|
+
const { object } = node;
|
|
683
|
+
if (object.type !== import_utils9.AST_NODE_TYPES.MemberExpression) {
|
|
684
|
+
return false;
|
|
685
|
+
}
|
|
686
|
+
const processNode = object.object;
|
|
687
|
+
const envNode = object.property;
|
|
688
|
+
return processNode.type === import_utils9.AST_NODE_TYPES.Identifier && processNode.name === "process" && envNode.type === import_utils9.AST_NODE_TYPES.Identifier && envNode.name === "env";
|
|
689
|
+
};
|
|
690
|
+
return {
|
|
691
|
+
LogicalExpression(node) {
|
|
692
|
+
if ((node.operator === "||" || node.operator === "??") && isProcessEnvAccess(node.left)) {
|
|
693
|
+
context.report({
|
|
694
|
+
node,
|
|
695
|
+
messageId: "noEnvFallback"
|
|
696
|
+
});
|
|
697
|
+
}
|
|
698
|
+
},
|
|
699
|
+
ConditionalExpression(node) {
|
|
700
|
+
if (isProcessEnvAccess(node.test)) {
|
|
701
|
+
context.report({
|
|
702
|
+
node,
|
|
703
|
+
messageId: "noEnvFallback"
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
var no_env_fallback_default = noEnvFallback;
|
|
711
|
+
|
|
712
|
+
// src/rules/no-explicit-return-type.ts
|
|
713
|
+
var import_utils10 = require("@typescript-eslint/utils");
|
|
714
|
+
var createRule10 = import_utils10.ESLintUtils.RuleCreator(
|
|
715
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
716
|
+
);
|
|
717
|
+
var noExplicitReturnType = createRule10({
|
|
718
|
+
name: "no-explicit-return-type",
|
|
719
|
+
meta: {
|
|
720
|
+
type: "suggestion",
|
|
721
|
+
docs: {
|
|
722
|
+
description: "Disallow explicit return types on functions"
|
|
723
|
+
},
|
|
724
|
+
fixable: "code",
|
|
725
|
+
schema: [],
|
|
726
|
+
messages: {
|
|
727
|
+
noExplicitReturnType: "Remove explicit return type '{{returnType}}' - TypeScript can infer it automatically"
|
|
728
|
+
}
|
|
729
|
+
},
|
|
730
|
+
defaultOptions: [],
|
|
731
|
+
create(context) {
|
|
732
|
+
const checkFunction = (node) => {
|
|
733
|
+
if (node.returnType) {
|
|
734
|
+
const returnTypeText = context.sourceCode.getText(node.returnType);
|
|
735
|
+
context.report({
|
|
736
|
+
node: node.returnType,
|
|
737
|
+
messageId: "noExplicitReturnType",
|
|
738
|
+
data: {
|
|
739
|
+
returnType: returnTypeText
|
|
740
|
+
},
|
|
741
|
+
fix(fixer) {
|
|
742
|
+
return fixer.remove(node.returnType);
|
|
743
|
+
}
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
};
|
|
747
|
+
return {
|
|
748
|
+
FunctionDeclaration: checkFunction,
|
|
749
|
+
FunctionExpression: checkFunction,
|
|
750
|
+
ArrowFunctionExpression: checkFunction
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
});
|
|
754
|
+
var no_explicit_return_type_default = noExplicitReturnType;
|
|
755
|
+
|
|
756
|
+
// src/rules/jsx-no-non-component-function.ts
|
|
757
|
+
var import_utils12 = require("@typescript-eslint/utils");
|
|
758
|
+
|
|
759
|
+
// src/utils.ts
|
|
760
|
+
var import_node_path = require("path");
|
|
761
|
+
var import_utils11 = require("@typescript-eslint/utils");
|
|
762
|
+
var getFileExtension = (filename) => (0, import_node_path.extname)(filename).slice(1);
|
|
763
|
+
|
|
764
|
+
// src/rules/jsx-no-non-component-function.ts
|
|
765
|
+
var createRule11 = import_utils12.ESLintUtils.RuleCreator(
|
|
766
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
767
|
+
);
|
|
768
|
+
var jsxNoNonComponentFunction = createRule11({
|
|
769
|
+
name: "jsx-no-non-component-function",
|
|
770
|
+
meta: {
|
|
771
|
+
type: "problem",
|
|
772
|
+
docs: {
|
|
773
|
+
description: "Disallow non-component functions defined at top level in .tsx and .jsx files"
|
|
774
|
+
},
|
|
775
|
+
schema: [],
|
|
776
|
+
messages: {
|
|
777
|
+
noTopLevelFunction: "Non-component functions should not be defined at top level in .tsx/.jsx files. Either move it inside the component or extract it to a separate file."
|
|
778
|
+
}
|
|
779
|
+
},
|
|
780
|
+
defaultOptions: [],
|
|
781
|
+
create(context) {
|
|
782
|
+
const { filename } = context;
|
|
783
|
+
const extension = getFileExtension(filename);
|
|
784
|
+
if (extension !== "tsx" && extension !== "jsx") {
|
|
785
|
+
return {};
|
|
786
|
+
}
|
|
787
|
+
function isReactComponent(node) {
|
|
788
|
+
const functionName = node.type === import_utils12.AST_NODE_TYPES.FunctionDeclaration && node.id ? node.id.name : null;
|
|
789
|
+
if (functionName && /^[A-Z]/.test(functionName)) {
|
|
790
|
+
return true;
|
|
791
|
+
}
|
|
792
|
+
if (node.returnType?.typeAnnotation) {
|
|
793
|
+
const returnTypeNode = node.returnType.typeAnnotation;
|
|
794
|
+
if (returnTypeNode.type === import_utils12.AST_NODE_TYPES.TSTypeReference && returnTypeNode.typeName.type === import_utils12.AST_NODE_TYPES.Identifier) {
|
|
795
|
+
const typeName = returnTypeNode.typeName.name;
|
|
796
|
+
if (typeName === "JSX" || typeName === "ReactElement" || typeName === "ReactNode") {
|
|
797
|
+
return true;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
return false;
|
|
802
|
+
}
|
|
803
|
+
function checkTopLevelFunction(node, declaratorNode) {
|
|
804
|
+
if (isReactComponent(node)) {
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
const { parent } = node;
|
|
808
|
+
if (!parent) {
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
if (parent.type === import_utils12.AST_NODE_TYPES.ExportDefaultDeclaration || parent.type === import_utils12.AST_NODE_TYPES.ExportNamedDeclaration) {
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
814
|
+
if (declaratorNode?.parent?.parent?.type === import_utils12.AST_NODE_TYPES.ExportNamedDeclaration) {
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
if (declaratorNode?.id.type === import_utils12.AST_NODE_TYPES.Identifier) {
|
|
818
|
+
const varName = declaratorNode.id.name;
|
|
819
|
+
if (/^[A-Z]/.test(varName)) {
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
context.report({
|
|
824
|
+
node: declaratorNode || node,
|
|
825
|
+
messageId: "noTopLevelFunction"
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
return {
|
|
829
|
+
"Program > VariableDeclaration > VariableDeclarator > ArrowFunctionExpression": function checkArrowFunction(node) {
|
|
830
|
+
const declarator = node.parent;
|
|
831
|
+
checkTopLevelFunction(node, declarator);
|
|
832
|
+
},
|
|
833
|
+
"Program > FunctionDeclaration": function checkFunctionDeclaration(node) {
|
|
834
|
+
checkTopLevelFunction(node);
|
|
835
|
+
}
|
|
836
|
+
};
|
|
837
|
+
}
|
|
838
|
+
});
|
|
839
|
+
var jsx_no_non_component_function_default = jsxNoNonComponentFunction;
|
|
840
|
+
|
|
841
|
+
// src/rules/no-logic-in-params.ts
|
|
842
|
+
var import_utils14 = require("@typescript-eslint/utils");
|
|
843
|
+
var createRule12 = import_utils14.ESLintUtils.RuleCreator(
|
|
844
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
845
|
+
);
|
|
846
|
+
var noLogicInParams = createRule12({
|
|
847
|
+
name: "no-logic-in-params",
|
|
848
|
+
meta: {
|
|
849
|
+
type: "suggestion",
|
|
850
|
+
docs: {
|
|
851
|
+
description: "Disallow logic or conditions in function parameters - extract to a const variable first"
|
|
852
|
+
},
|
|
853
|
+
messages: {
|
|
854
|
+
noLogicInParams: "Avoid logic or conditions in function parameters. Extract to a const variable first for better readability."
|
|
855
|
+
},
|
|
856
|
+
schema: []
|
|
857
|
+
},
|
|
858
|
+
defaultOptions: [],
|
|
859
|
+
create(context) {
|
|
860
|
+
const isComplexExpression = (node) => {
|
|
861
|
+
if (node.type === import_utils14.AST_NODE_TYPES.SpreadElement) {
|
|
862
|
+
return false;
|
|
863
|
+
}
|
|
864
|
+
if (node.type === import_utils14.AST_NODE_TYPES.ConditionalExpression) {
|
|
865
|
+
return true;
|
|
866
|
+
}
|
|
867
|
+
if (node.type === import_utils14.AST_NODE_TYPES.LogicalExpression) {
|
|
868
|
+
return true;
|
|
869
|
+
}
|
|
870
|
+
if (node.type === import_utils14.AST_NODE_TYPES.BinaryExpression) {
|
|
871
|
+
const logicalOperators = ["==", "===", "!=", "!==", "<", ">", "<=", ">=", "in", "instanceof"];
|
|
872
|
+
return logicalOperators.includes(node.operator);
|
|
873
|
+
}
|
|
874
|
+
if (node.type === import_utils14.AST_NODE_TYPES.UnaryExpression) {
|
|
875
|
+
return node.operator === "!";
|
|
876
|
+
}
|
|
877
|
+
return false;
|
|
878
|
+
};
|
|
879
|
+
return {
|
|
880
|
+
CallExpression(node) {
|
|
881
|
+
node.arguments.forEach((arg) => {
|
|
882
|
+
if (isComplexExpression(arg)) {
|
|
883
|
+
context.report({
|
|
884
|
+
node: arg,
|
|
885
|
+
messageId: "noLogicInParams"
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
});
|
|
889
|
+
},
|
|
890
|
+
NewExpression(node) {
|
|
891
|
+
node.arguments.forEach((arg) => {
|
|
892
|
+
if (isComplexExpression(arg)) {
|
|
893
|
+
context.report({
|
|
894
|
+
node: arg,
|
|
895
|
+
messageId: "noLogicInParams"
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
};
|
|
901
|
+
}
|
|
902
|
+
});
|
|
903
|
+
var no_logic_in_params_default = noLogicInParams;
|
|
904
|
+
|
|
905
|
+
// src/rules/prefer-destructuring-params.ts
|
|
906
|
+
var import_utils15 = require("@typescript-eslint/utils");
|
|
907
|
+
var createRule13 = import_utils15.ESLintUtils.RuleCreator(
|
|
908
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
909
|
+
);
|
|
910
|
+
var preferDestructuringParams = createRule13({
|
|
911
|
+
name: "prefer-destructuring-params",
|
|
912
|
+
meta: {
|
|
913
|
+
type: "suggestion",
|
|
914
|
+
docs: {
|
|
915
|
+
description: "Enforce destructuring for functions with multiple parameters"
|
|
916
|
+
},
|
|
917
|
+
messages: {
|
|
918
|
+
preferDestructuring: "Functions with multiple parameters should use destructuring"
|
|
919
|
+
},
|
|
920
|
+
schema: []
|
|
921
|
+
},
|
|
922
|
+
defaultOptions: [],
|
|
923
|
+
create(context) {
|
|
924
|
+
const isCallbackFunction = (node) => {
|
|
925
|
+
const { parent } = node;
|
|
926
|
+
return parent?.type === import_utils15.AST_NODE_TYPES.CallExpression;
|
|
927
|
+
};
|
|
928
|
+
const isDeveloperFunction = (node) => {
|
|
929
|
+
if (node.type === import_utils15.AST_NODE_TYPES.FunctionDeclaration) {
|
|
930
|
+
return true;
|
|
931
|
+
}
|
|
932
|
+
if (node.type === import_utils15.AST_NODE_TYPES.FunctionExpression || node.type === import_utils15.AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
933
|
+
if (isCallbackFunction(node)) {
|
|
934
|
+
return false;
|
|
935
|
+
}
|
|
936
|
+
const { parent } = node;
|
|
937
|
+
return parent?.type === import_utils15.AST_NODE_TYPES.VariableDeclarator || parent?.type === import_utils15.AST_NODE_TYPES.AssignmentExpression || parent?.type === import_utils15.AST_NODE_TYPES.Property || parent?.type === import_utils15.AST_NODE_TYPES.MethodDefinition;
|
|
938
|
+
}
|
|
939
|
+
return false;
|
|
940
|
+
};
|
|
941
|
+
const checkFunction = (node) => {
|
|
942
|
+
const { filename } = context;
|
|
943
|
+
if (filename.includes("node_modules") || filename.includes(".d.ts")) {
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
946
|
+
if (!isDeveloperFunction(node)) {
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
if (node.type === import_utils15.AST_NODE_TYPES.FunctionDeclaration && node.id) {
|
|
950
|
+
const functionName = node.id.name;
|
|
951
|
+
if (functionName.startsWith("_") || functionName.includes("$") || /^[A-Z][a-zA-Z]*$/.test(functionName)) {
|
|
952
|
+
return;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
if (node.params.length <= 1) {
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
const hasNonDestructuredParams = node.params.some(
|
|
959
|
+
(param) => param.type !== import_utils15.AST_NODE_TYPES.ObjectPattern && param.type !== import_utils15.AST_NODE_TYPES.RestElement
|
|
960
|
+
);
|
|
961
|
+
if (hasNonDestructuredParams) {
|
|
962
|
+
context.report({
|
|
963
|
+
node,
|
|
964
|
+
messageId: "preferDestructuring"
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
};
|
|
968
|
+
return {
|
|
969
|
+
FunctionDeclaration: checkFunction,
|
|
970
|
+
FunctionExpression: checkFunction,
|
|
971
|
+
ArrowFunctionExpression: checkFunction
|
|
972
|
+
};
|
|
973
|
+
}
|
|
974
|
+
});
|
|
975
|
+
var prefer_destructuring_params_default = preferDestructuringParams;
|
|
976
|
+
|
|
977
|
+
// src/rules/prefer-import-type.ts
|
|
978
|
+
var import_utils16 = require("@typescript-eslint/utils");
|
|
979
|
+
var createRule14 = import_utils16.ESLintUtils.RuleCreator(
|
|
980
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
981
|
+
);
|
|
982
|
+
var preferImportType = createRule14({
|
|
983
|
+
name: "prefer-import-type",
|
|
984
|
+
meta: {
|
|
985
|
+
type: "suggestion",
|
|
986
|
+
docs: {
|
|
987
|
+
description: "Enforce using 'import type' for type-only imports"
|
|
988
|
+
},
|
|
989
|
+
fixable: "code",
|
|
990
|
+
schema: [],
|
|
991
|
+
messages: {
|
|
992
|
+
preferImportType: "Use 'import type' for type-only imports"
|
|
993
|
+
}
|
|
994
|
+
},
|
|
995
|
+
defaultOptions: [],
|
|
996
|
+
create(context) {
|
|
997
|
+
function isInTypeContext(node) {
|
|
998
|
+
let current = node;
|
|
999
|
+
while (current) {
|
|
1000
|
+
switch (current.type) {
|
|
1001
|
+
case import_utils16.AST_NODE_TYPES.TSTypeReference:
|
|
1002
|
+
case import_utils16.AST_NODE_TYPES.TSTypeAnnotation:
|
|
1003
|
+
case import_utils16.AST_NODE_TYPES.TSTypeParameterInstantiation:
|
|
1004
|
+
case import_utils16.AST_NODE_TYPES.TSInterfaceHeritage:
|
|
1005
|
+
case import_utils16.AST_NODE_TYPES.TSClassImplements:
|
|
1006
|
+
case import_utils16.AST_NODE_TYPES.TSTypeQuery:
|
|
1007
|
+
case import_utils16.AST_NODE_TYPES.TSTypeAssertion:
|
|
1008
|
+
case import_utils16.AST_NODE_TYPES.TSAsExpression:
|
|
1009
|
+
case import_utils16.AST_NODE_TYPES.TSSatisfiesExpression:
|
|
1010
|
+
case import_utils16.AST_NODE_TYPES.TSTypeAliasDeclaration:
|
|
1011
|
+
case import_utils16.AST_NODE_TYPES.TSInterfaceDeclaration:
|
|
1012
|
+
case import_utils16.AST_NODE_TYPES.TSTypeParameter:
|
|
1013
|
+
case import_utils16.AST_NODE_TYPES.TSQualifiedName:
|
|
1014
|
+
return true;
|
|
1015
|
+
case import_utils16.AST_NODE_TYPES.MemberExpression:
|
|
1016
|
+
case import_utils16.AST_NODE_TYPES.Identifier:
|
|
1017
|
+
current = current.parent;
|
|
1018
|
+
break;
|
|
1019
|
+
default:
|
|
1020
|
+
return false;
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
return false;
|
|
1024
|
+
}
|
|
1025
|
+
function isUsedAsValue(localName, scope) {
|
|
1026
|
+
const variable = scope.set.get(localName);
|
|
1027
|
+
if (!variable) {
|
|
1028
|
+
return false;
|
|
1029
|
+
}
|
|
1030
|
+
if (variable.references.length === 0) {
|
|
1031
|
+
return false;
|
|
1032
|
+
}
|
|
1033
|
+
return variable.references.some((ref) => {
|
|
1034
|
+
if (ref.isWrite()) {
|
|
1035
|
+
return false;
|
|
1036
|
+
}
|
|
1037
|
+
const { identifier } = ref;
|
|
1038
|
+
const { parent } = identifier;
|
|
1039
|
+
if (!parent) {
|
|
1040
|
+
return false;
|
|
1041
|
+
}
|
|
1042
|
+
if (isInTypeContext(parent)) {
|
|
1043
|
+
return false;
|
|
1044
|
+
}
|
|
1045
|
+
switch (parent.type) {
|
|
1046
|
+
case import_utils16.AST_NODE_TYPES.CallExpression:
|
|
1047
|
+
case import_utils16.AST_NODE_TYPES.NewExpression:
|
|
1048
|
+
case import_utils16.AST_NODE_TYPES.JSXOpeningElement:
|
|
1049
|
+
case import_utils16.AST_NODE_TYPES.JSXClosingElement:
|
|
1050
|
+
case import_utils16.AST_NODE_TYPES.MemberExpression:
|
|
1051
|
+
case import_utils16.AST_NODE_TYPES.VariableDeclarator:
|
|
1052
|
+
case import_utils16.AST_NODE_TYPES.TaggedTemplateExpression:
|
|
1053
|
+
case import_utils16.AST_NODE_TYPES.SpreadElement:
|
|
1054
|
+
case import_utils16.AST_NODE_TYPES.ExportSpecifier:
|
|
1055
|
+
case import_utils16.AST_NODE_TYPES.ArrayExpression:
|
|
1056
|
+
case import_utils16.AST_NODE_TYPES.ObjectExpression:
|
|
1057
|
+
case import_utils16.AST_NODE_TYPES.BinaryExpression:
|
|
1058
|
+
case import_utils16.AST_NODE_TYPES.LogicalExpression:
|
|
1059
|
+
case import_utils16.AST_NODE_TYPES.UnaryExpression:
|
|
1060
|
+
case import_utils16.AST_NODE_TYPES.ReturnStatement:
|
|
1061
|
+
case import_utils16.AST_NODE_TYPES.ArrowFunctionExpression:
|
|
1062
|
+
case import_utils16.AST_NODE_TYPES.ConditionalExpression:
|
|
1063
|
+
case import_utils16.AST_NODE_TYPES.AwaitExpression:
|
|
1064
|
+
case import_utils16.AST_NODE_TYPES.YieldExpression:
|
|
1065
|
+
case import_utils16.AST_NODE_TYPES.Property:
|
|
1066
|
+
return true;
|
|
1067
|
+
default:
|
|
1068
|
+
return false;
|
|
1069
|
+
}
|
|
1070
|
+
});
|
|
1071
|
+
}
|
|
1072
|
+
function checkImportDeclaration(node) {
|
|
1073
|
+
if (node.importKind === "type") {
|
|
1074
|
+
return;
|
|
1075
|
+
}
|
|
1076
|
+
if (context.filename.includes(".test.") || context.filename.includes(".spec.") || context.filename.includes("__tests__")) {
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1079
|
+
if (node.specifiers.length === 0) {
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1082
|
+
const source = node.source.value;
|
|
1083
|
+
const isRuntimeImport = /\.(css|scss|sass|less|styl)(\?.*)?$/.test(source) || /\.(png|jpg|jpeg|gif|svg|webp|ico|bmp)(\?.*)?$/.test(source) || /\.(woff|woff2|ttf|eot|otf)(\?.*)?$/.test(source) || /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/.test(source) || /\.(json|txt|md|xml|yml|yaml)(\?.*)?$/.test(source) || /^next\/(font|image|link|head|script|dynamic|router)/.test(source) || source.includes("/font/") || source === "react-dom" || source === "react-dom/client" || source === "react-dom/server" || source.startsWith("@emotion/") || source.startsWith("styled-components") || source.includes("polyfill") || source.includes("shim") || source === "styled-jsx/css" || source.startsWith("webpack/");
|
|
1084
|
+
if (isRuntimeImport) {
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1087
|
+
const scope = context.sourceCode.getScope(node);
|
|
1088
|
+
const isTypeOnlyImport = node.specifiers.every((specifier) => {
|
|
1089
|
+
if (specifier.type === import_utils16.AST_NODE_TYPES.ImportDefaultSpecifier) {
|
|
1090
|
+
return false;
|
|
1091
|
+
}
|
|
1092
|
+
if (specifier.type === import_utils16.AST_NODE_TYPES.ImportNamespaceSpecifier) {
|
|
1093
|
+
return false;
|
|
1094
|
+
}
|
|
1095
|
+
if (specifier.type === import_utils16.AST_NODE_TYPES.ImportSpecifier) {
|
|
1096
|
+
const localName = specifier.local.name;
|
|
1097
|
+
return !isUsedAsValue(localName, scope);
|
|
1098
|
+
}
|
|
1099
|
+
return false;
|
|
1100
|
+
});
|
|
1101
|
+
if (isTypeOnlyImport) {
|
|
1102
|
+
context.report({
|
|
1103
|
+
node,
|
|
1104
|
+
messageId: "preferImportType",
|
|
1105
|
+
fix(fixer) {
|
|
1106
|
+
const sourceText = context.sourceCode.getText(node);
|
|
1107
|
+
const fixedSource = sourceText.replace(/^import\s+/, "import type ");
|
|
1108
|
+
return fixer.replaceText(node, fixedSource);
|
|
1109
|
+
}
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
return {
|
|
1114
|
+
ImportDeclaration: checkImportDeclaration
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
});
|
|
1118
|
+
var prefer_import_type_default = preferImportType;
|
|
1119
|
+
|
|
1120
|
+
// src/rules/prefer-interface-over-inline-types.ts
|
|
1121
|
+
var import_utils17 = require("@typescript-eslint/utils");
|
|
1122
|
+
var createRule15 = import_utils17.ESLintUtils.RuleCreator(
|
|
1123
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
1124
|
+
);
|
|
1125
|
+
var preferInterfaceOverInlineTypes = createRule15({
|
|
1126
|
+
name: "prefer-interface-over-inline-types",
|
|
1127
|
+
meta: {
|
|
1128
|
+
type: "suggestion",
|
|
1129
|
+
docs: {
|
|
1130
|
+
description: "Enforce interface declarations over inline type annotations for React component props"
|
|
1131
|
+
},
|
|
1132
|
+
fixable: void 0,
|
|
1133
|
+
schema: [],
|
|
1134
|
+
messages: {
|
|
1135
|
+
useInterface: "Use interface declaration for component props instead of inline type annotation"
|
|
1136
|
+
}
|
|
1137
|
+
},
|
|
1138
|
+
defaultOptions: [],
|
|
1139
|
+
create(context) {
|
|
1140
|
+
function hasJSXInConditional(node) {
|
|
1141
|
+
return node.consequent.type === import_utils17.AST_NODE_TYPES.JSXElement || node.consequent.type === import_utils17.AST_NODE_TYPES.JSXFragment || node.alternate.type === import_utils17.AST_NODE_TYPES.JSXElement || node.alternate.type === import_utils17.AST_NODE_TYPES.JSXFragment;
|
|
1142
|
+
}
|
|
1143
|
+
function hasJSXInLogical(node) {
|
|
1144
|
+
return node.right.type === import_utils17.AST_NODE_TYPES.JSXElement || node.right.type === import_utils17.AST_NODE_TYPES.JSXFragment;
|
|
1145
|
+
}
|
|
1146
|
+
function hasJSXReturn(block) {
|
|
1147
|
+
return block.body.some((stmt) => {
|
|
1148
|
+
if (stmt.type === import_utils17.AST_NODE_TYPES.ReturnStatement && stmt.argument) {
|
|
1149
|
+
return stmt.argument.type === import_utils17.AST_NODE_TYPES.JSXElement || stmt.argument.type === import_utils17.AST_NODE_TYPES.JSXFragment || stmt.argument.type === import_utils17.AST_NODE_TYPES.ConditionalExpression && hasJSXInConditional(stmt.argument) || stmt.argument.type === import_utils17.AST_NODE_TYPES.LogicalExpression && hasJSXInLogical(stmt.argument);
|
|
1150
|
+
}
|
|
1151
|
+
return false;
|
|
1152
|
+
});
|
|
1153
|
+
}
|
|
1154
|
+
function isReactComponent(node) {
|
|
1155
|
+
if (node.type === import_utils17.AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
1156
|
+
if (node.body.type === import_utils17.AST_NODE_TYPES.JSXElement || node.body.type === import_utils17.AST_NODE_TYPES.JSXFragment) {
|
|
1157
|
+
return true;
|
|
1158
|
+
}
|
|
1159
|
+
if (node.body.type === import_utils17.AST_NODE_TYPES.BlockStatement) {
|
|
1160
|
+
return hasJSXReturn(node.body);
|
|
1161
|
+
}
|
|
1162
|
+
} else if (node.type === import_utils17.AST_NODE_TYPES.FunctionExpression || node.type === import_utils17.AST_NODE_TYPES.FunctionDeclaration) {
|
|
1163
|
+
if (node.body && node.body.type === import_utils17.AST_NODE_TYPES.BlockStatement) {
|
|
1164
|
+
return hasJSXReturn(node.body);
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
return false;
|
|
1168
|
+
}
|
|
1169
|
+
function isInlineTypeAnnotation(node) {
|
|
1170
|
+
if (node.type === import_utils17.AST_NODE_TYPES.TSTypeLiteral) {
|
|
1171
|
+
return true;
|
|
1172
|
+
}
|
|
1173
|
+
if (node.type === import_utils17.AST_NODE_TYPES.TSTypeReference && node.typeArguments) {
|
|
1174
|
+
return node.typeArguments.params.some((param) => param.type === import_utils17.AST_NODE_TYPES.TSTypeLiteral);
|
|
1175
|
+
}
|
|
1176
|
+
if (node.type === import_utils17.AST_NODE_TYPES.TSUnionType) {
|
|
1177
|
+
return node.types.some((type) => isInlineTypeAnnotation(type));
|
|
1178
|
+
}
|
|
1179
|
+
return false;
|
|
1180
|
+
}
|
|
1181
|
+
function hasInlineObjectType(node) {
|
|
1182
|
+
if (node.type === import_utils17.AST_NODE_TYPES.TSTypeLiteral) {
|
|
1183
|
+
return true;
|
|
1184
|
+
}
|
|
1185
|
+
if (node.type === import_utils17.AST_NODE_TYPES.TSTypeReference && node.typeArguments) {
|
|
1186
|
+
return node.typeArguments.params.some((param) => param.type === import_utils17.AST_NODE_TYPES.TSTypeLiteral);
|
|
1187
|
+
}
|
|
1188
|
+
if (node.type === import_utils17.AST_NODE_TYPES.TSUnionType) {
|
|
1189
|
+
return node.types.some((type) => hasInlineObjectType(type));
|
|
1190
|
+
}
|
|
1191
|
+
return false;
|
|
1192
|
+
}
|
|
1193
|
+
function checkFunction(node) {
|
|
1194
|
+
if (!isReactComponent(node)) {
|
|
1195
|
+
return;
|
|
1196
|
+
}
|
|
1197
|
+
if (node.params.length !== 1) {
|
|
1198
|
+
return;
|
|
1199
|
+
}
|
|
1200
|
+
const param = node.params[0];
|
|
1201
|
+
if (param.type === import_utils17.AST_NODE_TYPES.Identifier && param.typeAnnotation) {
|
|
1202
|
+
const { typeAnnotation } = param.typeAnnotation;
|
|
1203
|
+
if (isInlineTypeAnnotation(typeAnnotation) && hasInlineObjectType(typeAnnotation)) {
|
|
1204
|
+
context.report({
|
|
1205
|
+
node: param.typeAnnotation,
|
|
1206
|
+
messageId: "useInterface"
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
return {
|
|
1212
|
+
ArrowFunctionExpression: checkFunction,
|
|
1213
|
+
FunctionExpression: checkFunction,
|
|
1214
|
+
FunctionDeclaration: checkFunction
|
|
1215
|
+
};
|
|
1216
|
+
}
|
|
1217
|
+
});
|
|
1218
|
+
var prefer_interface_over_inline_types_default = preferInterfaceOverInlineTypes;
|
|
1219
|
+
|
|
1220
|
+
// src/rules/prefer-jsx-template-literals.ts
|
|
1221
|
+
var import_utils18 = require("@typescript-eslint/utils");
|
|
1222
|
+
var createRule16 = import_utils18.ESLintUtils.RuleCreator(
|
|
1223
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
1224
|
+
);
|
|
1225
|
+
var preferJSXTemplateLiterals = createRule16({
|
|
1226
|
+
name: "prefer-jsx-template-literals",
|
|
1227
|
+
meta: {
|
|
1228
|
+
type: "suggestion",
|
|
1229
|
+
docs: {
|
|
1230
|
+
description: "Enforce using template literals instead of mixing text and JSX expressions"
|
|
1231
|
+
},
|
|
1232
|
+
fixable: "code",
|
|
1233
|
+
schema: [],
|
|
1234
|
+
messages: {
|
|
1235
|
+
preferTemplate: "Use template literal instead of mixing text with JSX expressions"
|
|
1236
|
+
}
|
|
1237
|
+
},
|
|
1238
|
+
defaultOptions: [],
|
|
1239
|
+
create(context) {
|
|
1240
|
+
function handleTextBeforeExpression(textNode, exprNode) {
|
|
1241
|
+
const textValue = textNode.value;
|
|
1242
|
+
const trimmedText = textValue.trim();
|
|
1243
|
+
if (!trimmedText) {
|
|
1244
|
+
return;
|
|
1245
|
+
}
|
|
1246
|
+
const hasTextContent = trimmedText.length > 0 && textValue !== trimmedText;
|
|
1247
|
+
const hasNoTrailingSpace = trimmedText.length > 0 && /\S$/.test(textValue);
|
|
1248
|
+
if (!hasTextContent && !hasNoTrailingSpace) {
|
|
1249
|
+
return;
|
|
1250
|
+
}
|
|
1251
|
+
context.report({
|
|
1252
|
+
node: textNode,
|
|
1253
|
+
messageId: "preferTemplate",
|
|
1254
|
+
fix(fixer) {
|
|
1255
|
+
const textPart = textValue.trimEnd();
|
|
1256
|
+
const exprText = context.sourceCode.getText(exprNode.expression);
|
|
1257
|
+
const templateLiteral = `{\`${textPart}\${${exprText}}\`}`;
|
|
1258
|
+
return [fixer.replaceText(textNode, templateLiteral), fixer.remove(exprNode)];
|
|
1259
|
+
}
|
|
1260
|
+
});
|
|
1261
|
+
}
|
|
1262
|
+
function handleExpressionBeforeText(exprNode, textNode) {
|
|
1263
|
+
const textValue = textNode.value;
|
|
1264
|
+
const trimmedText = textValue.trim();
|
|
1265
|
+
if (!trimmedText) {
|
|
1266
|
+
return;
|
|
1267
|
+
}
|
|
1268
|
+
const startsWithNonWhitespace = /^\S/.test(trimmedText);
|
|
1269
|
+
if (!startsWithNonWhitespace) {
|
|
1270
|
+
return;
|
|
1271
|
+
}
|
|
1272
|
+
context.report({
|
|
1273
|
+
node: textNode,
|
|
1274
|
+
messageId: "preferTemplate",
|
|
1275
|
+
fix(fixer) {
|
|
1276
|
+
const exprText = context.sourceCode.getText(exprNode.expression);
|
|
1277
|
+
const textPart = textValue.trim();
|
|
1278
|
+
const templateLiteral = `{\`\${${exprText}}${textPart}\`}`;
|
|
1279
|
+
return [fixer.replaceText(exprNode, templateLiteral), fixer.remove(textNode)];
|
|
1280
|
+
}
|
|
1281
|
+
});
|
|
1282
|
+
}
|
|
1283
|
+
function checkJSXElement(node) {
|
|
1284
|
+
const { children } = node;
|
|
1285
|
+
if (children.length < 2) {
|
|
1286
|
+
return;
|
|
1287
|
+
}
|
|
1288
|
+
for (let i = 0; i < children.length - 1; i += 1) {
|
|
1289
|
+
const child = children[i];
|
|
1290
|
+
const nextChild = children[i + 1];
|
|
1291
|
+
if (!child || !nextChild) {
|
|
1292
|
+
return;
|
|
1293
|
+
}
|
|
1294
|
+
if (child.type === import_utils18.AST_NODE_TYPES.JSXText && nextChild.type === import_utils18.AST_NODE_TYPES.JSXExpressionContainer) {
|
|
1295
|
+
handleTextBeforeExpression(child, nextChild);
|
|
1296
|
+
} else if (child.type === import_utils18.AST_NODE_TYPES.JSXExpressionContainer && nextChild.type === import_utils18.AST_NODE_TYPES.JSXText) {
|
|
1297
|
+
handleExpressionBeforeText(child, nextChild);
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
return {
|
|
1302
|
+
JSXElement: checkJSXElement
|
|
1303
|
+
};
|
|
1304
|
+
}
|
|
1305
|
+
});
|
|
1306
|
+
var prefer_jsx_template_literals_default = preferJSXTemplateLiterals;
|
|
1307
|
+
|
|
1308
|
+
// src/rules/prefer-named-param-types.ts
|
|
1309
|
+
var import_utils19 = require("@typescript-eslint/utils");
|
|
1310
|
+
var createRule17 = import_utils19.ESLintUtils.RuleCreator(
|
|
1311
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
1312
|
+
);
|
|
1313
|
+
var preferNamedParamTypes = createRule17({
|
|
1314
|
+
name: "prefer-named-param-types",
|
|
1315
|
+
meta: {
|
|
1316
|
+
type: "suggestion",
|
|
1317
|
+
docs: {
|
|
1318
|
+
description: "Enforce named interfaces/types instead of inline object types for function parameters"
|
|
1319
|
+
},
|
|
1320
|
+
messages: {
|
|
1321
|
+
preferNamedParamTypes: "Use a named interface or type for object parameter types instead of inline type annotations"
|
|
1322
|
+
},
|
|
1323
|
+
schema: []
|
|
1324
|
+
},
|
|
1325
|
+
defaultOptions: [],
|
|
1326
|
+
create(context) {
|
|
1327
|
+
function hasInlineObjectType(param) {
|
|
1328
|
+
if (param.type === import_utils19.AST_NODE_TYPES.AssignmentPattern) {
|
|
1329
|
+
return hasInlineObjectType(param.left);
|
|
1330
|
+
}
|
|
1331
|
+
if (param.type === import_utils19.AST_NODE_TYPES.ObjectPattern) {
|
|
1332
|
+
if (param.typeAnnotation?.typeAnnotation.type === import_utils19.AST_NODE_TYPES.TSTypeLiteral) {
|
|
1333
|
+
return true;
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
if (param.type === import_utils19.AST_NODE_TYPES.Identifier) {
|
|
1337
|
+
if (param.typeAnnotation?.typeAnnotation.type === import_utils19.AST_NODE_TYPES.TSTypeLiteral) {
|
|
1338
|
+
return true;
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
return false;
|
|
1342
|
+
}
|
|
1343
|
+
function checkFunction(node) {
|
|
1344
|
+
let params = [];
|
|
1345
|
+
if ("params" in node) {
|
|
1346
|
+
params = node.params;
|
|
1347
|
+
} else if ("value" in node && node.value) {
|
|
1348
|
+
params = node.value.params;
|
|
1349
|
+
}
|
|
1350
|
+
params.forEach((param) => {
|
|
1351
|
+
if (hasInlineObjectType(param)) {
|
|
1352
|
+
context.report({
|
|
1353
|
+
node: param,
|
|
1354
|
+
messageId: "preferNamedParamTypes"
|
|
1355
|
+
});
|
|
1356
|
+
}
|
|
1357
|
+
});
|
|
1358
|
+
}
|
|
1359
|
+
return {
|
|
1360
|
+
FunctionDeclaration: checkFunction,
|
|
1361
|
+
FunctionExpression: checkFunction,
|
|
1362
|
+
ArrowFunctionExpression: checkFunction,
|
|
1363
|
+
TSMethodSignature: checkFunction,
|
|
1364
|
+
MethodDefinition: checkFunction
|
|
1365
|
+
};
|
|
1366
|
+
}
|
|
1367
|
+
});
|
|
1368
|
+
var prefer_named_param_types_default = preferNamedParamTypes;
|
|
1369
|
+
|
|
1370
|
+
// src/rules/prefer-react-import-types.ts
|
|
1371
|
+
var import_utils20 = require("@typescript-eslint/utils");
|
|
1372
|
+
var createRule18 = import_utils20.ESLintUtils.RuleCreator(
|
|
1373
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
1374
|
+
);
|
|
1375
|
+
var preferReactImportTypes = createRule18({
|
|
1376
|
+
name: "prefer-react-import-types",
|
|
1377
|
+
meta: {
|
|
1378
|
+
type: "suggestion",
|
|
1379
|
+
docs: {
|
|
1380
|
+
description: "Enforce importing React types and utilities from 'react' instead of using React.X"
|
|
1381
|
+
},
|
|
1382
|
+
fixable: "code",
|
|
1383
|
+
schema: [],
|
|
1384
|
+
messages: {
|
|
1385
|
+
preferDirectImport: "Use direct import '{{importStatement}}' instead of 'React.{{typeName}}'"
|
|
1386
|
+
}
|
|
1387
|
+
},
|
|
1388
|
+
defaultOptions: [],
|
|
1389
|
+
create(context) {
|
|
1390
|
+
const reactTypes = /* @__PURE__ */ new Set([
|
|
1391
|
+
"ReactNode",
|
|
1392
|
+
"ReactElement",
|
|
1393
|
+
"ReactChildren",
|
|
1394
|
+
"ReactChild",
|
|
1395
|
+
"ComponentType",
|
|
1396
|
+
"FC",
|
|
1397
|
+
"FunctionComponent",
|
|
1398
|
+
"Component",
|
|
1399
|
+
"PureComponent",
|
|
1400
|
+
"ReactEventHandler",
|
|
1401
|
+
"MouseEventHandler",
|
|
1402
|
+
"ChangeEventHandler",
|
|
1403
|
+
"FormEventHandler",
|
|
1404
|
+
"KeyboardEventHandler",
|
|
1405
|
+
"TouchEventHandler",
|
|
1406
|
+
"PointerEventHandler",
|
|
1407
|
+
"FocusEventHandler",
|
|
1408
|
+
"UIEventHandler",
|
|
1409
|
+
"WheelEventHandler",
|
|
1410
|
+
"AnimationEventHandler",
|
|
1411
|
+
"TransitionEventHandler",
|
|
1412
|
+
"RefObject",
|
|
1413
|
+
"MutableRefObject",
|
|
1414
|
+
"Ref",
|
|
1415
|
+
"ForwardedRef",
|
|
1416
|
+
"HTMLProps",
|
|
1417
|
+
"ComponentProps",
|
|
1418
|
+
"JSXElementConstructor"
|
|
1419
|
+
]);
|
|
1420
|
+
const reactRuntimeExports = /* @__PURE__ */ new Set([
|
|
1421
|
+
"useState",
|
|
1422
|
+
"useEffect",
|
|
1423
|
+
"useContext",
|
|
1424
|
+
"useReducer",
|
|
1425
|
+
"useCallback",
|
|
1426
|
+
"useMemo",
|
|
1427
|
+
"useRef",
|
|
1428
|
+
"useImperativeHandle",
|
|
1429
|
+
"useLayoutEffect",
|
|
1430
|
+
"useDebugValue",
|
|
1431
|
+
"useDeferredValue",
|
|
1432
|
+
"useTransition",
|
|
1433
|
+
"useId",
|
|
1434
|
+
"useSyncExternalStore",
|
|
1435
|
+
"useInsertionEffect",
|
|
1436
|
+
"createElement",
|
|
1437
|
+
"createContext",
|
|
1438
|
+
"forwardRef",
|
|
1439
|
+
"memo",
|
|
1440
|
+
"lazy",
|
|
1441
|
+
"Suspense",
|
|
1442
|
+
"Fragment",
|
|
1443
|
+
"StrictMode",
|
|
1444
|
+
"createRef",
|
|
1445
|
+
"isValidElement",
|
|
1446
|
+
"cloneElement",
|
|
1447
|
+
"Children"
|
|
1448
|
+
]);
|
|
1449
|
+
const allReactExports = /* @__PURE__ */ new Set([...reactTypes, ...reactRuntimeExports]);
|
|
1450
|
+
function checkMemberExpression(node) {
|
|
1451
|
+
if (node.object.type === import_utils20.AST_NODE_TYPES.Identifier && node.object.name === "React" && node.property.type === import_utils20.AST_NODE_TYPES.Identifier && allReactExports.has(node.property.name)) {
|
|
1452
|
+
const typeName = node.property.name;
|
|
1453
|
+
const isType = reactTypes.has(typeName);
|
|
1454
|
+
const importStatement = isType ? `import type { ${typeName} } from "react"` : `import { ${typeName} } from "react"`;
|
|
1455
|
+
context.report({
|
|
1456
|
+
node,
|
|
1457
|
+
messageId: "preferDirectImport",
|
|
1458
|
+
data: { typeName, importStatement },
|
|
1459
|
+
fix(fixer) {
|
|
1460
|
+
return fixer.replaceText(node, typeName);
|
|
1461
|
+
}
|
|
1462
|
+
});
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
return {
|
|
1466
|
+
MemberExpression: checkMemberExpression,
|
|
1467
|
+
"TSTypeReference > TSQualifiedName": (node) => {
|
|
1468
|
+
if (node.left.type === import_utils20.AST_NODE_TYPES.Identifier && node.left.name === "React" && node.right.type === import_utils20.AST_NODE_TYPES.Identifier && allReactExports.has(node.right.name)) {
|
|
1469
|
+
const typeName = node.right.name;
|
|
1470
|
+
const isType = reactTypes.has(typeName);
|
|
1471
|
+
const importStatement = isType ? `import type { ${typeName} } from "react"` : `import { ${typeName} } from "react"`;
|
|
1472
|
+
context.report({
|
|
1473
|
+
node,
|
|
1474
|
+
messageId: "preferDirectImport",
|
|
1475
|
+
data: { typeName, importStatement },
|
|
1476
|
+
fix(fixer) {
|
|
1477
|
+
return fixer.replaceText(node, typeName);
|
|
1478
|
+
}
|
|
1479
|
+
});
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
};
|
|
1483
|
+
}
|
|
1484
|
+
});
|
|
1485
|
+
var prefer_react_import_types_default = preferReactImportTypes;
|
|
1486
|
+
|
|
1487
|
+
// src/rules/react-props-destructure.ts
|
|
1488
|
+
var import_utils21 = require("@typescript-eslint/utils");
|
|
1489
|
+
var createRule19 = import_utils21.ESLintUtils.RuleCreator(
|
|
1490
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
1491
|
+
);
|
|
1492
|
+
var reactPropsDestructure = createRule19({
|
|
1493
|
+
name: "react-props-destructure",
|
|
1494
|
+
meta: {
|
|
1495
|
+
type: "suggestion",
|
|
1496
|
+
docs: {
|
|
1497
|
+
description: "Enforce destructuring props inside React component body instead of parameters"
|
|
1498
|
+
},
|
|
1499
|
+
fixable: void 0,
|
|
1500
|
+
schema: [],
|
|
1501
|
+
messages: {
|
|
1502
|
+
noParameterDestructuring: "Destructure props inside component body instead of parameters. Use 'const { {{properties}} } = props;'"
|
|
1503
|
+
}
|
|
1504
|
+
},
|
|
1505
|
+
defaultOptions: [],
|
|
1506
|
+
create(context) {
|
|
1507
|
+
function hasJSXInConditional(node) {
|
|
1508
|
+
return node.consequent.type === import_utils21.AST_NODE_TYPES.JSXElement || node.consequent.type === import_utils21.AST_NODE_TYPES.JSXFragment || node.alternate.type === import_utils21.AST_NODE_TYPES.JSXElement || node.alternate.type === import_utils21.AST_NODE_TYPES.JSXFragment;
|
|
1509
|
+
}
|
|
1510
|
+
function hasJSXInLogical(node) {
|
|
1511
|
+
return node.right.type === import_utils21.AST_NODE_TYPES.JSXElement || node.right.type === import_utils21.AST_NODE_TYPES.JSXFragment;
|
|
1512
|
+
}
|
|
1513
|
+
function hasJSXReturn(block) {
|
|
1514
|
+
return block.body.some((stmt) => {
|
|
1515
|
+
if (stmt.type === import_utils21.AST_NODE_TYPES.ReturnStatement && stmt.argument) {
|
|
1516
|
+
return stmt.argument.type === import_utils21.AST_NODE_TYPES.JSXElement || stmt.argument.type === import_utils21.AST_NODE_TYPES.JSXFragment || stmt.argument.type === import_utils21.AST_NODE_TYPES.ConditionalExpression && hasJSXInConditional(stmt.argument) || stmt.argument.type === import_utils21.AST_NODE_TYPES.LogicalExpression && hasJSXInLogical(stmt.argument);
|
|
1517
|
+
}
|
|
1518
|
+
return false;
|
|
1519
|
+
});
|
|
1520
|
+
}
|
|
1521
|
+
function isReactComponent(node) {
|
|
1522
|
+
if (node.type === import_utils21.AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
1523
|
+
if (node.body.type === import_utils21.AST_NODE_TYPES.JSXElement || node.body.type === import_utils21.AST_NODE_TYPES.JSXFragment) {
|
|
1524
|
+
return true;
|
|
1525
|
+
}
|
|
1526
|
+
if (node.body.type === import_utils21.AST_NODE_TYPES.BlockStatement) {
|
|
1527
|
+
return hasJSXReturn(node.body);
|
|
1528
|
+
}
|
|
1529
|
+
} else if (node.type === import_utils21.AST_NODE_TYPES.FunctionExpression || node.type === import_utils21.AST_NODE_TYPES.FunctionDeclaration) {
|
|
1530
|
+
if (node.body && node.body.type === import_utils21.AST_NODE_TYPES.BlockStatement) {
|
|
1531
|
+
return hasJSXReturn(node.body);
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
return false;
|
|
1535
|
+
}
|
|
1536
|
+
function checkFunction(node) {
|
|
1537
|
+
if (!isReactComponent(node)) {
|
|
1538
|
+
return;
|
|
1539
|
+
}
|
|
1540
|
+
if (node.params.length !== 1) {
|
|
1541
|
+
return;
|
|
1542
|
+
}
|
|
1543
|
+
const param = node.params[0];
|
|
1544
|
+
if (param.type === import_utils21.AST_NODE_TYPES.ObjectPattern) {
|
|
1545
|
+
const properties = param.properties.filter((prop) => prop.type === import_utils21.AST_NODE_TYPES.Property).map((prop) => {
|
|
1546
|
+
if (prop.key.type === import_utils21.AST_NODE_TYPES.Identifier) {
|
|
1547
|
+
return prop.key.name;
|
|
1548
|
+
}
|
|
1549
|
+
return null;
|
|
1550
|
+
}).filter((name) => name !== null);
|
|
1551
|
+
if (properties.length === 0) {
|
|
1552
|
+
return;
|
|
1553
|
+
}
|
|
1554
|
+
context.report({
|
|
1555
|
+
node: param,
|
|
1556
|
+
messageId: "noParameterDestructuring",
|
|
1557
|
+
data: {
|
|
1558
|
+
properties: properties.join(", ")
|
|
1559
|
+
}
|
|
1560
|
+
});
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
return {
|
|
1564
|
+
ArrowFunctionExpression: checkFunction,
|
|
1565
|
+
FunctionExpression: checkFunction,
|
|
1566
|
+
FunctionDeclaration: checkFunction
|
|
1567
|
+
};
|
|
1568
|
+
}
|
|
1569
|
+
});
|
|
1570
|
+
var react_props_destructure_default = reactPropsDestructure;
|
|
1571
|
+
|
|
1572
|
+
// src/index.ts
|
|
1573
|
+
var meta = {
|
|
1574
|
+
name: package_default.name,
|
|
1575
|
+
version: package_default.version
|
|
1576
|
+
};
|
|
1577
|
+
var rules = {
|
|
1578
|
+
"enforce-readonly-component-props": enforce_readonly_component_props_default,
|
|
1579
|
+
"enforce-sorted-destructuring": enforce_sorted_destructuring_default,
|
|
1580
|
+
"file-kebab-case": file_kebab_case_default,
|
|
1581
|
+
"jsx-pascal-case": jsx_pascal_case_default,
|
|
1582
|
+
"jsx-no-non-component-function": jsx_no_non_component_function_default,
|
|
1583
|
+
"jsx-no-variable-in-callback": jsx_no_variable_in_callback_default,
|
|
1584
|
+
"md-filename-case-restriction": md_filename_case_restriction_default,
|
|
1585
|
+
"no-complex-inline-return": no_complex_inline_return_default,
|
|
1586
|
+
"no-emoji": no_emoji_default,
|
|
1587
|
+
"no-env-fallback": no_env_fallback_default,
|
|
1588
|
+
"no-explicit-return-type": no_explicit_return_type_default,
|
|
1589
|
+
"no-logic-in-params": no_logic_in_params_default,
|
|
1590
|
+
"prefer-destructuring-params": prefer_destructuring_params_default,
|
|
1591
|
+
"prefer-import-type": prefer_import_type_default,
|
|
1592
|
+
"prefer-interface-over-inline-types": prefer_interface_over_inline_types_default,
|
|
1593
|
+
"prefer-jsx-template-literals": prefer_jsx_template_literals_default,
|
|
1594
|
+
"prefer-named-param-types": prefer_named_param_types_default,
|
|
1595
|
+
"prefer-react-import-types": prefer_react_import_types_default,
|
|
1596
|
+
"react-props-destructure": react_props_destructure_default
|
|
1597
|
+
};
|
|
1598
|
+
var plugin = {
|
|
1599
|
+
meta,
|
|
1600
|
+
rules
|
|
1601
|
+
};
|
|
1602
|
+
var baseRules = {
|
|
1603
|
+
"nextfriday/no-emoji": "warn",
|
|
1604
|
+
"nextfriday/enforce-sorted-destructuring": "warn",
|
|
1605
|
+
"nextfriday/file-kebab-case": "warn",
|
|
1606
|
+
"nextfriday/md-filename-case-restriction": "warn",
|
|
1607
|
+
"nextfriday/prefer-destructuring-params": "warn",
|
|
1608
|
+
"nextfriday/no-explicit-return-type": "warn",
|
|
1609
|
+
"nextfriday/prefer-import-type": "warn",
|
|
1610
|
+
"nextfriday/prefer-named-param-types": "warn",
|
|
1611
|
+
"nextfriday/prefer-react-import-types": "warn",
|
|
1612
|
+
"nextfriday/no-complex-inline-return": "warn",
|
|
1613
|
+
"nextfriday/no-logic-in-params": "warn",
|
|
1614
|
+
"nextfriday/no-env-fallback": "warn"
|
|
1615
|
+
};
|
|
1616
|
+
var baseRecommendedRules = {
|
|
1617
|
+
"nextfriday/no-emoji": "error",
|
|
1618
|
+
"nextfriday/enforce-sorted-destructuring": "error",
|
|
1619
|
+
"nextfriday/file-kebab-case": "error",
|
|
1620
|
+
"nextfriday/md-filename-case-restriction": "error",
|
|
1621
|
+
"nextfriday/prefer-destructuring-params": "error",
|
|
1622
|
+
"nextfriday/no-explicit-return-type": "error",
|
|
1623
|
+
"nextfriday/prefer-import-type": "error",
|
|
1624
|
+
"nextfriday/prefer-named-param-types": "error",
|
|
1625
|
+
"nextfriday/prefer-react-import-types": "error",
|
|
1626
|
+
"nextfriday/no-complex-inline-return": "error",
|
|
1627
|
+
"nextfriday/no-logic-in-params": "error",
|
|
1628
|
+
"nextfriday/no-env-fallback": "error"
|
|
1629
|
+
};
|
|
1630
|
+
var jsxRules = {
|
|
1631
|
+
"nextfriday/jsx-pascal-case": "warn",
|
|
1632
|
+
"nextfriday/jsx-no-non-component-function": "warn",
|
|
1633
|
+
"nextfriday/jsx-no-variable-in-callback": "warn",
|
|
1634
|
+
"nextfriday/prefer-interface-over-inline-types": "warn",
|
|
1635
|
+
"nextfriday/prefer-jsx-template-literals": "warn",
|
|
1636
|
+
"nextfriday/react-props-destructure": "warn",
|
|
1637
|
+
"nextfriday/enforce-readonly-component-props": "warn"
|
|
1638
|
+
};
|
|
1639
|
+
var jsxRecommendedRules = {
|
|
1640
|
+
"nextfriday/jsx-pascal-case": "error",
|
|
1641
|
+
"nextfriday/jsx-no-non-component-function": "error",
|
|
1642
|
+
"nextfriday/jsx-no-variable-in-callback": "error",
|
|
1643
|
+
"nextfriday/prefer-interface-over-inline-types": "error",
|
|
1644
|
+
"nextfriday/prefer-jsx-template-literals": "error",
|
|
1645
|
+
"nextfriday/react-props-destructure": "error",
|
|
1646
|
+
"nextfriday/enforce-readonly-component-props": "error"
|
|
1647
|
+
};
|
|
1648
|
+
var createConfig = (configRules) => ({
|
|
1649
|
+
plugins: {
|
|
1650
|
+
nextfriday: plugin
|
|
1651
|
+
},
|
|
1652
|
+
rules: configRules
|
|
1653
|
+
});
|
|
1654
|
+
var configs = {
|
|
1655
|
+
base: createConfig(baseRules),
|
|
1656
|
+
"base/recommended": createConfig(baseRecommendedRules),
|
|
1657
|
+
react: createConfig({
|
|
1658
|
+
...baseRules,
|
|
1659
|
+
...jsxRules
|
|
1660
|
+
}),
|
|
1661
|
+
"react/recommended": createConfig({
|
|
1662
|
+
...baseRecommendedRules,
|
|
1663
|
+
...jsxRecommendedRules
|
|
1664
|
+
}),
|
|
1665
|
+
nextjs: createConfig({
|
|
1666
|
+
...baseRules,
|
|
1667
|
+
...jsxRules
|
|
1668
|
+
}),
|
|
1669
|
+
"nextjs/recommended": createConfig({
|
|
1670
|
+
...baseRecommendedRules,
|
|
1671
|
+
...jsxRecommendedRules
|
|
1672
|
+
})
|
|
1673
|
+
};
|
|
1674
|
+
var nextfridayPlugin = {
|
|
1675
|
+
meta,
|
|
1676
|
+
configs,
|
|
1677
|
+
rules
|
|
1678
|
+
};
|
|
1679
|
+
var index_default = nextfridayPlugin;
|
|
1680
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1681
|
+
0 && (module.exports = {
|
|
1682
|
+
configs,
|
|
1683
|
+
meta,
|
|
1684
|
+
rules
|
|
1685
|
+
});
|
|
1686
|
+
//# sourceMappingURL=index.cjs.map
|