eslint-plugin-nextfriday 1.1.1 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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.1.1",
4
+ version: "1.2.1",
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 createRule = ESLintUtils.RuleCreator(
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 = createRule({
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 ESLintUtils2 } from "@typescript-eslint/utils";
168
- var createRule2 = ESLintUtils2.RuleCreator(
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 = createRule2({
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 ESLintUtils3 } from "@typescript-eslint/utils";
209
- var createRule3 = ESLintUtils3.RuleCreator(
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 = createRule3({
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 ESLintUtils4 } from "@typescript-eslint/utils";
255
- var createRule4 = ESLintUtils4.RuleCreator(
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 = createRule4({
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 ESLintUtils5 } from "@typescript-eslint/utils";
293
- var createRule5 = ESLintUtils5.RuleCreator(
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 = createRule5({
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 ESLintUtils6 } from "@typescript-eslint/utils";
337
- var createRule6 = ESLintUtils6.RuleCreator(
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 = createRule6({
432
+ var preferDestructuringParams = createRule7({
341
433
  name: "prefer-destructuring-params",
342
434
  meta: {
343
435
  type: "suggestion",
@@ -352,11 +444,21 @@ var preferDestructuringParams = createRule6({
352
444
  defaultOptions: [],
353
445
  create(context) {
354
446
  const checkFunction = (node) => {
447
+ const { filename } = context;
448
+ if (filename.includes("node_modules") || filename.includes(".d.ts")) {
449
+ return;
450
+ }
451
+ if (node.type === AST_NODE_TYPES2.FunctionDeclaration && node.id) {
452
+ const functionName = node.id.name;
453
+ if (functionName.startsWith("_") || functionName.includes("$") || /^[A-Z][a-zA-Z]*$/.test(functionName)) {
454
+ return;
455
+ }
456
+ }
355
457
  if (node.params.length <= 1) {
356
458
  return;
357
459
  }
358
460
  const hasNonDestructuredParams = node.params.some(
359
- (param) => param.type !== AST_NODE_TYPES.ObjectPattern && param.type !== AST_NODE_TYPES.RestElement
461
+ (param) => param.type !== AST_NODE_TYPES2.ObjectPattern && param.type !== AST_NODE_TYPES2.RestElement
360
462
  );
361
463
  if (hasNonDestructuredParams) {
362
464
  context.report({
@@ -375,11 +477,11 @@ var preferDestructuringParams = createRule6({
375
477
  var prefer_destructuring_params_default = preferDestructuringParams;
376
478
 
377
479
  // src/rules/prefer-import-type.ts
378
- import { AST_NODE_TYPES as AST_NODE_TYPES2, ESLintUtils as ESLintUtils7 } from "@typescript-eslint/utils";
379
- var createRule7 = ESLintUtils7.RuleCreator(
480
+ import { AST_NODE_TYPES as AST_NODE_TYPES3, ESLintUtils as ESLintUtils8 } from "@typescript-eslint/utils";
481
+ var createRule8 = ESLintUtils8.RuleCreator(
380
482
  (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name}.md`
381
483
  );
382
- var preferImportType = createRule7({
484
+ var preferImportType = createRule8({
383
485
  name: "prefer-import-type",
384
486
  meta: {
385
487
  type: "suggestion",
@@ -410,14 +512,14 @@ var preferImportType = createRule7({
410
512
  return;
411
513
  }
412
514
  const isTypeOnlyImport = node.specifiers.every((specifier) => {
413
- if (specifier.type === AST_NODE_TYPES2.ImportDefaultSpecifier) {
515
+ if (specifier.type === AST_NODE_TYPES3.ImportDefaultSpecifier) {
414
516
  return false;
415
517
  }
416
- if (specifier.type === AST_NODE_TYPES2.ImportNamespaceSpecifier) {
518
+ if (specifier.type === AST_NODE_TYPES3.ImportNamespaceSpecifier) {
417
519
  return false;
418
520
  }
419
- if (specifier.type === AST_NODE_TYPES2.ImportSpecifier) {
420
- const importedName = specifier.imported.type === AST_NODE_TYPES2.Identifier ? specifier.imported.name : specifier.imported.value;
521
+ if (specifier.type === AST_NODE_TYPES3.ImportSpecifier) {
522
+ const importedName = specifier.imported.type === AST_NODE_TYPES3.Identifier ? specifier.imported.name : specifier.imported.value;
421
523
  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
524
  importedName
423
525
  ) || importedName.endsWith("Type") || importedName.endsWith("Interface") || importedName.endsWith("Props");
@@ -445,11 +547,11 @@ var preferImportType = createRule7({
445
547
  var prefer_import_type_default = preferImportType;
446
548
 
447
549
  // src/rules/prefer-interface-over-inline-types.ts
448
- import { AST_NODE_TYPES as AST_NODE_TYPES3, ESLintUtils as ESLintUtils8 } from "@typescript-eslint/utils";
449
- var createRule8 = ESLintUtils8.RuleCreator(
550
+ import { AST_NODE_TYPES as AST_NODE_TYPES4, ESLintUtils as ESLintUtils9 } from "@typescript-eslint/utils";
551
+ var createRule9 = ESLintUtils9.RuleCreator(
450
552
  (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name}.md`
451
553
  );
452
- var preferInterfaceOverInlineTypes = createRule8({
554
+ var preferInterfaceOverInlineTypes = createRule9({
453
555
  name: "prefer-interface-over-inline-types",
454
556
  meta: {
455
557
  type: "suggestion",
@@ -465,54 +567,54 @@ var preferInterfaceOverInlineTypes = createRule8({
465
567
  defaultOptions: [],
466
568
  create(context) {
467
569
  function hasJSXInConditional(node) {
468
- return node.consequent.type === AST_NODE_TYPES3.JSXElement || node.consequent.type === AST_NODE_TYPES3.JSXFragment || node.alternate.type === AST_NODE_TYPES3.JSXElement || node.alternate.type === AST_NODE_TYPES3.JSXFragment;
570
+ 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
571
  }
470
572
  function hasJSXInLogical(node) {
471
- return node.right.type === AST_NODE_TYPES3.JSXElement || node.right.type === AST_NODE_TYPES3.JSXFragment;
573
+ return node.right.type === AST_NODE_TYPES4.JSXElement || node.right.type === AST_NODE_TYPES4.JSXFragment;
472
574
  }
473
575
  function hasJSXReturn(block) {
474
576
  return block.body.some((stmt) => {
475
- if (stmt.type === AST_NODE_TYPES3.ReturnStatement && stmt.argument) {
476
- return stmt.argument.type === AST_NODE_TYPES3.JSXElement || stmt.argument.type === AST_NODE_TYPES3.JSXFragment || stmt.argument.type === AST_NODE_TYPES3.ConditionalExpression && hasJSXInConditional(stmt.argument) || stmt.argument.type === AST_NODE_TYPES3.LogicalExpression && hasJSXInLogical(stmt.argument);
577
+ if (stmt.type === AST_NODE_TYPES4.ReturnStatement && stmt.argument) {
578
+ 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
579
  }
478
580
  return false;
479
581
  });
480
582
  }
481
583
  function isReactComponent(node) {
482
- if (node.type === AST_NODE_TYPES3.ArrowFunctionExpression) {
483
- if (node.body.type === AST_NODE_TYPES3.JSXElement || node.body.type === AST_NODE_TYPES3.JSXFragment) {
584
+ if (node.type === AST_NODE_TYPES4.ArrowFunctionExpression) {
585
+ if (node.body.type === AST_NODE_TYPES4.JSXElement || node.body.type === AST_NODE_TYPES4.JSXFragment) {
484
586
  return true;
485
587
  }
486
- if (node.body.type === AST_NODE_TYPES3.BlockStatement) {
588
+ if (node.body.type === AST_NODE_TYPES4.BlockStatement) {
487
589
  return hasJSXReturn(node.body);
488
590
  }
489
- } else if (node.type === AST_NODE_TYPES3.FunctionExpression || node.type === AST_NODE_TYPES3.FunctionDeclaration) {
490
- if (node.body && node.body.type === AST_NODE_TYPES3.BlockStatement) {
591
+ } else if (node.type === AST_NODE_TYPES4.FunctionExpression || node.type === AST_NODE_TYPES4.FunctionDeclaration) {
592
+ if (node.body && node.body.type === AST_NODE_TYPES4.BlockStatement) {
491
593
  return hasJSXReturn(node.body);
492
594
  }
493
595
  }
494
596
  return false;
495
597
  }
496
598
  function isInlineTypeAnnotation(node) {
497
- if (node.type === AST_NODE_TYPES3.TSTypeLiteral) {
599
+ if (node.type === AST_NODE_TYPES4.TSTypeLiteral) {
498
600
  return true;
499
601
  }
500
- if (node.type === AST_NODE_TYPES3.TSTypeReference && node.typeArguments) {
501
- return node.typeArguments.params.some((param) => param.type === AST_NODE_TYPES3.TSTypeLiteral);
602
+ if (node.type === AST_NODE_TYPES4.TSTypeReference && node.typeArguments) {
603
+ return node.typeArguments.params.some((param) => param.type === AST_NODE_TYPES4.TSTypeLiteral);
502
604
  }
503
- if (node.type === AST_NODE_TYPES3.TSUnionType) {
605
+ if (node.type === AST_NODE_TYPES4.TSUnionType) {
504
606
  return node.types.some((type) => isInlineTypeAnnotation(type));
505
607
  }
506
608
  return false;
507
609
  }
508
610
  function hasInlineObjectType(node) {
509
- if (node.type === AST_NODE_TYPES3.TSTypeLiteral) {
611
+ if (node.type === AST_NODE_TYPES4.TSTypeLiteral) {
510
612
  return true;
511
613
  }
512
- if (node.type === AST_NODE_TYPES3.TSTypeReference && node.typeArguments) {
513
- return node.typeArguments.params.some((param) => param.type === AST_NODE_TYPES3.TSTypeLiteral);
614
+ if (node.type === AST_NODE_TYPES4.TSTypeReference && node.typeArguments) {
615
+ return node.typeArguments.params.some((param) => param.type === AST_NODE_TYPES4.TSTypeLiteral);
514
616
  }
515
- if (node.type === AST_NODE_TYPES3.TSUnionType) {
617
+ if (node.type === AST_NODE_TYPES4.TSUnionType) {
516
618
  return node.types.some((type) => hasInlineObjectType(type));
517
619
  }
518
620
  return false;
@@ -525,7 +627,7 @@ var preferInterfaceOverInlineTypes = createRule8({
525
627
  return;
526
628
  }
527
629
  const param = node.params[0];
528
- if (param.type === AST_NODE_TYPES3.Identifier && param.typeAnnotation) {
630
+ if (param.type === AST_NODE_TYPES4.Identifier && param.typeAnnotation) {
529
631
  const { typeAnnotation } = param.typeAnnotation;
530
632
  if (isInlineTypeAnnotation(typeAnnotation) && hasInlineObjectType(typeAnnotation)) {
531
633
  context.report({
@@ -545,11 +647,11 @@ var preferInterfaceOverInlineTypes = createRule8({
545
647
  var prefer_interface_over_inline_types_default = preferInterfaceOverInlineTypes;
546
648
 
547
649
  // src/rules/prefer-react-import-types.ts
548
- import { AST_NODE_TYPES as AST_NODE_TYPES4, ESLintUtils as ESLintUtils9 } from "@typescript-eslint/utils";
549
- var createRule9 = ESLintUtils9.RuleCreator(
650
+ import { AST_NODE_TYPES as AST_NODE_TYPES5, ESLintUtils as ESLintUtils10 } from "@typescript-eslint/utils";
651
+ var createRule10 = ESLintUtils10.RuleCreator(
550
652
  (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name}.md`
551
653
  );
552
- var preferReactImportTypes = createRule9({
654
+ var preferReactImportTypes = createRule10({
553
655
  name: "prefer-react-import-types",
554
656
  meta: {
555
657
  type: "suggestion",
@@ -625,7 +727,7 @@ var preferReactImportTypes = createRule9({
625
727
  ]);
626
728
  const allReactExports = /* @__PURE__ */ new Set([...reactTypes, ...reactRuntimeExports]);
627
729
  function checkMemberExpression(node) {
628
- if (node.object.type === AST_NODE_TYPES4.Identifier && node.object.name === "React" && node.property.type === AST_NODE_TYPES4.Identifier && allReactExports.has(node.property.name)) {
730
+ 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
731
  const typeName = node.property.name;
630
732
  const isType = reactTypes.has(typeName);
631
733
  const importStatement = isType ? `import type { ${typeName} } from "react"` : `import { ${typeName} } from "react"`;
@@ -642,7 +744,7 @@ var preferReactImportTypes = createRule9({
642
744
  return {
643
745
  MemberExpression: checkMemberExpression,
644
746
  "TSTypeReference > TSQualifiedName": (node) => {
645
- if (node.left.type === AST_NODE_TYPES4.Identifier && node.left.name === "React" && node.right.type === AST_NODE_TYPES4.Identifier && allReactExports.has(node.right.name)) {
747
+ 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
748
  const typeName = node.right.name;
647
749
  const isType = reactTypes.has(typeName);
648
750
  const importStatement = isType ? `import type { ${typeName} } from "react"` : `import { ${typeName} } from "react"`;
@@ -662,11 +764,11 @@ var preferReactImportTypes = createRule9({
662
764
  var prefer_react_import_types_default = preferReactImportTypes;
663
765
 
664
766
  // src/rules/react-props-destructure.ts
665
- import { AST_NODE_TYPES as AST_NODE_TYPES5, ESLintUtils as ESLintUtils10 } from "@typescript-eslint/utils";
666
- var createRule10 = ESLintUtils10.RuleCreator(
767
+ import { AST_NODE_TYPES as AST_NODE_TYPES6, ESLintUtils as ESLintUtils11 } from "@typescript-eslint/utils";
768
+ var createRule11 = ESLintUtils11.RuleCreator(
667
769
  (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name}.md`
668
770
  );
669
- var reactPropsDestructure = createRule10({
771
+ var reactPropsDestructure = createRule11({
670
772
  name: "react-props-destructure",
671
773
  meta: {
672
774
  type: "suggestion",
@@ -682,29 +784,29 @@ var reactPropsDestructure = createRule10({
682
784
  defaultOptions: [],
683
785
  create(context) {
684
786
  function hasJSXInConditional(node) {
685
- return node.consequent.type === AST_NODE_TYPES5.JSXElement || node.consequent.type === AST_NODE_TYPES5.JSXFragment || node.alternate.type === AST_NODE_TYPES5.JSXElement || node.alternate.type === AST_NODE_TYPES5.JSXFragment;
787
+ 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
788
  }
687
789
  function hasJSXInLogical(node) {
688
- return node.right.type === AST_NODE_TYPES5.JSXElement || node.right.type === AST_NODE_TYPES5.JSXFragment;
790
+ return node.right.type === AST_NODE_TYPES6.JSXElement || node.right.type === AST_NODE_TYPES6.JSXFragment;
689
791
  }
690
792
  function hasJSXReturn(block) {
691
793
  return block.body.some((stmt) => {
692
- if (stmt.type === AST_NODE_TYPES5.ReturnStatement && stmt.argument) {
693
- return stmt.argument.type === AST_NODE_TYPES5.JSXElement || stmt.argument.type === AST_NODE_TYPES5.JSXFragment || stmt.argument.type === AST_NODE_TYPES5.ConditionalExpression && hasJSXInConditional(stmt.argument) || stmt.argument.type === AST_NODE_TYPES5.LogicalExpression && hasJSXInLogical(stmt.argument);
794
+ if (stmt.type === AST_NODE_TYPES6.ReturnStatement && stmt.argument) {
795
+ 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
796
  }
695
797
  return false;
696
798
  });
697
799
  }
698
800
  function isReactComponent(node) {
699
- if (node.type === AST_NODE_TYPES5.ArrowFunctionExpression) {
700
- if (node.body.type === AST_NODE_TYPES5.JSXElement || node.body.type === AST_NODE_TYPES5.JSXFragment) {
801
+ if (node.type === AST_NODE_TYPES6.ArrowFunctionExpression) {
802
+ if (node.body.type === AST_NODE_TYPES6.JSXElement || node.body.type === AST_NODE_TYPES6.JSXFragment) {
701
803
  return true;
702
804
  }
703
- if (node.body.type === AST_NODE_TYPES5.BlockStatement) {
805
+ if (node.body.type === AST_NODE_TYPES6.BlockStatement) {
704
806
  return hasJSXReturn(node.body);
705
807
  }
706
- } else if (node.type === AST_NODE_TYPES5.FunctionExpression || node.type === AST_NODE_TYPES5.FunctionDeclaration) {
707
- if (node.body && node.body.type === AST_NODE_TYPES5.BlockStatement) {
808
+ } else if (node.type === AST_NODE_TYPES6.FunctionExpression || node.type === AST_NODE_TYPES6.FunctionDeclaration) {
809
+ if (node.body && node.body.type === AST_NODE_TYPES6.BlockStatement) {
708
810
  return hasJSXReturn(node.body);
709
811
  }
710
812
  }
@@ -718,9 +820,9 @@ var reactPropsDestructure = createRule10({
718
820
  return;
719
821
  }
720
822
  const param = node.params[0];
721
- if (param.type === AST_NODE_TYPES5.ObjectPattern) {
722
- const properties = param.properties.filter((prop) => prop.type === AST_NODE_TYPES5.Property).map((prop) => {
723
- if (prop.key.type === AST_NODE_TYPES5.Identifier) {
823
+ if (param.type === AST_NODE_TYPES6.ObjectPattern) {
824
+ const properties = param.properties.filter((prop) => prop.type === AST_NODE_TYPES6.Property).map((prop) => {
825
+ if (prop.key.type === AST_NODE_TYPES6.Identifier) {
724
826
  return prop.key.name;
725
827
  }
726
828
  return null;
@@ -752,6 +854,7 @@ var meta = {
752
854
  version: package_default.version
753
855
  };
754
856
  var rules = {
857
+ "enforce-readonly-component-props": enforce_readonly_component_props_default,
755
858
  "file-kebab-case": file_kebab_case_default,
756
859
  "jsx-pascal-case": jsx_pascal_case_default,
757
860
  "md-filename-case-restriction": md_filename_case_restriction_default,
@@ -788,12 +891,14 @@ var baseRecommendedRules = {
788
891
  var jsxRules = {
789
892
  "nextfriday/jsx-pascal-case": "warn",
790
893
  "nextfriday/prefer-interface-over-inline-types": "warn",
791
- "nextfriday/react-props-destructure": "warn"
894
+ "nextfriday/react-props-destructure": "warn",
895
+ "nextfriday/enforce-readonly-component-props": "warn"
792
896
  };
793
897
  var jsxRecommendedRules = {
794
898
  "nextfriday/jsx-pascal-case": "error",
795
899
  "nextfriday/prefer-interface-over-inline-types": "error",
796
- "nextfriday/react-props-destructure": "error"
900
+ "nextfriday/react-props-destructure": "error",
901
+ "nextfriday/enforce-readonly-component-props": "error"
797
902
  };
798
903
  var createConfig = (configRules) => ({
799
904
  plugins: {