eslint-plugin-nextfriday 1.5.3 → 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 +9 -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 +577 -127
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +56 -0
- package/lib/index.d.ts +56 -0
- package/lib/index.js +577 -127
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// package.json
|
|
2
2
|
var package_default = {
|
|
3
3
|
name: "eslint-plugin-nextfriday",
|
|
4
|
-
version: "1.
|
|
4
|
+
version: "1.6.0",
|
|
5
5
|
description: "A comprehensive ESLint plugin providing custom rules and configurations for Next Friday development workflows.",
|
|
6
6
|
keywords: [
|
|
7
7
|
"eslint",
|
|
@@ -118,7 +118,7 @@ var package_default = {
|
|
|
118
118
|
// src/rules/enforce-readonly-component-props.ts
|
|
119
119
|
import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
|
|
120
120
|
var createRule = ESLintUtils.RuleCreator(
|
|
121
|
-
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.
|
|
121
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
122
122
|
);
|
|
123
123
|
var enforceReadonlyComponentProps = createRule({
|
|
124
124
|
name: "enforce-readonly-component-props",
|
|
@@ -207,11 +207,132 @@ var enforceReadonlyComponentProps = createRule({
|
|
|
207
207
|
});
|
|
208
208
|
var enforce_readonly_component_props_default = enforceReadonlyComponentProps;
|
|
209
209
|
|
|
210
|
+
// src/rules/enforce-sorted-destructuring.ts
|
|
211
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES2, ESLintUtils as ESLintUtils2 } from "@typescript-eslint/utils";
|
|
212
|
+
var createRule2 = ESLintUtils2.RuleCreator(
|
|
213
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
214
|
+
);
|
|
215
|
+
var enforceSortedDestructuring = createRule2({
|
|
216
|
+
name: "enforce-sorted-destructuring",
|
|
217
|
+
meta: {
|
|
218
|
+
type: "suggestion",
|
|
219
|
+
docs: {
|
|
220
|
+
description: "Enforce alphabetical sorting of destructured properties with defaults first"
|
|
221
|
+
},
|
|
222
|
+
schema: [],
|
|
223
|
+
messages: {
|
|
224
|
+
unsortedDestructuring: "Destructured properties should be sorted alphabetically. Properties with defaults should come first, sorted by type (string, number, boolean, object) then alphabetically."
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
defaultOptions: [],
|
|
228
|
+
create(context) {
|
|
229
|
+
function getPropertyName(property) {
|
|
230
|
+
if (property.type === AST_NODE_TYPES2.RestElement) {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
if (property.key.type === AST_NODE_TYPES2.Identifier) {
|
|
234
|
+
return property.key.name;
|
|
235
|
+
}
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
function hasDefaultValue(property) {
|
|
239
|
+
return property.value.type === AST_NODE_TYPES2.AssignmentPattern && Boolean(property.value.right);
|
|
240
|
+
}
|
|
241
|
+
function getDefaultValueType(property) {
|
|
242
|
+
if (!hasDefaultValue(property)) {
|
|
243
|
+
return "none";
|
|
244
|
+
}
|
|
245
|
+
const assignmentPattern = property.value;
|
|
246
|
+
const { right } = assignmentPattern;
|
|
247
|
+
if (!right) {
|
|
248
|
+
return "none";
|
|
249
|
+
}
|
|
250
|
+
switch (right.type) {
|
|
251
|
+
case AST_NODE_TYPES2.Literal:
|
|
252
|
+
if (typeof right.value === "string") {
|
|
253
|
+
return "string";
|
|
254
|
+
}
|
|
255
|
+
if (typeof right.value === "number") {
|
|
256
|
+
return "number";
|
|
257
|
+
}
|
|
258
|
+
if (typeof right.value === "boolean") {
|
|
259
|
+
return "boolean";
|
|
260
|
+
}
|
|
261
|
+
return "other";
|
|
262
|
+
case AST_NODE_TYPES2.TemplateLiteral:
|
|
263
|
+
return "string";
|
|
264
|
+
case AST_NODE_TYPES2.ObjectExpression:
|
|
265
|
+
case AST_NODE_TYPES2.ArrayExpression:
|
|
266
|
+
return "object";
|
|
267
|
+
default:
|
|
268
|
+
return "other";
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
function getTypeSortOrder(type) {
|
|
272
|
+
const order = {
|
|
273
|
+
string: 0,
|
|
274
|
+
number: 1,
|
|
275
|
+
boolean: 2,
|
|
276
|
+
object: 3,
|
|
277
|
+
other: 4,
|
|
278
|
+
none: 5
|
|
279
|
+
};
|
|
280
|
+
return order[type] ?? 5;
|
|
281
|
+
}
|
|
282
|
+
function checkVariableDeclarator(node) {
|
|
283
|
+
if (node.id.type !== AST_NODE_TYPES2.ObjectPattern) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
const { properties } = node.id;
|
|
287
|
+
if (properties.length < 2) {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
const propertyInfo = properties.map((prop) => {
|
|
291
|
+
if (prop.type === AST_NODE_TYPES2.RestElement) {
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
return {
|
|
295
|
+
property: prop,
|
|
296
|
+
name: getPropertyName(prop),
|
|
297
|
+
hasDefault: hasDefaultValue(prop),
|
|
298
|
+
defaultType: getDefaultValueType(prop)
|
|
299
|
+
};
|
|
300
|
+
}).filter((info) => info !== null && info.name !== null);
|
|
301
|
+
const sorted = [...propertyInfo].sort((a, b) => {
|
|
302
|
+
if (a.hasDefault && !b.hasDefault) {
|
|
303
|
+
return -1;
|
|
304
|
+
}
|
|
305
|
+
if (!a.hasDefault && b.hasDefault) {
|
|
306
|
+
return 1;
|
|
307
|
+
}
|
|
308
|
+
if (a.hasDefault && b.hasDefault) {
|
|
309
|
+
const typeComparison = getTypeSortOrder(a.defaultType) - getTypeSortOrder(b.defaultType);
|
|
310
|
+
if (typeComparison !== 0) {
|
|
311
|
+
return typeComparison;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return a.name.localeCompare(b.name);
|
|
315
|
+
});
|
|
316
|
+
const isSorted = propertyInfo.every((info, index) => info.name === sorted[index].name);
|
|
317
|
+
if (!isSorted) {
|
|
318
|
+
context.report({
|
|
319
|
+
node: node.id,
|
|
320
|
+
messageId: "unsortedDestructuring"
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return {
|
|
325
|
+
VariableDeclarator: checkVariableDeclarator
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
var enforce_sorted_destructuring_default = enforceSortedDestructuring;
|
|
330
|
+
|
|
210
331
|
// src/rules/file-kebab-case.ts
|
|
211
332
|
import path from "path";
|
|
212
|
-
import { ESLintUtils as
|
|
213
|
-
var
|
|
214
|
-
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.
|
|
333
|
+
import { ESLintUtils as ESLintUtils3 } from "@typescript-eslint/utils";
|
|
334
|
+
var createRule3 = ESLintUtils3.RuleCreator(
|
|
335
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
215
336
|
);
|
|
216
337
|
var isKebabCase = (str) => {
|
|
217
338
|
if (/\.(config|rc|setup|spec|test)$/.test(str) || /^[a-z0-9]+(?:-[a-z0-9]+)*\.[a-z0-9]+(?:-[a-z0-9]+)*$/.test(str)) {
|
|
@@ -219,7 +340,7 @@ var isKebabCase = (str) => {
|
|
|
219
340
|
}
|
|
220
341
|
return /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(str);
|
|
221
342
|
};
|
|
222
|
-
var fileKebabCase =
|
|
343
|
+
var fileKebabCase = createRule3({
|
|
223
344
|
name: "file-kebab-case",
|
|
224
345
|
meta: {
|
|
225
346
|
type: "problem",
|
|
@@ -240,8 +361,8 @@ var fileKebabCase = createRule2({
|
|
|
240
361
|
if (ext !== ".ts" && ext !== ".js") {
|
|
241
362
|
return;
|
|
242
363
|
}
|
|
243
|
-
const
|
|
244
|
-
if (!isKebabCase(
|
|
364
|
+
const basename2 = path.basename(filename, ext);
|
|
365
|
+
if (!isKebabCase(basename2)) {
|
|
245
366
|
context.report({
|
|
246
367
|
loc: { line: 1, column: 0 },
|
|
247
368
|
messageId: "fileKebabCase"
|
|
@@ -255,12 +376,12 @@ var file_kebab_case_default = fileKebabCase;
|
|
|
255
376
|
|
|
256
377
|
// src/rules/jsx-pascal-case.ts
|
|
257
378
|
import path2 from "path";
|
|
258
|
-
import { ESLintUtils as
|
|
259
|
-
var
|
|
260
|
-
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.
|
|
379
|
+
import { ESLintUtils as ESLintUtils4 } from "@typescript-eslint/utils";
|
|
380
|
+
var createRule4 = ESLintUtils4.RuleCreator(
|
|
381
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
261
382
|
);
|
|
262
383
|
var isPascalCase = (str) => /^[A-Z][a-zA-Z0-9]*$/.test(str) && !/^[A-Z]+$/.test(str);
|
|
263
|
-
var jsxPascalCase =
|
|
384
|
+
var jsxPascalCase = createRule4({
|
|
264
385
|
name: "jsx-pascal-case",
|
|
265
386
|
meta: {
|
|
266
387
|
type: "problem",
|
|
@@ -281,8 +402,8 @@ var jsxPascalCase = createRule3({
|
|
|
281
402
|
if (ext !== ".jsx" && ext !== ".tsx") {
|
|
282
403
|
return;
|
|
283
404
|
}
|
|
284
|
-
const
|
|
285
|
-
if (!isPascalCase(
|
|
405
|
+
const basename2 = path2.basename(filename, ext);
|
|
406
|
+
if (!isPascalCase(basename2)) {
|
|
286
407
|
context.report({
|
|
287
408
|
loc: { line: 1, column: 0 },
|
|
288
409
|
messageId: "jsxPascalCase"
|
|
@@ -294,13 +415,84 @@ var jsxPascalCase = createRule3({
|
|
|
294
415
|
});
|
|
295
416
|
var jsx_pascal_case_default = jsxPascalCase;
|
|
296
417
|
|
|
418
|
+
// src/rules/jsx-no-variable-in-callback.ts
|
|
419
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES3, ESLintUtils as ESLintUtils5 } from "@typescript-eslint/utils";
|
|
420
|
+
var createRule5 = ESLintUtils5.RuleCreator(
|
|
421
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
422
|
+
);
|
|
423
|
+
var jsxNoVariableInCallback = createRule5({
|
|
424
|
+
name: "jsx-no-variable-in-callback",
|
|
425
|
+
meta: {
|
|
426
|
+
type: "suggestion",
|
|
427
|
+
docs: {
|
|
428
|
+
description: "Disallow variable declarations inside callback functions within JSX"
|
|
429
|
+
},
|
|
430
|
+
schema: [],
|
|
431
|
+
messages: {
|
|
432
|
+
noVariableInCallback: "Variable declarations should not be inside callback functions within JSX. Extract the logic to a separate function outside the JSX."
|
|
433
|
+
}
|
|
434
|
+
},
|
|
435
|
+
defaultOptions: [],
|
|
436
|
+
create(context) {
|
|
437
|
+
function isInsideJSX(node) {
|
|
438
|
+
let current = node.parent;
|
|
439
|
+
while (current) {
|
|
440
|
+
if (current.type === AST_NODE_TYPES3.JSXElement || current.type === AST_NODE_TYPES3.JSXFragment) {
|
|
441
|
+
return true;
|
|
442
|
+
}
|
|
443
|
+
current = current.parent;
|
|
444
|
+
}
|
|
445
|
+
return false;
|
|
446
|
+
}
|
|
447
|
+
function isCallbackInJSX(node) {
|
|
448
|
+
if (!node.parent) {
|
|
449
|
+
return false;
|
|
450
|
+
}
|
|
451
|
+
if (!isInsideJSX(node)) {
|
|
452
|
+
return false;
|
|
453
|
+
}
|
|
454
|
+
if (node.parent.type === AST_NODE_TYPES3.CallExpression || node.parent.type === AST_NODE_TYPES3.JSXExpressionContainer) {
|
|
455
|
+
return true;
|
|
456
|
+
}
|
|
457
|
+
if (node.parent.type === AST_NODE_TYPES3.ArrayExpression && node.parent.parent) {
|
|
458
|
+
if (node.parent.parent.type === AST_NODE_TYPES3.CallExpression || node.parent.parent.type === AST_NODE_TYPES3.JSXExpressionContainer) {
|
|
459
|
+
return true;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
return false;
|
|
463
|
+
}
|
|
464
|
+
function checkFunctionBody(node) {
|
|
465
|
+
if (!isCallbackInJSX(node)) {
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
const { body } = node;
|
|
469
|
+
if (body.type !== AST_NODE_TYPES3.BlockStatement) {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
body.body.forEach((statement) => {
|
|
473
|
+
if (statement.type === AST_NODE_TYPES3.VariableDeclaration) {
|
|
474
|
+
context.report({
|
|
475
|
+
node: statement,
|
|
476
|
+
messageId: "noVariableInCallback"
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
return {
|
|
482
|
+
ArrowFunctionExpression: checkFunctionBody,
|
|
483
|
+
FunctionExpression: checkFunctionBody
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
var jsx_no_variable_in_callback_default = jsxNoVariableInCallback;
|
|
488
|
+
|
|
297
489
|
// src/rules/md-filename-case-restriction.ts
|
|
298
490
|
import path3 from "path";
|
|
299
|
-
import { ESLintUtils as
|
|
300
|
-
var
|
|
301
|
-
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.
|
|
491
|
+
import { ESLintUtils as ESLintUtils6 } from "@typescript-eslint/utils";
|
|
492
|
+
var createRule6 = ESLintUtils6.RuleCreator(
|
|
493
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
302
494
|
);
|
|
303
|
-
var mdFilenameCaseRestriction =
|
|
495
|
+
var mdFilenameCaseRestriction = createRule6({
|
|
304
496
|
name: "md-filename-case-restriction",
|
|
305
497
|
meta: {
|
|
306
498
|
type: "problem",
|
|
@@ -320,18 +512,18 @@ var mdFilenameCaseRestriction = createRule4({
|
|
|
320
512
|
if (!filename.endsWith(".md")) {
|
|
321
513
|
return;
|
|
322
514
|
}
|
|
323
|
-
const
|
|
515
|
+
const basename2 = path3.basename(filename, ".md");
|
|
324
516
|
function isSnakeCase(text) {
|
|
325
517
|
return /^[A-Z][A-Z0-9_]*$/.test(text);
|
|
326
518
|
}
|
|
327
519
|
function isValidCase(text) {
|
|
328
520
|
return isSnakeCase(text);
|
|
329
521
|
}
|
|
330
|
-
if (!isValidCase(
|
|
522
|
+
if (!isValidCase(basename2)) {
|
|
331
523
|
context.report({
|
|
332
524
|
node: context.sourceCode.ast,
|
|
333
525
|
messageId: "invalidFilenameCase",
|
|
334
|
-
data: { filename:
|
|
526
|
+
data: { filename: basename2 }
|
|
335
527
|
});
|
|
336
528
|
}
|
|
337
529
|
}
|
|
@@ -341,11 +533,11 @@ var mdFilenameCaseRestriction = createRule4({
|
|
|
341
533
|
var md_filename_case_restriction_default = mdFilenameCaseRestriction;
|
|
342
534
|
|
|
343
535
|
// src/rules/no-complex-inline-return.ts
|
|
344
|
-
import { ESLintUtils as
|
|
345
|
-
var
|
|
346
|
-
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.
|
|
536
|
+
import { ESLintUtils as ESLintUtils7, AST_NODE_TYPES as AST_NODE_TYPES4 } from "@typescript-eslint/utils";
|
|
537
|
+
var createRule7 = ESLintUtils7.RuleCreator(
|
|
538
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
347
539
|
);
|
|
348
|
-
var noComplexInlineReturn =
|
|
540
|
+
var noComplexInlineReturn = createRule7({
|
|
349
541
|
name: "no-complex-inline-return",
|
|
350
542
|
meta: {
|
|
351
543
|
type: "suggestion",
|
|
@@ -361,13 +553,13 @@ var noComplexInlineReturn = createRule5({
|
|
|
361
553
|
create(context) {
|
|
362
554
|
const isComplexExpression = (node) => {
|
|
363
555
|
if (!node) return false;
|
|
364
|
-
if (node.type ===
|
|
556
|
+
if (node.type === AST_NODE_TYPES4.ConditionalExpression) {
|
|
365
557
|
return true;
|
|
366
558
|
}
|
|
367
|
-
if (node.type ===
|
|
559
|
+
if (node.type === AST_NODE_TYPES4.LogicalExpression) {
|
|
368
560
|
return true;
|
|
369
561
|
}
|
|
370
|
-
if (node.type ===
|
|
562
|
+
if (node.type === AST_NODE_TYPES4.NewExpression) {
|
|
371
563
|
return true;
|
|
372
564
|
}
|
|
373
565
|
return false;
|
|
@@ -388,11 +580,11 @@ var no_complex_inline_return_default = noComplexInlineReturn;
|
|
|
388
580
|
|
|
389
581
|
// src/rules/no-emoji.ts
|
|
390
582
|
import emojiRegex from "emoji-regex";
|
|
391
|
-
import { ESLintUtils as
|
|
392
|
-
var
|
|
393
|
-
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.
|
|
583
|
+
import { ESLintUtils as ESLintUtils8 } from "@typescript-eslint/utils";
|
|
584
|
+
var createRule8 = ESLintUtils8.RuleCreator(
|
|
585
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
394
586
|
);
|
|
395
|
-
var noEmoji =
|
|
587
|
+
var noEmoji = createRule8({
|
|
396
588
|
name: "no-emoji",
|
|
397
589
|
meta: {
|
|
398
590
|
type: "problem",
|
|
@@ -426,11 +618,11 @@ var noEmoji = createRule6({
|
|
|
426
618
|
var no_emoji_default = noEmoji;
|
|
427
619
|
|
|
428
620
|
// src/rules/no-env-fallback.ts
|
|
429
|
-
import { ESLintUtils as
|
|
430
|
-
var
|
|
431
|
-
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.
|
|
621
|
+
import { ESLintUtils as ESLintUtils9, AST_NODE_TYPES as AST_NODE_TYPES5 } from "@typescript-eslint/utils";
|
|
622
|
+
var createRule9 = ESLintUtils9.RuleCreator(
|
|
623
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
432
624
|
);
|
|
433
|
-
var noEnvFallback =
|
|
625
|
+
var noEnvFallback = createRule9({
|
|
434
626
|
name: "no-env-fallback",
|
|
435
627
|
meta: {
|
|
436
628
|
type: "problem",
|
|
@@ -445,16 +637,16 @@ var noEnvFallback = createRule7({
|
|
|
445
637
|
defaultOptions: [],
|
|
446
638
|
create(context) {
|
|
447
639
|
const isProcessEnvAccess = (node) => {
|
|
448
|
-
if (node.type !==
|
|
640
|
+
if (node.type !== AST_NODE_TYPES5.MemberExpression) {
|
|
449
641
|
return false;
|
|
450
642
|
}
|
|
451
643
|
const { object } = node;
|
|
452
|
-
if (object.type !==
|
|
644
|
+
if (object.type !== AST_NODE_TYPES5.MemberExpression) {
|
|
453
645
|
return false;
|
|
454
646
|
}
|
|
455
647
|
const processNode = object.object;
|
|
456
648
|
const envNode = object.property;
|
|
457
|
-
return processNode.type ===
|
|
649
|
+
return processNode.type === AST_NODE_TYPES5.Identifier && processNode.name === "process" && envNode.type === AST_NODE_TYPES5.Identifier && envNode.name === "env";
|
|
458
650
|
};
|
|
459
651
|
return {
|
|
460
652
|
LogicalExpression(node) {
|
|
@@ -479,11 +671,11 @@ var noEnvFallback = createRule7({
|
|
|
479
671
|
var no_env_fallback_default = noEnvFallback;
|
|
480
672
|
|
|
481
673
|
// src/rules/no-explicit-return-type.ts
|
|
482
|
-
import { ESLintUtils as
|
|
483
|
-
var
|
|
484
|
-
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.
|
|
674
|
+
import { ESLintUtils as ESLintUtils10 } from "@typescript-eslint/utils";
|
|
675
|
+
var createRule10 = ESLintUtils10.RuleCreator(
|
|
676
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
485
677
|
);
|
|
486
|
-
var noExplicitReturnType =
|
|
678
|
+
var noExplicitReturnType = createRule10({
|
|
487
679
|
name: "no-explicit-return-type",
|
|
488
680
|
meta: {
|
|
489
681
|
type: "suggestion",
|
|
@@ -522,12 +714,97 @@ var noExplicitReturnType = createRule8({
|
|
|
522
714
|
});
|
|
523
715
|
var no_explicit_return_type_default = noExplicitReturnType;
|
|
524
716
|
|
|
717
|
+
// src/rules/jsx-no-non-component-function.ts
|
|
718
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES7, ESLintUtils as ESLintUtils11 } from "@typescript-eslint/utils";
|
|
719
|
+
|
|
720
|
+
// src/utils.ts
|
|
721
|
+
import { basename, extname } from "path";
|
|
722
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES6 } from "@typescript-eslint/utils";
|
|
723
|
+
var getFileExtension = (filename) => extname(filename).slice(1);
|
|
724
|
+
|
|
725
|
+
// src/rules/jsx-no-non-component-function.ts
|
|
726
|
+
var createRule11 = ESLintUtils11.RuleCreator(
|
|
727
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
728
|
+
);
|
|
729
|
+
var jsxNoNonComponentFunction = createRule11({
|
|
730
|
+
name: "jsx-no-non-component-function",
|
|
731
|
+
meta: {
|
|
732
|
+
type: "problem",
|
|
733
|
+
docs: {
|
|
734
|
+
description: "Disallow non-component functions defined at top level in .tsx and .jsx files"
|
|
735
|
+
},
|
|
736
|
+
schema: [],
|
|
737
|
+
messages: {
|
|
738
|
+
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."
|
|
739
|
+
}
|
|
740
|
+
},
|
|
741
|
+
defaultOptions: [],
|
|
742
|
+
create(context) {
|
|
743
|
+
const { filename } = context;
|
|
744
|
+
const extension = getFileExtension(filename);
|
|
745
|
+
if (extension !== "tsx" && extension !== "jsx") {
|
|
746
|
+
return {};
|
|
747
|
+
}
|
|
748
|
+
function isReactComponent(node) {
|
|
749
|
+
const functionName = node.type === AST_NODE_TYPES7.FunctionDeclaration && node.id ? node.id.name : null;
|
|
750
|
+
if (functionName && /^[A-Z]/.test(functionName)) {
|
|
751
|
+
return true;
|
|
752
|
+
}
|
|
753
|
+
if (node.returnType?.typeAnnotation) {
|
|
754
|
+
const returnTypeNode = node.returnType.typeAnnotation;
|
|
755
|
+
if (returnTypeNode.type === AST_NODE_TYPES7.TSTypeReference && returnTypeNode.typeName.type === AST_NODE_TYPES7.Identifier) {
|
|
756
|
+
const typeName = returnTypeNode.typeName.name;
|
|
757
|
+
if (typeName === "JSX" || typeName === "ReactElement" || typeName === "ReactNode") {
|
|
758
|
+
return true;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
return false;
|
|
763
|
+
}
|
|
764
|
+
function checkTopLevelFunction(node, declaratorNode) {
|
|
765
|
+
if (isReactComponent(node)) {
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
const { parent } = node;
|
|
769
|
+
if (!parent) {
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
if (parent.type === AST_NODE_TYPES7.ExportDefaultDeclaration || parent.type === AST_NODE_TYPES7.ExportNamedDeclaration) {
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
if (declaratorNode?.parent?.parent?.type === AST_NODE_TYPES7.ExportNamedDeclaration) {
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
if (declaratorNode?.id.type === AST_NODE_TYPES7.Identifier) {
|
|
779
|
+
const varName = declaratorNode.id.name;
|
|
780
|
+
if (/^[A-Z]/.test(varName)) {
|
|
781
|
+
return;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
context.report({
|
|
785
|
+
node: declaratorNode || node,
|
|
786
|
+
messageId: "noTopLevelFunction"
|
|
787
|
+
});
|
|
788
|
+
}
|
|
789
|
+
return {
|
|
790
|
+
"Program > VariableDeclaration > VariableDeclarator > ArrowFunctionExpression": function checkArrowFunction(node) {
|
|
791
|
+
const declarator = node.parent;
|
|
792
|
+
checkTopLevelFunction(node, declarator);
|
|
793
|
+
},
|
|
794
|
+
"Program > FunctionDeclaration": function checkFunctionDeclaration(node) {
|
|
795
|
+
checkTopLevelFunction(node);
|
|
796
|
+
}
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
});
|
|
800
|
+
var jsx_no_non_component_function_default = jsxNoNonComponentFunction;
|
|
801
|
+
|
|
525
802
|
// src/rules/no-logic-in-params.ts
|
|
526
|
-
import { ESLintUtils as
|
|
527
|
-
var
|
|
528
|
-
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.
|
|
803
|
+
import { ESLintUtils as ESLintUtils12, AST_NODE_TYPES as AST_NODE_TYPES8 } from "@typescript-eslint/utils";
|
|
804
|
+
var createRule12 = ESLintUtils12.RuleCreator(
|
|
805
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
529
806
|
);
|
|
530
|
-
var noLogicInParams =
|
|
807
|
+
var noLogicInParams = createRule12({
|
|
531
808
|
name: "no-logic-in-params",
|
|
532
809
|
meta: {
|
|
533
810
|
type: "suggestion",
|
|
@@ -542,20 +819,20 @@ var noLogicInParams = createRule9({
|
|
|
542
819
|
defaultOptions: [],
|
|
543
820
|
create(context) {
|
|
544
821
|
const isComplexExpression = (node) => {
|
|
545
|
-
if (node.type ===
|
|
822
|
+
if (node.type === AST_NODE_TYPES8.SpreadElement) {
|
|
546
823
|
return false;
|
|
547
824
|
}
|
|
548
|
-
if (node.type ===
|
|
825
|
+
if (node.type === AST_NODE_TYPES8.ConditionalExpression) {
|
|
549
826
|
return true;
|
|
550
827
|
}
|
|
551
|
-
if (node.type ===
|
|
828
|
+
if (node.type === AST_NODE_TYPES8.LogicalExpression) {
|
|
552
829
|
return true;
|
|
553
830
|
}
|
|
554
|
-
if (node.type ===
|
|
831
|
+
if (node.type === AST_NODE_TYPES8.BinaryExpression) {
|
|
555
832
|
const logicalOperators = ["==", "===", "!=", "!==", "<", ">", "<=", ">=", "in", "instanceof"];
|
|
556
833
|
return logicalOperators.includes(node.operator);
|
|
557
834
|
}
|
|
558
|
-
if (node.type ===
|
|
835
|
+
if (node.type === AST_NODE_TYPES8.UnaryExpression) {
|
|
559
836
|
return node.operator === "!";
|
|
560
837
|
}
|
|
561
838
|
return false;
|
|
@@ -587,11 +864,11 @@ var noLogicInParams = createRule9({
|
|
|
587
864
|
var no_logic_in_params_default = noLogicInParams;
|
|
588
865
|
|
|
589
866
|
// src/rules/prefer-destructuring-params.ts
|
|
590
|
-
import { AST_NODE_TYPES as
|
|
591
|
-
var
|
|
592
|
-
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.
|
|
867
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES9, ESLintUtils as ESLintUtils13 } from "@typescript-eslint/utils";
|
|
868
|
+
var createRule13 = ESLintUtils13.RuleCreator(
|
|
869
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
593
870
|
);
|
|
594
|
-
var preferDestructuringParams =
|
|
871
|
+
var preferDestructuringParams = createRule13({
|
|
595
872
|
name: "prefer-destructuring-params",
|
|
596
873
|
meta: {
|
|
597
874
|
type: "suggestion",
|
|
@@ -607,18 +884,18 @@ var preferDestructuringParams = createRule10({
|
|
|
607
884
|
create(context) {
|
|
608
885
|
const isCallbackFunction = (node) => {
|
|
609
886
|
const { parent } = node;
|
|
610
|
-
return parent?.type ===
|
|
887
|
+
return parent?.type === AST_NODE_TYPES9.CallExpression;
|
|
611
888
|
};
|
|
612
889
|
const isDeveloperFunction = (node) => {
|
|
613
|
-
if (node.type ===
|
|
890
|
+
if (node.type === AST_NODE_TYPES9.FunctionDeclaration) {
|
|
614
891
|
return true;
|
|
615
892
|
}
|
|
616
|
-
if (node.type ===
|
|
893
|
+
if (node.type === AST_NODE_TYPES9.FunctionExpression || node.type === AST_NODE_TYPES9.ArrowFunctionExpression) {
|
|
617
894
|
if (isCallbackFunction(node)) {
|
|
618
895
|
return false;
|
|
619
896
|
}
|
|
620
897
|
const { parent } = node;
|
|
621
|
-
return parent?.type ===
|
|
898
|
+
return parent?.type === AST_NODE_TYPES9.VariableDeclarator || parent?.type === AST_NODE_TYPES9.AssignmentExpression || parent?.type === AST_NODE_TYPES9.Property || parent?.type === AST_NODE_TYPES9.MethodDefinition;
|
|
622
899
|
}
|
|
623
900
|
return false;
|
|
624
901
|
};
|
|
@@ -630,7 +907,7 @@ var preferDestructuringParams = createRule10({
|
|
|
630
907
|
if (!isDeveloperFunction(node)) {
|
|
631
908
|
return;
|
|
632
909
|
}
|
|
633
|
-
if (node.type ===
|
|
910
|
+
if (node.type === AST_NODE_TYPES9.FunctionDeclaration && node.id) {
|
|
634
911
|
const functionName = node.id.name;
|
|
635
912
|
if (functionName.startsWith("_") || functionName.includes("$") || /^[A-Z][a-zA-Z]*$/.test(functionName)) {
|
|
636
913
|
return;
|
|
@@ -640,7 +917,7 @@ var preferDestructuringParams = createRule10({
|
|
|
640
917
|
return;
|
|
641
918
|
}
|
|
642
919
|
const hasNonDestructuredParams = node.params.some(
|
|
643
|
-
(param) => param.type !==
|
|
920
|
+
(param) => param.type !== AST_NODE_TYPES9.ObjectPattern && param.type !== AST_NODE_TYPES9.RestElement
|
|
644
921
|
);
|
|
645
922
|
if (hasNonDestructuredParams) {
|
|
646
923
|
context.report({
|
|
@@ -659,11 +936,11 @@ var preferDestructuringParams = createRule10({
|
|
|
659
936
|
var prefer_destructuring_params_default = preferDestructuringParams;
|
|
660
937
|
|
|
661
938
|
// src/rules/prefer-import-type.ts
|
|
662
|
-
import { AST_NODE_TYPES as
|
|
663
|
-
var
|
|
664
|
-
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.
|
|
939
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES10, ESLintUtils as ESLintUtils14 } from "@typescript-eslint/utils";
|
|
940
|
+
var createRule14 = ESLintUtils14.RuleCreator(
|
|
941
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
665
942
|
);
|
|
666
|
-
var preferImportType =
|
|
943
|
+
var preferImportType = createRule14({
|
|
667
944
|
name: "prefer-import-type",
|
|
668
945
|
meta: {
|
|
669
946
|
type: "suggestion",
|
|
@@ -678,6 +955,81 @@ var preferImportType = createRule11({
|
|
|
678
955
|
},
|
|
679
956
|
defaultOptions: [],
|
|
680
957
|
create(context) {
|
|
958
|
+
function isInTypeContext(node) {
|
|
959
|
+
let current = node;
|
|
960
|
+
while (current) {
|
|
961
|
+
switch (current.type) {
|
|
962
|
+
case AST_NODE_TYPES10.TSTypeReference:
|
|
963
|
+
case AST_NODE_TYPES10.TSTypeAnnotation:
|
|
964
|
+
case AST_NODE_TYPES10.TSTypeParameterInstantiation:
|
|
965
|
+
case AST_NODE_TYPES10.TSInterfaceHeritage:
|
|
966
|
+
case AST_NODE_TYPES10.TSClassImplements:
|
|
967
|
+
case AST_NODE_TYPES10.TSTypeQuery:
|
|
968
|
+
case AST_NODE_TYPES10.TSTypeAssertion:
|
|
969
|
+
case AST_NODE_TYPES10.TSAsExpression:
|
|
970
|
+
case AST_NODE_TYPES10.TSSatisfiesExpression:
|
|
971
|
+
case AST_NODE_TYPES10.TSTypeAliasDeclaration:
|
|
972
|
+
case AST_NODE_TYPES10.TSInterfaceDeclaration:
|
|
973
|
+
case AST_NODE_TYPES10.TSTypeParameter:
|
|
974
|
+
case AST_NODE_TYPES10.TSQualifiedName:
|
|
975
|
+
return true;
|
|
976
|
+
case AST_NODE_TYPES10.MemberExpression:
|
|
977
|
+
case AST_NODE_TYPES10.Identifier:
|
|
978
|
+
current = current.parent;
|
|
979
|
+
break;
|
|
980
|
+
default:
|
|
981
|
+
return false;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
return false;
|
|
985
|
+
}
|
|
986
|
+
function isUsedAsValue(localName, scope) {
|
|
987
|
+
const variable = scope.set.get(localName);
|
|
988
|
+
if (!variable) {
|
|
989
|
+
return false;
|
|
990
|
+
}
|
|
991
|
+
if (variable.references.length === 0) {
|
|
992
|
+
return false;
|
|
993
|
+
}
|
|
994
|
+
return variable.references.some((ref) => {
|
|
995
|
+
if (ref.isWrite()) {
|
|
996
|
+
return false;
|
|
997
|
+
}
|
|
998
|
+
const { identifier } = ref;
|
|
999
|
+
const { parent } = identifier;
|
|
1000
|
+
if (!parent) {
|
|
1001
|
+
return false;
|
|
1002
|
+
}
|
|
1003
|
+
if (isInTypeContext(parent)) {
|
|
1004
|
+
return false;
|
|
1005
|
+
}
|
|
1006
|
+
switch (parent.type) {
|
|
1007
|
+
case AST_NODE_TYPES10.CallExpression:
|
|
1008
|
+
case AST_NODE_TYPES10.NewExpression:
|
|
1009
|
+
case AST_NODE_TYPES10.JSXOpeningElement:
|
|
1010
|
+
case AST_NODE_TYPES10.JSXClosingElement:
|
|
1011
|
+
case AST_NODE_TYPES10.MemberExpression:
|
|
1012
|
+
case AST_NODE_TYPES10.VariableDeclarator:
|
|
1013
|
+
case AST_NODE_TYPES10.TaggedTemplateExpression:
|
|
1014
|
+
case AST_NODE_TYPES10.SpreadElement:
|
|
1015
|
+
case AST_NODE_TYPES10.ExportSpecifier:
|
|
1016
|
+
case AST_NODE_TYPES10.ArrayExpression:
|
|
1017
|
+
case AST_NODE_TYPES10.ObjectExpression:
|
|
1018
|
+
case AST_NODE_TYPES10.BinaryExpression:
|
|
1019
|
+
case AST_NODE_TYPES10.LogicalExpression:
|
|
1020
|
+
case AST_NODE_TYPES10.UnaryExpression:
|
|
1021
|
+
case AST_NODE_TYPES10.ReturnStatement:
|
|
1022
|
+
case AST_NODE_TYPES10.ArrowFunctionExpression:
|
|
1023
|
+
case AST_NODE_TYPES10.ConditionalExpression:
|
|
1024
|
+
case AST_NODE_TYPES10.AwaitExpression:
|
|
1025
|
+
case AST_NODE_TYPES10.YieldExpression:
|
|
1026
|
+
case AST_NODE_TYPES10.Property:
|
|
1027
|
+
return true;
|
|
1028
|
+
default:
|
|
1029
|
+
return false;
|
|
1030
|
+
}
|
|
1031
|
+
});
|
|
1032
|
+
}
|
|
681
1033
|
function checkImportDeclaration(node) {
|
|
682
1034
|
if (node.importKind === "type") {
|
|
683
1035
|
return;
|
|
@@ -693,19 +1045,17 @@ var preferImportType = createRule11({
|
|
|
693
1045
|
if (isRuntimeImport) {
|
|
694
1046
|
return;
|
|
695
1047
|
}
|
|
1048
|
+
const scope = context.sourceCode.getScope(node);
|
|
696
1049
|
const isTypeOnlyImport = node.specifiers.every((specifier) => {
|
|
697
|
-
if (specifier.type ===
|
|
1050
|
+
if (specifier.type === AST_NODE_TYPES10.ImportDefaultSpecifier) {
|
|
698
1051
|
return false;
|
|
699
1052
|
}
|
|
700
|
-
if (specifier.type ===
|
|
1053
|
+
if (specifier.type === AST_NODE_TYPES10.ImportNamespaceSpecifier) {
|
|
701
1054
|
return false;
|
|
702
1055
|
}
|
|
703
|
-
if (specifier.type ===
|
|
704
|
-
const
|
|
705
|
-
|
|
706
|
-
importedName
|
|
707
|
-
) || importedName.endsWith("Type") || importedName.endsWith("Interface") || importedName.endsWith("Props");
|
|
708
|
-
return isKnownTypeOnly;
|
|
1056
|
+
if (specifier.type === AST_NODE_TYPES10.ImportSpecifier) {
|
|
1057
|
+
const localName = specifier.local.name;
|
|
1058
|
+
return !isUsedAsValue(localName, scope);
|
|
709
1059
|
}
|
|
710
1060
|
return false;
|
|
711
1061
|
});
|
|
@@ -729,11 +1079,11 @@ var preferImportType = createRule11({
|
|
|
729
1079
|
var prefer_import_type_default = preferImportType;
|
|
730
1080
|
|
|
731
1081
|
// src/rules/prefer-interface-over-inline-types.ts
|
|
732
|
-
import { AST_NODE_TYPES as
|
|
733
|
-
var
|
|
734
|
-
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.
|
|
1082
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES11, ESLintUtils as ESLintUtils15 } from "@typescript-eslint/utils";
|
|
1083
|
+
var createRule15 = ESLintUtils15.RuleCreator(
|
|
1084
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
735
1085
|
);
|
|
736
|
-
var preferInterfaceOverInlineTypes =
|
|
1086
|
+
var preferInterfaceOverInlineTypes = createRule15({
|
|
737
1087
|
name: "prefer-interface-over-inline-types",
|
|
738
1088
|
meta: {
|
|
739
1089
|
type: "suggestion",
|
|
@@ -749,54 +1099,54 @@ var preferInterfaceOverInlineTypes = createRule12({
|
|
|
749
1099
|
defaultOptions: [],
|
|
750
1100
|
create(context) {
|
|
751
1101
|
function hasJSXInConditional(node) {
|
|
752
|
-
return node.consequent.type ===
|
|
1102
|
+
return node.consequent.type === AST_NODE_TYPES11.JSXElement || node.consequent.type === AST_NODE_TYPES11.JSXFragment || node.alternate.type === AST_NODE_TYPES11.JSXElement || node.alternate.type === AST_NODE_TYPES11.JSXFragment;
|
|
753
1103
|
}
|
|
754
1104
|
function hasJSXInLogical(node) {
|
|
755
|
-
return node.right.type ===
|
|
1105
|
+
return node.right.type === AST_NODE_TYPES11.JSXElement || node.right.type === AST_NODE_TYPES11.JSXFragment;
|
|
756
1106
|
}
|
|
757
1107
|
function hasJSXReturn(block) {
|
|
758
1108
|
return block.body.some((stmt) => {
|
|
759
|
-
if (stmt.type ===
|
|
760
|
-
return stmt.argument.type ===
|
|
1109
|
+
if (stmt.type === AST_NODE_TYPES11.ReturnStatement && stmt.argument) {
|
|
1110
|
+
return stmt.argument.type === AST_NODE_TYPES11.JSXElement || stmt.argument.type === AST_NODE_TYPES11.JSXFragment || stmt.argument.type === AST_NODE_TYPES11.ConditionalExpression && hasJSXInConditional(stmt.argument) || stmt.argument.type === AST_NODE_TYPES11.LogicalExpression && hasJSXInLogical(stmt.argument);
|
|
761
1111
|
}
|
|
762
1112
|
return false;
|
|
763
1113
|
});
|
|
764
1114
|
}
|
|
765
1115
|
function isReactComponent(node) {
|
|
766
|
-
if (node.type ===
|
|
767
|
-
if (node.body.type ===
|
|
1116
|
+
if (node.type === AST_NODE_TYPES11.ArrowFunctionExpression) {
|
|
1117
|
+
if (node.body.type === AST_NODE_TYPES11.JSXElement || node.body.type === AST_NODE_TYPES11.JSXFragment) {
|
|
768
1118
|
return true;
|
|
769
1119
|
}
|
|
770
|
-
if (node.body.type ===
|
|
1120
|
+
if (node.body.type === AST_NODE_TYPES11.BlockStatement) {
|
|
771
1121
|
return hasJSXReturn(node.body);
|
|
772
1122
|
}
|
|
773
|
-
} else if (node.type ===
|
|
774
|
-
if (node.body && node.body.type ===
|
|
1123
|
+
} else if (node.type === AST_NODE_TYPES11.FunctionExpression || node.type === AST_NODE_TYPES11.FunctionDeclaration) {
|
|
1124
|
+
if (node.body && node.body.type === AST_NODE_TYPES11.BlockStatement) {
|
|
775
1125
|
return hasJSXReturn(node.body);
|
|
776
1126
|
}
|
|
777
1127
|
}
|
|
778
1128
|
return false;
|
|
779
1129
|
}
|
|
780
1130
|
function isInlineTypeAnnotation(node) {
|
|
781
|
-
if (node.type ===
|
|
1131
|
+
if (node.type === AST_NODE_TYPES11.TSTypeLiteral) {
|
|
782
1132
|
return true;
|
|
783
1133
|
}
|
|
784
|
-
if (node.type ===
|
|
785
|
-
return node.typeArguments.params.some((param) => param.type ===
|
|
1134
|
+
if (node.type === AST_NODE_TYPES11.TSTypeReference && node.typeArguments) {
|
|
1135
|
+
return node.typeArguments.params.some((param) => param.type === AST_NODE_TYPES11.TSTypeLiteral);
|
|
786
1136
|
}
|
|
787
|
-
if (node.type ===
|
|
1137
|
+
if (node.type === AST_NODE_TYPES11.TSUnionType) {
|
|
788
1138
|
return node.types.some((type) => isInlineTypeAnnotation(type));
|
|
789
1139
|
}
|
|
790
1140
|
return false;
|
|
791
1141
|
}
|
|
792
1142
|
function hasInlineObjectType(node) {
|
|
793
|
-
if (node.type ===
|
|
1143
|
+
if (node.type === AST_NODE_TYPES11.TSTypeLiteral) {
|
|
794
1144
|
return true;
|
|
795
1145
|
}
|
|
796
|
-
if (node.type ===
|
|
797
|
-
return node.typeArguments.params.some((param) => param.type ===
|
|
1146
|
+
if (node.type === AST_NODE_TYPES11.TSTypeReference && node.typeArguments) {
|
|
1147
|
+
return node.typeArguments.params.some((param) => param.type === AST_NODE_TYPES11.TSTypeLiteral);
|
|
798
1148
|
}
|
|
799
|
-
if (node.type ===
|
|
1149
|
+
if (node.type === AST_NODE_TYPES11.TSUnionType) {
|
|
800
1150
|
return node.types.some((type) => hasInlineObjectType(type));
|
|
801
1151
|
}
|
|
802
1152
|
return false;
|
|
@@ -809,7 +1159,7 @@ var preferInterfaceOverInlineTypes = createRule12({
|
|
|
809
1159
|
return;
|
|
810
1160
|
}
|
|
811
1161
|
const param = node.params[0];
|
|
812
|
-
if (param.type ===
|
|
1162
|
+
if (param.type === AST_NODE_TYPES11.Identifier && param.typeAnnotation) {
|
|
813
1163
|
const { typeAnnotation } = param.typeAnnotation;
|
|
814
1164
|
if (isInlineTypeAnnotation(typeAnnotation) && hasInlineObjectType(typeAnnotation)) {
|
|
815
1165
|
context.report({
|
|
@@ -828,12 +1178,100 @@ var preferInterfaceOverInlineTypes = createRule12({
|
|
|
828
1178
|
});
|
|
829
1179
|
var prefer_interface_over_inline_types_default = preferInterfaceOverInlineTypes;
|
|
830
1180
|
|
|
1181
|
+
// src/rules/prefer-jsx-template-literals.ts
|
|
1182
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES12, ESLintUtils as ESLintUtils16 } from "@typescript-eslint/utils";
|
|
1183
|
+
var createRule16 = ESLintUtils16.RuleCreator(
|
|
1184
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
1185
|
+
);
|
|
1186
|
+
var preferJSXTemplateLiterals = createRule16({
|
|
1187
|
+
name: "prefer-jsx-template-literals",
|
|
1188
|
+
meta: {
|
|
1189
|
+
type: "suggestion",
|
|
1190
|
+
docs: {
|
|
1191
|
+
description: "Enforce using template literals instead of mixing text and JSX expressions"
|
|
1192
|
+
},
|
|
1193
|
+
fixable: "code",
|
|
1194
|
+
schema: [],
|
|
1195
|
+
messages: {
|
|
1196
|
+
preferTemplate: "Use template literal instead of mixing text with JSX expressions"
|
|
1197
|
+
}
|
|
1198
|
+
},
|
|
1199
|
+
defaultOptions: [],
|
|
1200
|
+
create(context) {
|
|
1201
|
+
function handleTextBeforeExpression(textNode, exprNode) {
|
|
1202
|
+
const textValue = textNode.value;
|
|
1203
|
+
const trimmedText = textValue.trim();
|
|
1204
|
+
if (!trimmedText) {
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1207
|
+
const hasTextContent = trimmedText.length > 0 && textValue !== trimmedText;
|
|
1208
|
+
const hasNoTrailingSpace = trimmedText.length > 0 && /\S$/.test(textValue);
|
|
1209
|
+
if (!hasTextContent && !hasNoTrailingSpace) {
|
|
1210
|
+
return;
|
|
1211
|
+
}
|
|
1212
|
+
context.report({
|
|
1213
|
+
node: textNode,
|
|
1214
|
+
messageId: "preferTemplate",
|
|
1215
|
+
fix(fixer) {
|
|
1216
|
+
const textPart = textValue.trimEnd();
|
|
1217
|
+
const exprText = context.sourceCode.getText(exprNode.expression);
|
|
1218
|
+
const templateLiteral = `{\`${textPart}\${${exprText}}\`}`;
|
|
1219
|
+
return [fixer.replaceText(textNode, templateLiteral), fixer.remove(exprNode)];
|
|
1220
|
+
}
|
|
1221
|
+
});
|
|
1222
|
+
}
|
|
1223
|
+
function handleExpressionBeforeText(exprNode, textNode) {
|
|
1224
|
+
const textValue = textNode.value;
|
|
1225
|
+
const trimmedText = textValue.trim();
|
|
1226
|
+
if (!trimmedText) {
|
|
1227
|
+
return;
|
|
1228
|
+
}
|
|
1229
|
+
const startsWithNonWhitespace = /^\S/.test(trimmedText);
|
|
1230
|
+
if (!startsWithNonWhitespace) {
|
|
1231
|
+
return;
|
|
1232
|
+
}
|
|
1233
|
+
context.report({
|
|
1234
|
+
node: textNode,
|
|
1235
|
+
messageId: "preferTemplate",
|
|
1236
|
+
fix(fixer) {
|
|
1237
|
+
const exprText = context.sourceCode.getText(exprNode.expression);
|
|
1238
|
+
const textPart = textValue.trim();
|
|
1239
|
+
const templateLiteral = `{\`\${${exprText}}${textPart}\`}`;
|
|
1240
|
+
return [fixer.replaceText(exprNode, templateLiteral), fixer.remove(textNode)];
|
|
1241
|
+
}
|
|
1242
|
+
});
|
|
1243
|
+
}
|
|
1244
|
+
function checkJSXElement(node) {
|
|
1245
|
+
const { children } = node;
|
|
1246
|
+
if (children.length < 2) {
|
|
1247
|
+
return;
|
|
1248
|
+
}
|
|
1249
|
+
for (let i = 0; i < children.length - 1; i += 1) {
|
|
1250
|
+
const child = children[i];
|
|
1251
|
+
const nextChild = children[i + 1];
|
|
1252
|
+
if (!child || !nextChild) {
|
|
1253
|
+
return;
|
|
1254
|
+
}
|
|
1255
|
+
if (child.type === AST_NODE_TYPES12.JSXText && nextChild.type === AST_NODE_TYPES12.JSXExpressionContainer) {
|
|
1256
|
+
handleTextBeforeExpression(child, nextChild);
|
|
1257
|
+
} else if (child.type === AST_NODE_TYPES12.JSXExpressionContainer && nextChild.type === AST_NODE_TYPES12.JSXText) {
|
|
1258
|
+
handleExpressionBeforeText(child, nextChild);
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
return {
|
|
1263
|
+
JSXElement: checkJSXElement
|
|
1264
|
+
};
|
|
1265
|
+
}
|
|
1266
|
+
});
|
|
1267
|
+
var prefer_jsx_template_literals_default = preferJSXTemplateLiterals;
|
|
1268
|
+
|
|
831
1269
|
// src/rules/prefer-named-param-types.ts
|
|
832
|
-
import { AST_NODE_TYPES as
|
|
833
|
-
var
|
|
834
|
-
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.
|
|
1270
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES13, ESLintUtils as ESLintUtils17 } from "@typescript-eslint/utils";
|
|
1271
|
+
var createRule17 = ESLintUtils17.RuleCreator(
|
|
1272
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
835
1273
|
);
|
|
836
|
-
var preferNamedParamTypes =
|
|
1274
|
+
var preferNamedParamTypes = createRule17({
|
|
837
1275
|
name: "prefer-named-param-types",
|
|
838
1276
|
meta: {
|
|
839
1277
|
type: "suggestion",
|
|
@@ -848,16 +1286,16 @@ var preferNamedParamTypes = createRule13({
|
|
|
848
1286
|
defaultOptions: [],
|
|
849
1287
|
create(context) {
|
|
850
1288
|
function hasInlineObjectType(param) {
|
|
851
|
-
if (param.type ===
|
|
1289
|
+
if (param.type === AST_NODE_TYPES13.AssignmentPattern) {
|
|
852
1290
|
return hasInlineObjectType(param.left);
|
|
853
1291
|
}
|
|
854
|
-
if (param.type ===
|
|
855
|
-
if (param.typeAnnotation?.typeAnnotation.type ===
|
|
1292
|
+
if (param.type === AST_NODE_TYPES13.ObjectPattern) {
|
|
1293
|
+
if (param.typeAnnotation?.typeAnnotation.type === AST_NODE_TYPES13.TSTypeLiteral) {
|
|
856
1294
|
return true;
|
|
857
1295
|
}
|
|
858
1296
|
}
|
|
859
|
-
if (param.type ===
|
|
860
|
-
if (param.typeAnnotation?.typeAnnotation.type ===
|
|
1297
|
+
if (param.type === AST_NODE_TYPES13.Identifier) {
|
|
1298
|
+
if (param.typeAnnotation?.typeAnnotation.type === AST_NODE_TYPES13.TSTypeLiteral) {
|
|
861
1299
|
return true;
|
|
862
1300
|
}
|
|
863
1301
|
}
|
|
@@ -891,11 +1329,11 @@ var preferNamedParamTypes = createRule13({
|
|
|
891
1329
|
var prefer_named_param_types_default = preferNamedParamTypes;
|
|
892
1330
|
|
|
893
1331
|
// src/rules/prefer-react-import-types.ts
|
|
894
|
-
import { AST_NODE_TYPES as
|
|
895
|
-
var
|
|
896
|
-
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.
|
|
1332
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES14, ESLintUtils as ESLintUtils18 } from "@typescript-eslint/utils";
|
|
1333
|
+
var createRule18 = ESLintUtils18.RuleCreator(
|
|
1334
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
897
1335
|
);
|
|
898
|
-
var preferReactImportTypes =
|
|
1336
|
+
var preferReactImportTypes = createRule18({
|
|
899
1337
|
name: "prefer-react-import-types",
|
|
900
1338
|
meta: {
|
|
901
1339
|
type: "suggestion",
|
|
@@ -971,7 +1409,7 @@ var preferReactImportTypes = createRule14({
|
|
|
971
1409
|
]);
|
|
972
1410
|
const allReactExports = /* @__PURE__ */ new Set([...reactTypes, ...reactRuntimeExports]);
|
|
973
1411
|
function checkMemberExpression(node) {
|
|
974
|
-
if (node.object.type ===
|
|
1412
|
+
if (node.object.type === AST_NODE_TYPES14.Identifier && node.object.name === "React" && node.property.type === AST_NODE_TYPES14.Identifier && allReactExports.has(node.property.name)) {
|
|
975
1413
|
const typeName = node.property.name;
|
|
976
1414
|
const isType = reactTypes.has(typeName);
|
|
977
1415
|
const importStatement = isType ? `import type { ${typeName} } from "react"` : `import { ${typeName} } from "react"`;
|
|
@@ -988,7 +1426,7 @@ var preferReactImportTypes = createRule14({
|
|
|
988
1426
|
return {
|
|
989
1427
|
MemberExpression: checkMemberExpression,
|
|
990
1428
|
"TSTypeReference > TSQualifiedName": (node) => {
|
|
991
|
-
if (node.left.type ===
|
|
1429
|
+
if (node.left.type === AST_NODE_TYPES14.Identifier && node.left.name === "React" && node.right.type === AST_NODE_TYPES14.Identifier && allReactExports.has(node.right.name)) {
|
|
992
1430
|
const typeName = node.right.name;
|
|
993
1431
|
const isType = reactTypes.has(typeName);
|
|
994
1432
|
const importStatement = isType ? `import type { ${typeName} } from "react"` : `import { ${typeName} } from "react"`;
|
|
@@ -1008,11 +1446,11 @@ var preferReactImportTypes = createRule14({
|
|
|
1008
1446
|
var prefer_react_import_types_default = preferReactImportTypes;
|
|
1009
1447
|
|
|
1010
1448
|
// src/rules/react-props-destructure.ts
|
|
1011
|
-
import { AST_NODE_TYPES as
|
|
1012
|
-
var
|
|
1013
|
-
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.
|
|
1449
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES15, ESLintUtils as ESLintUtils19 } from "@typescript-eslint/utils";
|
|
1450
|
+
var createRule19 = ESLintUtils19.RuleCreator(
|
|
1451
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
|
|
1014
1452
|
);
|
|
1015
|
-
var reactPropsDestructure =
|
|
1453
|
+
var reactPropsDestructure = createRule19({
|
|
1016
1454
|
name: "react-props-destructure",
|
|
1017
1455
|
meta: {
|
|
1018
1456
|
type: "suggestion",
|
|
@@ -1028,29 +1466,29 @@ var reactPropsDestructure = createRule15({
|
|
|
1028
1466
|
defaultOptions: [],
|
|
1029
1467
|
create(context) {
|
|
1030
1468
|
function hasJSXInConditional(node) {
|
|
1031
|
-
return node.consequent.type ===
|
|
1469
|
+
return node.consequent.type === AST_NODE_TYPES15.JSXElement || node.consequent.type === AST_NODE_TYPES15.JSXFragment || node.alternate.type === AST_NODE_TYPES15.JSXElement || node.alternate.type === AST_NODE_TYPES15.JSXFragment;
|
|
1032
1470
|
}
|
|
1033
1471
|
function hasJSXInLogical(node) {
|
|
1034
|
-
return node.right.type ===
|
|
1472
|
+
return node.right.type === AST_NODE_TYPES15.JSXElement || node.right.type === AST_NODE_TYPES15.JSXFragment;
|
|
1035
1473
|
}
|
|
1036
1474
|
function hasJSXReturn(block) {
|
|
1037
1475
|
return block.body.some((stmt) => {
|
|
1038
|
-
if (stmt.type ===
|
|
1039
|
-
return stmt.argument.type ===
|
|
1476
|
+
if (stmt.type === AST_NODE_TYPES15.ReturnStatement && stmt.argument) {
|
|
1477
|
+
return stmt.argument.type === AST_NODE_TYPES15.JSXElement || stmt.argument.type === AST_NODE_TYPES15.JSXFragment || stmt.argument.type === AST_NODE_TYPES15.ConditionalExpression && hasJSXInConditional(stmt.argument) || stmt.argument.type === AST_NODE_TYPES15.LogicalExpression && hasJSXInLogical(stmt.argument);
|
|
1040
1478
|
}
|
|
1041
1479
|
return false;
|
|
1042
1480
|
});
|
|
1043
1481
|
}
|
|
1044
1482
|
function isReactComponent(node) {
|
|
1045
|
-
if (node.type ===
|
|
1046
|
-
if (node.body.type ===
|
|
1483
|
+
if (node.type === AST_NODE_TYPES15.ArrowFunctionExpression) {
|
|
1484
|
+
if (node.body.type === AST_NODE_TYPES15.JSXElement || node.body.type === AST_NODE_TYPES15.JSXFragment) {
|
|
1047
1485
|
return true;
|
|
1048
1486
|
}
|
|
1049
|
-
if (node.body.type ===
|
|
1487
|
+
if (node.body.type === AST_NODE_TYPES15.BlockStatement) {
|
|
1050
1488
|
return hasJSXReturn(node.body);
|
|
1051
1489
|
}
|
|
1052
|
-
} else if (node.type ===
|
|
1053
|
-
if (node.body && node.body.type ===
|
|
1490
|
+
} else if (node.type === AST_NODE_TYPES15.FunctionExpression || node.type === AST_NODE_TYPES15.FunctionDeclaration) {
|
|
1491
|
+
if (node.body && node.body.type === AST_NODE_TYPES15.BlockStatement) {
|
|
1054
1492
|
return hasJSXReturn(node.body);
|
|
1055
1493
|
}
|
|
1056
1494
|
}
|
|
@@ -1064,9 +1502,9 @@ var reactPropsDestructure = createRule15({
|
|
|
1064
1502
|
return;
|
|
1065
1503
|
}
|
|
1066
1504
|
const param = node.params[0];
|
|
1067
|
-
if (param.type ===
|
|
1068
|
-
const properties = param.properties.filter((prop) => prop.type ===
|
|
1069
|
-
if (prop.key.type ===
|
|
1505
|
+
if (param.type === AST_NODE_TYPES15.ObjectPattern) {
|
|
1506
|
+
const properties = param.properties.filter((prop) => prop.type === AST_NODE_TYPES15.Property).map((prop) => {
|
|
1507
|
+
if (prop.key.type === AST_NODE_TYPES15.Identifier) {
|
|
1070
1508
|
return prop.key.name;
|
|
1071
1509
|
}
|
|
1072
1510
|
return null;
|
|
@@ -1099,8 +1537,11 @@ var meta = {
|
|
|
1099
1537
|
};
|
|
1100
1538
|
var rules = {
|
|
1101
1539
|
"enforce-readonly-component-props": enforce_readonly_component_props_default,
|
|
1540
|
+
"enforce-sorted-destructuring": enforce_sorted_destructuring_default,
|
|
1102
1541
|
"file-kebab-case": file_kebab_case_default,
|
|
1103
1542
|
"jsx-pascal-case": jsx_pascal_case_default,
|
|
1543
|
+
"jsx-no-non-component-function": jsx_no_non_component_function_default,
|
|
1544
|
+
"jsx-no-variable-in-callback": jsx_no_variable_in_callback_default,
|
|
1104
1545
|
"md-filename-case-restriction": md_filename_case_restriction_default,
|
|
1105
1546
|
"no-complex-inline-return": no_complex_inline_return_default,
|
|
1106
1547
|
"no-emoji": no_emoji_default,
|
|
@@ -1110,6 +1551,7 @@ var rules = {
|
|
|
1110
1551
|
"prefer-destructuring-params": prefer_destructuring_params_default,
|
|
1111
1552
|
"prefer-import-type": prefer_import_type_default,
|
|
1112
1553
|
"prefer-interface-over-inline-types": prefer_interface_over_inline_types_default,
|
|
1554
|
+
"prefer-jsx-template-literals": prefer_jsx_template_literals_default,
|
|
1113
1555
|
"prefer-named-param-types": prefer_named_param_types_default,
|
|
1114
1556
|
"prefer-react-import-types": prefer_react_import_types_default,
|
|
1115
1557
|
"react-props-destructure": react_props_destructure_default
|
|
@@ -1120,6 +1562,7 @@ var plugin = {
|
|
|
1120
1562
|
};
|
|
1121
1563
|
var baseRules = {
|
|
1122
1564
|
"nextfriday/no-emoji": "warn",
|
|
1565
|
+
"nextfriday/enforce-sorted-destructuring": "warn",
|
|
1123
1566
|
"nextfriday/file-kebab-case": "warn",
|
|
1124
1567
|
"nextfriday/md-filename-case-restriction": "warn",
|
|
1125
1568
|
"nextfriday/prefer-destructuring-params": "warn",
|
|
@@ -1133,6 +1576,7 @@ var baseRules = {
|
|
|
1133
1576
|
};
|
|
1134
1577
|
var baseRecommendedRules = {
|
|
1135
1578
|
"nextfriday/no-emoji": "error",
|
|
1579
|
+
"nextfriday/enforce-sorted-destructuring": "error",
|
|
1136
1580
|
"nextfriday/file-kebab-case": "error",
|
|
1137
1581
|
"nextfriday/md-filename-case-restriction": "error",
|
|
1138
1582
|
"nextfriday/prefer-destructuring-params": "error",
|
|
@@ -1146,13 +1590,19 @@ var baseRecommendedRules = {
|
|
|
1146
1590
|
};
|
|
1147
1591
|
var jsxRules = {
|
|
1148
1592
|
"nextfriday/jsx-pascal-case": "warn",
|
|
1593
|
+
"nextfriday/jsx-no-non-component-function": "warn",
|
|
1594
|
+
"nextfriday/jsx-no-variable-in-callback": "warn",
|
|
1149
1595
|
"nextfriday/prefer-interface-over-inline-types": "warn",
|
|
1596
|
+
"nextfriday/prefer-jsx-template-literals": "warn",
|
|
1150
1597
|
"nextfriday/react-props-destructure": "warn",
|
|
1151
1598
|
"nextfriday/enforce-readonly-component-props": "warn"
|
|
1152
1599
|
};
|
|
1153
1600
|
var jsxRecommendedRules = {
|
|
1154
1601
|
"nextfriday/jsx-pascal-case": "error",
|
|
1602
|
+
"nextfriday/jsx-no-non-component-function": "error",
|
|
1603
|
+
"nextfriday/jsx-no-variable-in-callback": "error",
|
|
1155
1604
|
"nextfriday/prefer-interface-over-inline-types": "error",
|
|
1605
|
+
"nextfriday/prefer-jsx-template-literals": "error",
|
|
1156
1606
|
"nextfriday/react-props-destructure": "error",
|
|
1157
1607
|
"nextfriday/enforce-readonly-component-props": "error"
|
|
1158
1608
|
};
|