eslint-plugin-nextfriday 1.1.1 → 1.2.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 +6 -0
- package/README.md +4 -0
- package/docs/rules/ENFORCE_READONLY_COMPONENT_PROPS.md +104 -0
- package/lib/index.cjs +165 -70
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +14 -0
- package/lib/index.d.ts +14 -0
- package/lib/index.js +165 -70
- 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.2.0",
|
|
5
5
|
description: "A comprehensive ESLint plugin providing custom rules and configurations for Next Friday development workflows.",
|
|
6
6
|
keywords: [
|
|
7
7
|
"eslint",
|
|
@@ -116,10 +116,102 @@ var package_default = {
|
|
|
116
116
|
}
|
|
117
117
|
};
|
|
118
118
|
|
|
119
|
+
// src/rules/enforce-readonly-component-props.ts
|
|
120
|
+
import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
|
|
121
|
+
var createRule = ESLintUtils.RuleCreator(
|
|
122
|
+
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name}.md`
|
|
123
|
+
);
|
|
124
|
+
var enforceReadonlyComponentProps = createRule({
|
|
125
|
+
name: "enforce-readonly-component-props",
|
|
126
|
+
meta: {
|
|
127
|
+
type: "suggestion",
|
|
128
|
+
docs: {
|
|
129
|
+
description: "Enforce Readonly wrapper for React component props when using named types or interfaces"
|
|
130
|
+
},
|
|
131
|
+
fixable: "code",
|
|
132
|
+
schema: [],
|
|
133
|
+
messages: {
|
|
134
|
+
useReadonly: "Component props should be wrapped with Readonly<> for immutability"
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
defaultOptions: [],
|
|
138
|
+
create(context) {
|
|
139
|
+
function hasJSXInConditional(node) {
|
|
140
|
+
return node.consequent.type === AST_NODE_TYPES.JSXElement || node.consequent.type === AST_NODE_TYPES.JSXFragment || node.alternate.type === AST_NODE_TYPES.JSXElement || node.alternate.type === AST_NODE_TYPES.JSXFragment;
|
|
141
|
+
}
|
|
142
|
+
function hasJSXInLogical(node) {
|
|
143
|
+
return node.right.type === AST_NODE_TYPES.JSXElement || node.right.type === AST_NODE_TYPES.JSXFragment;
|
|
144
|
+
}
|
|
145
|
+
function hasJSXReturn(block) {
|
|
146
|
+
return block.body.some((stmt) => {
|
|
147
|
+
if (stmt.type === AST_NODE_TYPES.ReturnStatement && stmt.argument) {
|
|
148
|
+
return stmt.argument.type === AST_NODE_TYPES.JSXElement || stmt.argument.type === AST_NODE_TYPES.JSXFragment || stmt.argument.type === AST_NODE_TYPES.ConditionalExpression && hasJSXInConditional(stmt.argument) || stmt.argument.type === AST_NODE_TYPES.LogicalExpression && hasJSXInLogical(stmt.argument);
|
|
149
|
+
}
|
|
150
|
+
return false;
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
function isReactComponent(node) {
|
|
154
|
+
if (node.type === AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
155
|
+
if (node.body.type === AST_NODE_TYPES.JSXElement || node.body.type === AST_NODE_TYPES.JSXFragment) {
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
if (node.body.type === AST_NODE_TYPES.BlockStatement) {
|
|
159
|
+
return hasJSXReturn(node.body);
|
|
160
|
+
}
|
|
161
|
+
} else if (node.type === AST_NODE_TYPES.FunctionExpression || node.type === AST_NODE_TYPES.FunctionDeclaration) {
|
|
162
|
+
if (node.body && node.body.type === AST_NODE_TYPES.BlockStatement) {
|
|
163
|
+
return hasJSXReturn(node.body);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
function isNamedType(node) {
|
|
169
|
+
return node.type === AST_NODE_TYPES.TSTypeReference;
|
|
170
|
+
}
|
|
171
|
+
function isAlreadyReadonly(node) {
|
|
172
|
+
if (node.type === AST_NODE_TYPES.TSTypeReference && node.typeName) {
|
|
173
|
+
if (node.typeName.type === AST_NODE_TYPES.Identifier && node.typeName.name === "Readonly") {
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
function checkFunction(node) {
|
|
180
|
+
if (!isReactComponent(node)) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (node.params.length !== 1) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const param = node.params[0];
|
|
187
|
+
if (param.type === AST_NODE_TYPES.Identifier && param.typeAnnotation) {
|
|
188
|
+
const { typeAnnotation } = param.typeAnnotation;
|
|
189
|
+
if (isNamedType(typeAnnotation) && !isAlreadyReadonly(typeAnnotation)) {
|
|
190
|
+
const { sourceCode } = context;
|
|
191
|
+
const typeText = sourceCode.getText(typeAnnotation);
|
|
192
|
+
context.report({
|
|
193
|
+
node: param.typeAnnotation,
|
|
194
|
+
messageId: "useReadonly",
|
|
195
|
+
fix(fixer) {
|
|
196
|
+
return fixer.replaceText(typeAnnotation, `Readonly<${typeText}>`);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return {
|
|
203
|
+
ArrowFunctionExpression: checkFunction,
|
|
204
|
+
FunctionExpression: checkFunction,
|
|
205
|
+
FunctionDeclaration: checkFunction
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
var enforce_readonly_component_props_default = enforceReadonlyComponentProps;
|
|
210
|
+
|
|
119
211
|
// src/rules/file-kebab-case.ts
|
|
120
212
|
import path from "path";
|
|
121
|
-
import { ESLintUtils } from "@typescript-eslint/utils";
|
|
122
|
-
var
|
|
213
|
+
import { ESLintUtils as ESLintUtils2 } from "@typescript-eslint/utils";
|
|
214
|
+
var createRule2 = ESLintUtils2.RuleCreator(
|
|
123
215
|
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name}.md`
|
|
124
216
|
);
|
|
125
217
|
var isKebabCase = (str) => {
|
|
@@ -128,7 +220,7 @@ var isKebabCase = (str) => {
|
|
|
128
220
|
}
|
|
129
221
|
return /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(str);
|
|
130
222
|
};
|
|
131
|
-
var fileKebabCase =
|
|
223
|
+
var fileKebabCase = createRule2({
|
|
132
224
|
name: "file-kebab-case",
|
|
133
225
|
meta: {
|
|
134
226
|
type: "problem",
|
|
@@ -164,12 +256,12 @@ var file_kebab_case_default = fileKebabCase;
|
|
|
164
256
|
|
|
165
257
|
// src/rules/jsx-pascal-case.ts
|
|
166
258
|
import path2 from "path";
|
|
167
|
-
import { ESLintUtils as
|
|
168
|
-
var
|
|
259
|
+
import { ESLintUtils as ESLintUtils3 } from "@typescript-eslint/utils";
|
|
260
|
+
var createRule3 = ESLintUtils3.RuleCreator(
|
|
169
261
|
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name}.md`
|
|
170
262
|
);
|
|
171
263
|
var isPascalCase = (str) => /^[A-Z][a-zA-Z0-9]*$/.test(str) && !/^[A-Z]+$/.test(str);
|
|
172
|
-
var jsxPascalCase =
|
|
264
|
+
var jsxPascalCase = createRule3({
|
|
173
265
|
name: "jsx-pascal-case",
|
|
174
266
|
meta: {
|
|
175
267
|
type: "problem",
|
|
@@ -205,11 +297,11 @@ var jsx_pascal_case_default = jsxPascalCase;
|
|
|
205
297
|
|
|
206
298
|
// src/rules/md-filename-case-restriction.ts
|
|
207
299
|
import path3 from "path";
|
|
208
|
-
import { ESLintUtils as
|
|
209
|
-
var
|
|
300
|
+
import { ESLintUtils as ESLintUtils4 } from "@typescript-eslint/utils";
|
|
301
|
+
var createRule4 = ESLintUtils4.RuleCreator(
|
|
210
302
|
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name}.md`
|
|
211
303
|
);
|
|
212
|
-
var mdFilenameCaseRestriction =
|
|
304
|
+
var mdFilenameCaseRestriction = createRule4({
|
|
213
305
|
name: "md-filename-case-restriction",
|
|
214
306
|
meta: {
|
|
215
307
|
type: "problem",
|
|
@@ -251,11 +343,11 @@ var md_filename_case_restriction_default = mdFilenameCaseRestriction;
|
|
|
251
343
|
|
|
252
344
|
// src/rules/no-emoji.ts
|
|
253
345
|
import emojiRegex from "emoji-regex";
|
|
254
|
-
import { ESLintUtils as
|
|
255
|
-
var
|
|
346
|
+
import { ESLintUtils as ESLintUtils5 } from "@typescript-eslint/utils";
|
|
347
|
+
var createRule5 = ESLintUtils5.RuleCreator(
|
|
256
348
|
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name}.md`
|
|
257
349
|
);
|
|
258
|
-
var noEmoji =
|
|
350
|
+
var noEmoji = createRule5({
|
|
259
351
|
name: "no-emoji",
|
|
260
352
|
meta: {
|
|
261
353
|
type: "problem",
|
|
@@ -289,11 +381,11 @@ var noEmoji = createRule4({
|
|
|
289
381
|
var no_emoji_default = noEmoji;
|
|
290
382
|
|
|
291
383
|
// src/rules/no-explicit-return-type.ts
|
|
292
|
-
import { ESLintUtils as
|
|
293
|
-
var
|
|
384
|
+
import { ESLintUtils as ESLintUtils6 } from "@typescript-eslint/utils";
|
|
385
|
+
var createRule6 = ESLintUtils6.RuleCreator(
|
|
294
386
|
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name}.md`
|
|
295
387
|
);
|
|
296
|
-
var noExplicitReturnType =
|
|
388
|
+
var noExplicitReturnType = createRule6({
|
|
297
389
|
name: "no-explicit-return-type",
|
|
298
390
|
meta: {
|
|
299
391
|
type: "suggestion",
|
|
@@ -333,11 +425,11 @@ var noExplicitReturnType = createRule5({
|
|
|
333
425
|
var no_explicit_return_type_default = noExplicitReturnType;
|
|
334
426
|
|
|
335
427
|
// src/rules/prefer-destructuring-params.ts
|
|
336
|
-
import { AST_NODE_TYPES, ESLintUtils as
|
|
337
|
-
var
|
|
428
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES2, ESLintUtils as ESLintUtils7 } from "@typescript-eslint/utils";
|
|
429
|
+
var createRule7 = ESLintUtils7.RuleCreator(
|
|
338
430
|
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name}.md`
|
|
339
431
|
);
|
|
340
|
-
var preferDestructuringParams =
|
|
432
|
+
var preferDestructuringParams = createRule7({
|
|
341
433
|
name: "prefer-destructuring-params",
|
|
342
434
|
meta: {
|
|
343
435
|
type: "suggestion",
|
|
@@ -356,7 +448,7 @@ var preferDestructuringParams = createRule6({
|
|
|
356
448
|
return;
|
|
357
449
|
}
|
|
358
450
|
const hasNonDestructuredParams = node.params.some(
|
|
359
|
-
(param) => param.type !==
|
|
451
|
+
(param) => param.type !== AST_NODE_TYPES2.ObjectPattern && param.type !== AST_NODE_TYPES2.RestElement
|
|
360
452
|
);
|
|
361
453
|
if (hasNonDestructuredParams) {
|
|
362
454
|
context.report({
|
|
@@ -375,11 +467,11 @@ var preferDestructuringParams = createRule6({
|
|
|
375
467
|
var prefer_destructuring_params_default = preferDestructuringParams;
|
|
376
468
|
|
|
377
469
|
// src/rules/prefer-import-type.ts
|
|
378
|
-
import { AST_NODE_TYPES as
|
|
379
|
-
var
|
|
470
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES3, ESLintUtils as ESLintUtils8 } from "@typescript-eslint/utils";
|
|
471
|
+
var createRule8 = ESLintUtils8.RuleCreator(
|
|
380
472
|
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name}.md`
|
|
381
473
|
);
|
|
382
|
-
var preferImportType =
|
|
474
|
+
var preferImportType = createRule8({
|
|
383
475
|
name: "prefer-import-type",
|
|
384
476
|
meta: {
|
|
385
477
|
type: "suggestion",
|
|
@@ -410,14 +502,14 @@ var preferImportType = createRule7({
|
|
|
410
502
|
return;
|
|
411
503
|
}
|
|
412
504
|
const isTypeOnlyImport = node.specifiers.every((specifier) => {
|
|
413
|
-
if (specifier.type ===
|
|
505
|
+
if (specifier.type === AST_NODE_TYPES3.ImportDefaultSpecifier) {
|
|
414
506
|
return false;
|
|
415
507
|
}
|
|
416
|
-
if (specifier.type ===
|
|
508
|
+
if (specifier.type === AST_NODE_TYPES3.ImportNamespaceSpecifier) {
|
|
417
509
|
return false;
|
|
418
510
|
}
|
|
419
|
-
if (specifier.type ===
|
|
420
|
-
const importedName = specifier.imported.type ===
|
|
511
|
+
if (specifier.type === AST_NODE_TYPES3.ImportSpecifier) {
|
|
512
|
+
const importedName = specifier.imported.type === AST_NODE_TYPES3.Identifier ? specifier.imported.name : specifier.imported.value;
|
|
421
513
|
const isKnownTypeOnly = node.source.value === "@typescript-eslint/utils" && ["TSESTree", "RuleContext"].includes(importedName) || node.source.value === "react" && ["Component", "ComponentProps", "ReactNode", "FC", "JSX", "ReactElement", "PropsWithChildren"].includes(
|
|
422
514
|
importedName
|
|
423
515
|
) || importedName.endsWith("Type") || importedName.endsWith("Interface") || importedName.endsWith("Props");
|
|
@@ -445,11 +537,11 @@ var preferImportType = createRule7({
|
|
|
445
537
|
var prefer_import_type_default = preferImportType;
|
|
446
538
|
|
|
447
539
|
// src/rules/prefer-interface-over-inline-types.ts
|
|
448
|
-
import { AST_NODE_TYPES as
|
|
449
|
-
var
|
|
540
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES4, ESLintUtils as ESLintUtils9 } from "@typescript-eslint/utils";
|
|
541
|
+
var createRule9 = ESLintUtils9.RuleCreator(
|
|
450
542
|
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name}.md`
|
|
451
543
|
);
|
|
452
|
-
var preferInterfaceOverInlineTypes =
|
|
544
|
+
var preferInterfaceOverInlineTypes = createRule9({
|
|
453
545
|
name: "prefer-interface-over-inline-types",
|
|
454
546
|
meta: {
|
|
455
547
|
type: "suggestion",
|
|
@@ -465,54 +557,54 @@ var preferInterfaceOverInlineTypes = createRule8({
|
|
|
465
557
|
defaultOptions: [],
|
|
466
558
|
create(context) {
|
|
467
559
|
function hasJSXInConditional(node) {
|
|
468
|
-
return node.consequent.type ===
|
|
560
|
+
return node.consequent.type === AST_NODE_TYPES4.JSXElement || node.consequent.type === AST_NODE_TYPES4.JSXFragment || node.alternate.type === AST_NODE_TYPES4.JSXElement || node.alternate.type === AST_NODE_TYPES4.JSXFragment;
|
|
469
561
|
}
|
|
470
562
|
function hasJSXInLogical(node) {
|
|
471
|
-
return node.right.type ===
|
|
563
|
+
return node.right.type === AST_NODE_TYPES4.JSXElement || node.right.type === AST_NODE_TYPES4.JSXFragment;
|
|
472
564
|
}
|
|
473
565
|
function hasJSXReturn(block) {
|
|
474
566
|
return block.body.some((stmt) => {
|
|
475
|
-
if (stmt.type ===
|
|
476
|
-
return stmt.argument.type ===
|
|
567
|
+
if (stmt.type === AST_NODE_TYPES4.ReturnStatement && stmt.argument) {
|
|
568
|
+
return stmt.argument.type === AST_NODE_TYPES4.JSXElement || stmt.argument.type === AST_NODE_TYPES4.JSXFragment || stmt.argument.type === AST_NODE_TYPES4.ConditionalExpression && hasJSXInConditional(stmt.argument) || stmt.argument.type === AST_NODE_TYPES4.LogicalExpression && hasJSXInLogical(stmt.argument);
|
|
477
569
|
}
|
|
478
570
|
return false;
|
|
479
571
|
});
|
|
480
572
|
}
|
|
481
573
|
function isReactComponent(node) {
|
|
482
|
-
if (node.type ===
|
|
483
|
-
if (node.body.type ===
|
|
574
|
+
if (node.type === AST_NODE_TYPES4.ArrowFunctionExpression) {
|
|
575
|
+
if (node.body.type === AST_NODE_TYPES4.JSXElement || node.body.type === AST_NODE_TYPES4.JSXFragment) {
|
|
484
576
|
return true;
|
|
485
577
|
}
|
|
486
|
-
if (node.body.type ===
|
|
578
|
+
if (node.body.type === AST_NODE_TYPES4.BlockStatement) {
|
|
487
579
|
return hasJSXReturn(node.body);
|
|
488
580
|
}
|
|
489
|
-
} else if (node.type ===
|
|
490
|
-
if (node.body && node.body.type ===
|
|
581
|
+
} else if (node.type === AST_NODE_TYPES4.FunctionExpression || node.type === AST_NODE_TYPES4.FunctionDeclaration) {
|
|
582
|
+
if (node.body && node.body.type === AST_NODE_TYPES4.BlockStatement) {
|
|
491
583
|
return hasJSXReturn(node.body);
|
|
492
584
|
}
|
|
493
585
|
}
|
|
494
586
|
return false;
|
|
495
587
|
}
|
|
496
588
|
function isInlineTypeAnnotation(node) {
|
|
497
|
-
if (node.type ===
|
|
589
|
+
if (node.type === AST_NODE_TYPES4.TSTypeLiteral) {
|
|
498
590
|
return true;
|
|
499
591
|
}
|
|
500
|
-
if (node.type ===
|
|
501
|
-
return node.typeArguments.params.some((param) => param.type ===
|
|
592
|
+
if (node.type === AST_NODE_TYPES4.TSTypeReference && node.typeArguments) {
|
|
593
|
+
return node.typeArguments.params.some((param) => param.type === AST_NODE_TYPES4.TSTypeLiteral);
|
|
502
594
|
}
|
|
503
|
-
if (node.type ===
|
|
595
|
+
if (node.type === AST_NODE_TYPES4.TSUnionType) {
|
|
504
596
|
return node.types.some((type) => isInlineTypeAnnotation(type));
|
|
505
597
|
}
|
|
506
598
|
return false;
|
|
507
599
|
}
|
|
508
600
|
function hasInlineObjectType(node) {
|
|
509
|
-
if (node.type ===
|
|
601
|
+
if (node.type === AST_NODE_TYPES4.TSTypeLiteral) {
|
|
510
602
|
return true;
|
|
511
603
|
}
|
|
512
|
-
if (node.type ===
|
|
513
|
-
return node.typeArguments.params.some((param) => param.type ===
|
|
604
|
+
if (node.type === AST_NODE_TYPES4.TSTypeReference && node.typeArguments) {
|
|
605
|
+
return node.typeArguments.params.some((param) => param.type === AST_NODE_TYPES4.TSTypeLiteral);
|
|
514
606
|
}
|
|
515
|
-
if (node.type ===
|
|
607
|
+
if (node.type === AST_NODE_TYPES4.TSUnionType) {
|
|
516
608
|
return node.types.some((type) => hasInlineObjectType(type));
|
|
517
609
|
}
|
|
518
610
|
return false;
|
|
@@ -525,7 +617,7 @@ var preferInterfaceOverInlineTypes = createRule8({
|
|
|
525
617
|
return;
|
|
526
618
|
}
|
|
527
619
|
const param = node.params[0];
|
|
528
|
-
if (param.type ===
|
|
620
|
+
if (param.type === AST_NODE_TYPES4.Identifier && param.typeAnnotation) {
|
|
529
621
|
const { typeAnnotation } = param.typeAnnotation;
|
|
530
622
|
if (isInlineTypeAnnotation(typeAnnotation) && hasInlineObjectType(typeAnnotation)) {
|
|
531
623
|
context.report({
|
|
@@ -545,11 +637,11 @@ var preferInterfaceOverInlineTypes = createRule8({
|
|
|
545
637
|
var prefer_interface_over_inline_types_default = preferInterfaceOverInlineTypes;
|
|
546
638
|
|
|
547
639
|
// src/rules/prefer-react-import-types.ts
|
|
548
|
-
import { AST_NODE_TYPES as
|
|
549
|
-
var
|
|
640
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES5, ESLintUtils as ESLintUtils10 } from "@typescript-eslint/utils";
|
|
641
|
+
var createRule10 = ESLintUtils10.RuleCreator(
|
|
550
642
|
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name}.md`
|
|
551
643
|
);
|
|
552
|
-
var preferReactImportTypes =
|
|
644
|
+
var preferReactImportTypes = createRule10({
|
|
553
645
|
name: "prefer-react-import-types",
|
|
554
646
|
meta: {
|
|
555
647
|
type: "suggestion",
|
|
@@ -625,7 +717,7 @@ var preferReactImportTypes = createRule9({
|
|
|
625
717
|
]);
|
|
626
718
|
const allReactExports = /* @__PURE__ */ new Set([...reactTypes, ...reactRuntimeExports]);
|
|
627
719
|
function checkMemberExpression(node) {
|
|
628
|
-
if (node.object.type ===
|
|
720
|
+
if (node.object.type === AST_NODE_TYPES5.Identifier && node.object.name === "React" && node.property.type === AST_NODE_TYPES5.Identifier && allReactExports.has(node.property.name)) {
|
|
629
721
|
const typeName = node.property.name;
|
|
630
722
|
const isType = reactTypes.has(typeName);
|
|
631
723
|
const importStatement = isType ? `import type { ${typeName} } from "react"` : `import { ${typeName} } from "react"`;
|
|
@@ -642,7 +734,7 @@ var preferReactImportTypes = createRule9({
|
|
|
642
734
|
return {
|
|
643
735
|
MemberExpression: checkMemberExpression,
|
|
644
736
|
"TSTypeReference > TSQualifiedName": (node) => {
|
|
645
|
-
if (node.left.type ===
|
|
737
|
+
if (node.left.type === AST_NODE_TYPES5.Identifier && node.left.name === "React" && node.right.type === AST_NODE_TYPES5.Identifier && allReactExports.has(node.right.name)) {
|
|
646
738
|
const typeName = node.right.name;
|
|
647
739
|
const isType = reactTypes.has(typeName);
|
|
648
740
|
const importStatement = isType ? `import type { ${typeName} } from "react"` : `import { ${typeName} } from "react"`;
|
|
@@ -662,11 +754,11 @@ var preferReactImportTypes = createRule9({
|
|
|
662
754
|
var prefer_react_import_types_default = preferReactImportTypes;
|
|
663
755
|
|
|
664
756
|
// src/rules/react-props-destructure.ts
|
|
665
|
-
import { AST_NODE_TYPES as
|
|
666
|
-
var
|
|
757
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES6, ESLintUtils as ESLintUtils11 } from "@typescript-eslint/utils";
|
|
758
|
+
var createRule11 = ESLintUtils11.RuleCreator(
|
|
667
759
|
(name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name}.md`
|
|
668
760
|
);
|
|
669
|
-
var reactPropsDestructure =
|
|
761
|
+
var reactPropsDestructure = createRule11({
|
|
670
762
|
name: "react-props-destructure",
|
|
671
763
|
meta: {
|
|
672
764
|
type: "suggestion",
|
|
@@ -682,29 +774,29 @@ var reactPropsDestructure = createRule10({
|
|
|
682
774
|
defaultOptions: [],
|
|
683
775
|
create(context) {
|
|
684
776
|
function hasJSXInConditional(node) {
|
|
685
|
-
return node.consequent.type ===
|
|
777
|
+
return node.consequent.type === AST_NODE_TYPES6.JSXElement || node.consequent.type === AST_NODE_TYPES6.JSXFragment || node.alternate.type === AST_NODE_TYPES6.JSXElement || node.alternate.type === AST_NODE_TYPES6.JSXFragment;
|
|
686
778
|
}
|
|
687
779
|
function hasJSXInLogical(node) {
|
|
688
|
-
return node.right.type ===
|
|
780
|
+
return node.right.type === AST_NODE_TYPES6.JSXElement || node.right.type === AST_NODE_TYPES6.JSXFragment;
|
|
689
781
|
}
|
|
690
782
|
function hasJSXReturn(block) {
|
|
691
783
|
return block.body.some((stmt) => {
|
|
692
|
-
if (stmt.type ===
|
|
693
|
-
return stmt.argument.type ===
|
|
784
|
+
if (stmt.type === AST_NODE_TYPES6.ReturnStatement && stmt.argument) {
|
|
785
|
+
return stmt.argument.type === AST_NODE_TYPES6.JSXElement || stmt.argument.type === AST_NODE_TYPES6.JSXFragment || stmt.argument.type === AST_NODE_TYPES6.ConditionalExpression && hasJSXInConditional(stmt.argument) || stmt.argument.type === AST_NODE_TYPES6.LogicalExpression && hasJSXInLogical(stmt.argument);
|
|
694
786
|
}
|
|
695
787
|
return false;
|
|
696
788
|
});
|
|
697
789
|
}
|
|
698
790
|
function isReactComponent(node) {
|
|
699
|
-
if (node.type ===
|
|
700
|
-
if (node.body.type ===
|
|
791
|
+
if (node.type === AST_NODE_TYPES6.ArrowFunctionExpression) {
|
|
792
|
+
if (node.body.type === AST_NODE_TYPES6.JSXElement || node.body.type === AST_NODE_TYPES6.JSXFragment) {
|
|
701
793
|
return true;
|
|
702
794
|
}
|
|
703
|
-
if (node.body.type ===
|
|
795
|
+
if (node.body.type === AST_NODE_TYPES6.BlockStatement) {
|
|
704
796
|
return hasJSXReturn(node.body);
|
|
705
797
|
}
|
|
706
|
-
} else if (node.type ===
|
|
707
|
-
if (node.body && node.body.type ===
|
|
798
|
+
} else if (node.type === AST_NODE_TYPES6.FunctionExpression || node.type === AST_NODE_TYPES6.FunctionDeclaration) {
|
|
799
|
+
if (node.body && node.body.type === AST_NODE_TYPES6.BlockStatement) {
|
|
708
800
|
return hasJSXReturn(node.body);
|
|
709
801
|
}
|
|
710
802
|
}
|
|
@@ -718,9 +810,9 @@ var reactPropsDestructure = createRule10({
|
|
|
718
810
|
return;
|
|
719
811
|
}
|
|
720
812
|
const param = node.params[0];
|
|
721
|
-
if (param.type ===
|
|
722
|
-
const properties = param.properties.filter((prop) => prop.type ===
|
|
723
|
-
if (prop.key.type ===
|
|
813
|
+
if (param.type === AST_NODE_TYPES6.ObjectPattern) {
|
|
814
|
+
const properties = param.properties.filter((prop) => prop.type === AST_NODE_TYPES6.Property).map((prop) => {
|
|
815
|
+
if (prop.key.type === AST_NODE_TYPES6.Identifier) {
|
|
724
816
|
return prop.key.name;
|
|
725
817
|
}
|
|
726
818
|
return null;
|
|
@@ -752,6 +844,7 @@ var meta = {
|
|
|
752
844
|
version: package_default.version
|
|
753
845
|
};
|
|
754
846
|
var rules = {
|
|
847
|
+
"enforce-readonly-component-props": enforce_readonly_component_props_default,
|
|
755
848
|
"file-kebab-case": file_kebab_case_default,
|
|
756
849
|
"jsx-pascal-case": jsx_pascal_case_default,
|
|
757
850
|
"md-filename-case-restriction": md_filename_case_restriction_default,
|
|
@@ -788,12 +881,14 @@ var baseRecommendedRules = {
|
|
|
788
881
|
var jsxRules = {
|
|
789
882
|
"nextfriday/jsx-pascal-case": "warn",
|
|
790
883
|
"nextfriday/prefer-interface-over-inline-types": "warn",
|
|
791
|
-
"nextfriday/react-props-destructure": "warn"
|
|
884
|
+
"nextfriday/react-props-destructure": "warn",
|
|
885
|
+
"nextfriday/enforce-readonly-component-props": "warn"
|
|
792
886
|
};
|
|
793
887
|
var jsxRecommendedRules = {
|
|
794
888
|
"nextfriday/jsx-pascal-case": "error",
|
|
795
889
|
"nextfriday/prefer-interface-over-inline-types": "error",
|
|
796
|
-
"nextfriday/react-props-destructure": "error"
|
|
890
|
+
"nextfriday/react-props-destructure": "error",
|
|
891
|
+
"nextfriday/enforce-readonly-component-props": "error"
|
|
797
892
|
};
|
|
798
893
|
var createConfig = (configRules) => ({
|
|
799
894
|
plugins: {
|