eslint-plugin-nextfriday 4.3.2 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.cjs CHANGED
@@ -32,10 +32,10 @@ let emoji_regex = require("emoji-regex");
32
32
  emoji_regex = __toESM(emoji_regex, 1);
33
33
  //#region package.json
34
34
  var name = "eslint-plugin-nextfriday";
35
- var version = "4.3.2";
35
+ var version = "5.0.0";
36
36
  //#endregion
37
37
  //#region src/rules/boolean-naming-prefix.ts
38
- const createRule$32 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
38
+ const createRule$26 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
39
39
  const BOOLEAN_PREFIXES = [
40
40
  "is",
41
41
  "has",
@@ -84,7 +84,7 @@ const hasBooleanTypeAnnotation = (node) => {
84
84
  }
85
85
  return false;
86
86
  };
87
- const booleanNamingPrefix = createRule$32({
87
+ const booleanNamingPrefix = createRule$26({
88
88
  name: "boolean-naming-prefix",
89
89
  meta: {
90
90
  type: "suggestion",
@@ -144,99 +144,6 @@ const booleanNamingPrefix = createRule$32({
144
144
  }
145
145
  });
146
146
  //#endregion
147
- //#region src/rules/enforce-camel-case.ts
148
- const createRule$31 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
149
- const SNAKE_CASE_REGEX$2 = /^[a-z]+_[a-z0-9_]*$/;
150
- const PASCAL_CASE_REGEX = /^[A-Z][a-zA-Z0-9]*$/;
151
- const REACT_WRAPPERS = [
152
- "memo",
153
- "forwardRef",
154
- "lazy"
155
- ];
156
- const returnsJsx$1 = (node) => {
157
- if (node.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXElement || node.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXFragment) return true;
158
- if (node.type === _typescript_eslint_utils.AST_NODE_TYPES.ConditionalExpression) return returnsJsx$1(node.consequent) || returnsJsx$1(node.alternate);
159
- if (node.type === _typescript_eslint_utils.AST_NODE_TYPES.LogicalExpression) return returnsJsx$1(node.left) || returnsJsx$1(node.right);
160
- return false;
161
- };
162
- const bodyReturnsJsx$1 = (body) => {
163
- if (body.type !== _typescript_eslint_utils.AST_NODE_TYPES.BlockStatement) return returnsJsx$1(body);
164
- return body.body.some((stmt) => stmt.type === _typescript_eslint_utils.AST_NODE_TYPES.ReturnStatement && stmt.argument !== null && returnsJsx$1(stmt.argument));
165
- };
166
- const isComponentFunction$1 = (init) => {
167
- if (init.type === _typescript_eslint_utils.AST_NODE_TYPES.ArrowFunctionExpression || init.type === _typescript_eslint_utils.AST_NODE_TYPES.FunctionExpression) return bodyReturnsJsx$1(init.body);
168
- if (init.type === _typescript_eslint_utils.AST_NODE_TYPES.CallExpression) {
169
- const { callee } = init;
170
- if (callee.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && REACT_WRAPPERS.includes(callee.name)) return true;
171
- if (callee.type === _typescript_eslint_utils.AST_NODE_TYPES.MemberExpression && callee.object.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && callee.object.name === "React" && callee.property.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && REACT_WRAPPERS.includes(callee.property.name)) return true;
172
- }
173
- return false;
174
- };
175
- const isGlobalScope$2 = (node) => {
176
- const declaration = node.parent;
177
- if (!declaration || declaration.type !== _typescript_eslint_utils.AST_NODE_TYPES.VariableDeclaration) return false;
178
- const { parent } = declaration;
179
- if (parent.type === _typescript_eslint_utils.AST_NODE_TYPES.Program) return true;
180
- if (parent.type === _typescript_eslint_utils.AST_NODE_TYPES.ExportNamedDeclaration && parent.parent?.type === _typescript_eslint_utils.AST_NODE_TYPES.Program) return true;
181
- return false;
182
- };
183
- const isStaticValue$1 = (init) => {
184
- if (init.type === _typescript_eslint_utils.AST_NODE_TYPES.Literal) return true;
185
- if (init.type === _typescript_eslint_utils.AST_NODE_TYPES.UnaryExpression && init.argument.type === _typescript_eslint_utils.AST_NODE_TYPES.Literal) return true;
186
- if (init.type === _typescript_eslint_utils.AST_NODE_TYPES.TemplateLiteral && init.expressions.length === 0) return true;
187
- if (init.type === _typescript_eslint_utils.AST_NODE_TYPES.ArrayExpression) return init.elements.every((el) => el !== null && el.type !== _typescript_eslint_utils.AST_NODE_TYPES.SpreadElement && isStaticValue$1(el));
188
- if (init.type === _typescript_eslint_utils.AST_NODE_TYPES.ObjectExpression) return init.properties.every((prop) => prop.type === _typescript_eslint_utils.AST_NODE_TYPES.Property && isStaticValue$1(prop.value));
189
- if (init.type === _typescript_eslint_utils.AST_NODE_TYPES.TSAsExpression && init.typeAnnotation.type === _typescript_eslint_utils.AST_NODE_TYPES.TSTypeReference && init.typeAnnotation.typeName.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && init.typeAnnotation.typeName.name === "const") return true;
190
- return false;
191
- };
192
- const enforceCamelCase = createRule$31({
193
- name: "enforce-camel-case",
194
- meta: {
195
- type: "suggestion",
196
- docs: { description: "Enforce camelCase for variables and functions, ban snake_case, and restrict PascalCase to React components" },
197
- messages: {
198
- noSnakeCase: "Variable '{{ name }}' should not use snake_case. Use camelCase instead.",
199
- pascalCaseReserved: "Variable '{{ name }}' uses PascalCase but is not a React component. PascalCase is reserved for components."
200
- },
201
- schema: []
202
- },
203
- defaultOptions: [],
204
- create(context) {
205
- return {
206
- VariableDeclarator(node) {
207
- if (node.id.type !== _typescript_eslint_utils.AST_NODE_TYPES.Identifier) return;
208
- const { name } = node.id;
209
- if (SNAKE_CASE_REGEX$2.test(name)) {
210
- if (node.parent.kind === "const" && isGlobalScope$2(node) && node.init && isStaticValue$1(node.init)) return;
211
- context.report({
212
- node: node.id,
213
- messageId: "noSnakeCase",
214
- data: { name }
215
- });
216
- return;
217
- }
218
- if (!node.init || !PASCAL_CASE_REGEX.test(name)) return;
219
- if (isComponentFunction$1(node.init)) return;
220
- if (node.init.type !== _typescript_eslint_utils.AST_NODE_TYPES.ArrowFunctionExpression && node.init.type !== _typescript_eslint_utils.AST_NODE_TYPES.FunctionExpression && node.init.type !== _typescript_eslint_utils.AST_NODE_TYPES.CallExpression) return;
221
- context.report({
222
- node: node.id,
223
- messageId: "pascalCaseReserved",
224
- data: { name }
225
- });
226
- },
227
- FunctionDeclaration(node) {
228
- if (!node.id) return;
229
- const { name } = node.id;
230
- if (SNAKE_CASE_REGEX$2.test(name)) context.report({
231
- node: node.id,
232
- messageId: "noSnakeCase",
233
- data: { name }
234
- });
235
- }
236
- };
237
- }
238
- });
239
- //#endregion
240
147
  //#region src/utils.ts
241
148
  const getFileExtension = (filename) => (0, node_path.extname)(filename).slice(1);
242
149
  const getBaseName = (filename) => (0, node_path.basename)(filename, (0, node_path.extname)(filename));
@@ -250,9 +157,9 @@ const isConfigFile = (filename) => {
250
157
  };
251
158
  //#endregion
252
159
  //#region src/rules/enforce-constant-case.ts
253
- const createRule$30 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
254
- const SCREAMING_SNAKE_CASE_REGEX$2 = /^[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)*$/;
255
- const SNAKE_CASE_REGEX$1 = /^[a-z]+_[a-z0-9_]*$/;
160
+ const createRule$25 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
161
+ const SCREAMING_SNAKE_CASE_REGEX$1 = /^[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)*$/;
162
+ const SNAKE_CASE_REGEX = /^[a-z]+_[a-z0-9_]*$/;
256
163
  const toScreamingSnakeCase = (str) => str.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/([A-Z])([A-Z][a-z])/g, "$1_$2").toUpperCase();
257
164
  const isMagicLiteral = (init) => {
258
165
  if (init.type === _typescript_eslint_utils.AST_NODE_TYPES.Literal) return typeof init.value === "string" || typeof init.value === "number";
@@ -268,7 +175,7 @@ const isGlobalScope$1 = (node) => {
268
175
  if (parent.type === _typescript_eslint_utils.AST_NODE_TYPES.ExportNamedDeclaration && parent.parent?.type === _typescript_eslint_utils.AST_NODE_TYPES.Program) return true;
269
176
  return false;
270
177
  };
271
- const enforceConstantCase = createRule$30({
178
+ const enforceConstantCase = createRule$25({
272
179
  name: "enforce-constant-case",
273
180
  meta: {
274
181
  type: "suggestion",
@@ -288,7 +195,7 @@ const enforceConstantCase = createRule$30({
288
195
  if (declarator.id.type !== _typescript_eslint_utils.AST_NODE_TYPES.Identifier || !declarator.init) return;
289
196
  if (!isMagicLiteral(declarator.init)) return;
290
197
  const { name } = declarator.id;
291
- if (SNAKE_CASE_REGEX$1.test(name)) {
198
+ if (SNAKE_CASE_REGEX.test(name)) {
292
199
  context.report({
293
200
  node: declarator.id,
294
201
  messageId: "noSnakeCase",
@@ -299,7 +206,7 @@ const enforceConstantCase = createRule$30({
299
206
  });
300
207
  return;
301
208
  }
302
- if (!SCREAMING_SNAKE_CASE_REGEX$2.test(name)) context.report({
209
+ if (!SCREAMING_SNAKE_CASE_REGEX$1.test(name)) context.report({
303
210
  node: declarator.id,
304
211
  messageId: "useScreamingSnakeCase",
305
212
  data: {
@@ -391,44 +298,6 @@ const enforceHookNaming = _typescript_eslint_utils.ESLintUtils.RuleCreator((name
391
298
  }
392
299
  });
393
300
  //#endregion
394
- //#region src/rules/enforce-property-case.ts
395
- const createRule$29 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
396
- const SNAKE_CASE_REGEX = /^[a-z]+_[a-z0-9_]*$/;
397
- const SCREAMING_SNAKE_CASE_REGEX$1 = /^[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)*$/;
398
- const isInsideAsConst = (node) => {
399
- const { parent } = node;
400
- if (parent.type === _typescript_eslint_utils.AST_NODE_TYPES.TSAsExpression && parent.typeAnnotation.type === _typescript_eslint_utils.AST_NODE_TYPES.TSTypeReference && parent.typeAnnotation.typeName.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && parent.typeAnnotation.typeName.name === "const") return true;
401
- if (parent.type === _typescript_eslint_utils.AST_NODE_TYPES.ArrayExpression) {
402
- const grandparent = parent.parent;
403
- if (grandparent?.type === _typescript_eslint_utils.AST_NODE_TYPES.TSAsExpression && grandparent.typeAnnotation.type === _typescript_eslint_utils.AST_NODE_TYPES.TSTypeReference && grandparent.typeAnnotation.typeName.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && grandparent.typeAnnotation.typeName.name === "const") return true;
404
- }
405
- return false;
406
- };
407
- const enforcePropertyCase = createRule$29({
408
- name: "enforce-property-case",
409
- meta: {
410
- type: "suggestion",
411
- docs: { description: "Enforce camelCase for unquoted object property keys" },
412
- messages: { useCamelCase: "Property '{{ name }}' should use camelCase. Use camelCase for object properties, or wrap in quotes if required by an API." },
413
- schema: []
414
- },
415
- defaultOptions: [],
416
- create(context) {
417
- return { Property(node) {
418
- if (node.parent.type !== _typescript_eslint_utils.AST_NODE_TYPES.ObjectExpression) return;
419
- if (isInsideAsConst(node.parent)) return;
420
- if (node.computed) return;
421
- if (node.key.type !== _typescript_eslint_utils.AST_NODE_TYPES.Identifier) return;
422
- const { name } = node.key;
423
- if (SNAKE_CASE_REGEX.test(name) || SCREAMING_SNAKE_CASE_REGEX$1.test(name)) context.report({
424
- node: node.key,
425
- messageId: "useCamelCase",
426
- data: { name }
427
- });
428
- } };
429
- }
430
- });
431
- //#endregion
432
301
  //#region src/rules/enforce-props-suffix.ts
433
302
  const enforcePropsSuffix = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`)({
434
303
  name: "enforce-props-suffix",
@@ -537,7 +406,7 @@ const enforceReadonlyComponentProps = _typescript_eslint_utils.ESLintUtils.RuleC
537
406
  });
538
407
  //#endregion
539
408
  //#region src/rules/enforce-render-naming.ts
540
- const createRule$28 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
409
+ const createRule$24 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
541
410
  const ARRAY_RETURNING_METHODS = new Set([
542
411
  "map",
543
412
  "flatMap",
@@ -586,7 +455,7 @@ function isComponentFunction(node) {
586
455
  if (parent?.type === _typescript_eslint_utils.AST_NODE_TYPES.VariableDeclarator && parent.id.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && isPascalCase$1(parent.id.name)) return true;
587
456
  return false;
588
457
  }
589
- const enforceRenderNaming = createRule$28({
458
+ const enforceRenderNaming = createRule$24({
590
459
  name: "enforce-render-naming",
591
460
  meta: {
592
461
  type: "problem",
@@ -638,7 +507,7 @@ const enforceRenderNaming = createRule$28({
638
507
  });
639
508
  //#endregion
640
509
  //#region src/rules/enforce-service-naming.ts
641
- const createRule$27 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
510
+ const createRule$23 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
642
511
  const BANNED_PREFIXES = {
643
512
  delete: ["remove", "archive"],
644
513
  do: ["submit", "process"],
@@ -649,7 +518,7 @@ const BANNED_PREFIXES = {
649
518
  "patch"
650
519
  ]
651
520
  };
652
- const enforceServiceNaming = createRule$27({
521
+ const enforceServiceNaming = createRule$23({
653
522
  name: "enforce-service-naming",
654
523
  meta: {
655
524
  type: "suggestion",
@@ -687,7 +556,7 @@ const enforceServiceNaming = createRule$27({
687
556
  });
688
557
  //#endregion
689
558
  //#region src/rules/enforce-test-filename.ts
690
- const createRule$26 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
559
+ const createRule$22 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
691
560
  const TEST_GLOBALS = new Set([
692
561
  "describe",
693
562
  "it",
@@ -697,7 +566,7 @@ const TEST_GLOBALS = new Set([
697
566
  "afterEach",
698
567
  "afterAll"
699
568
  ]);
700
- const enforceTestFilename = createRule$26({
569
+ const enforceTestFilename = createRule$22({
701
570
  name: "enforce-test-filename",
702
571
  meta: {
703
572
  type: "suggestion",
@@ -777,7 +646,7 @@ const enforceSortedDestructuring = _typescript_eslint_utils.ESLintUtils.RuleCrea
777
646
  });
778
647
  //#endregion
779
648
  //#region src/rules/enforce-type-declaration-order.ts
780
- const createRule$25 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
649
+ const createRule$21 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
781
650
  function getTypeDeclarationName(node) {
782
651
  if (node.type === _typescript_eslint_utils.AST_NODE_TYPES.TSInterfaceDeclaration && node.id.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier) return {
783
652
  name: node.id.name,
@@ -789,7 +658,7 @@ function getTypeDeclarationName(node) {
789
658
  };
790
659
  return null;
791
660
  }
792
- const enforceTypeDeclarationOrder = createRule$25({
661
+ const enforceTypeDeclarationOrder = createRule$21({
793
662
  name: "enforce-type-declaration-order",
794
663
  meta: {
795
664
  type: "suggestion",
@@ -844,7 +713,7 @@ const enforceTypeDeclarationOrder = createRule$25({
844
713
  });
845
714
  //#endregion
846
715
  //#region src/rules/index-export-only.ts
847
- const createRule$24 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
716
+ const createRule$20 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
848
717
  const isIndexFile = (filename) => getBaseName(filename) === "index";
849
718
  const isAllowedExportNamed = (node) => {
850
719
  if (!node.declaration) return true;
@@ -858,12 +727,16 @@ const isAllowedTopLevel = (node) => {
858
727
  case _typescript_eslint_utils.AST_NODE_TYPES.TSTypeAliasDeclaration:
859
728
  case _typescript_eslint_utils.AST_NODE_TYPES.TSInterfaceDeclaration:
860
729
  case _typescript_eslint_utils.AST_NODE_TYPES.TSImportEqualsDeclaration: return true;
730
+ case _typescript_eslint_utils.AST_NODE_TYPES.ExpressionStatement: {
731
+ const { expression } = node;
732
+ return expression.type === _typescript_eslint_utils.AST_NODE_TYPES.Literal && typeof expression.value === "string";
733
+ }
861
734
  case _typescript_eslint_utils.AST_NODE_TYPES.ExportNamedDeclaration: return isAllowedExportNamed(node);
862
735
  case _typescript_eslint_utils.AST_NODE_TYPES.ExportDefaultDeclaration: return isAllowedExportDefault(node);
863
736
  default: return false;
864
737
  }
865
738
  };
866
- const indexExportOnly = createRule$24({
739
+ const indexExportOnly = createRule$20({
867
740
  name: "index-export-only",
868
741
  meta: {
869
742
  type: "suggestion",
@@ -937,7 +810,7 @@ const jsxNewlineBetweenElements = _typescript_eslint_utils.ESLintUtils.RuleCreat
937
810
  });
938
811
  //#endregion
939
812
  //#region src/rules/jsx-no-data-array.ts
940
- const createRule$23 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
813
+ const createRule$19 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
941
814
  function isObjectLikeElement(node) {
942
815
  if (!node) return false;
943
816
  if (node.type === _typescript_eslint_utils.AST_NODE_TYPES.ObjectExpression) return true;
@@ -950,7 +823,7 @@ function getArrayInitializer(init) {
950
823
  if (init.type === _typescript_eslint_utils.AST_NODE_TYPES.TSAsExpression || init.type === _typescript_eslint_utils.AST_NODE_TYPES.TSSatisfiesExpression) return getArrayInitializer(init.expression);
951
824
  return null;
952
825
  }
953
- const jsxNoDataArray = createRule$23({
826
+ const jsxNoDataArray = createRule$19({
954
827
  name: "jsx-no-data-array",
955
828
  meta: {
956
829
  type: "problem",
@@ -991,7 +864,7 @@ const jsxNoDataArray = createRule$23({
991
864
  });
992
865
  //#endregion
993
866
  //#region src/rules/jsx-no-data-object.ts
994
- const createRule$22 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
867
+ const createRule$18 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
995
868
  function unwrapAssertion(node) {
996
869
  if (!node) return null;
997
870
  if (node.type === _typescript_eslint_utils.AST_NODE_TYPES.TSAsExpression || node.type === _typescript_eslint_utils.AST_NODE_TYPES.TSSatisfiesExpression) return unwrapAssertion(node.expression);
@@ -1021,7 +894,7 @@ function getObjectInitializer(init) {
1021
894
  if (unwrapped.type === _typescript_eslint_utils.AST_NODE_TYPES.ObjectExpression) return unwrapped;
1022
895
  return null;
1023
896
  }
1024
- const jsxNoDataObject = createRule$22({
897
+ const jsxNoDataObject = createRule$18({
1025
898
  name: "jsx-no-data-object",
1026
899
  meta: {
1027
900
  type: "problem",
@@ -1074,14 +947,14 @@ const jsxNoInlineObjectProp = _typescript_eslint_utils.ESLintUtils.RuleCreator((
1074
947
  });
1075
948
  //#endregion
1076
949
  //#region src/rules/jsx-no-newline-single-line-elements.ts
1077
- const createRule$21 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
950
+ const createRule$17 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
1078
951
  function isJSXElementOrFragment(node) {
1079
952
  return node.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXElement || node.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXFragment;
1080
953
  }
1081
954
  function isSingleLine(node) {
1082
955
  return node.loc.start.line === node.loc.end.line;
1083
956
  }
1084
- const jsxNoNewlineSingleLineElements = createRule$21({
957
+ const jsxNoNewlineSingleLineElements = createRule$17({
1085
958
  name: "jsx-no-newline-single-line-elements",
1086
959
  meta: {
1087
960
  type: "layout",
@@ -1180,7 +1053,7 @@ const jsxNoNonComponentFunction = _typescript_eslint_utils.ESLintUtils.RuleCreat
1180
1053
  });
1181
1054
  //#endregion
1182
1055
  //#region src/rules/jsx-no-sub-interface.ts
1183
- const createRule$20 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
1056
+ const createRule$16 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
1184
1057
  const PROPS_WRAPPER_NAMES = new Set([
1185
1058
  "Readonly",
1186
1059
  "Required",
@@ -1212,7 +1085,7 @@ function getDeclarationFromExportWrapper(node) {
1212
1085
  if (node.type === _typescript_eslint_utils.AST_NODE_TYPES.ExportDefaultDeclaration) return node.declaration;
1213
1086
  return node;
1214
1087
  }
1215
- const jsxNoSubInterface = createRule$20({
1088
+ const jsxNoSubInterface = createRule$16({
1216
1089
  name: "jsx-no-sub-interface",
1217
1090
  meta: {
1218
1091
  type: "problem",
@@ -1279,13 +1152,13 @@ const jsxNoSubInterface = createRule$20({
1279
1152
  });
1280
1153
  //#endregion
1281
1154
  //#region src/rules/jsx-no-ternary-null.ts
1282
- const createRule$19 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
1155
+ const createRule$15 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
1283
1156
  function isNullOrUndefined(node) {
1284
1157
  if (node.type === _typescript_eslint_utils.AST_NODE_TYPES.Literal && node.value === null) return true;
1285
1158
  if (node.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && node.name === "undefined") return true;
1286
1159
  return false;
1287
1160
  }
1288
- const jsxNoTernaryNull = createRule$19({
1161
+ const jsxNoTernaryNull = createRule$15({
1289
1162
  name: "jsx-no-ternary-null",
1290
1163
  meta: {
1291
1164
  type: "suggestion",
@@ -1452,7 +1325,7 @@ const jsxSimpleProps = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) =
1452
1325
  });
1453
1326
  //#endregion
1454
1327
  //#region src/rules/jsx-sort-props.ts
1455
- const createRule$18 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
1328
+ const createRule$14 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
1456
1329
  const TYPE_GROUP = {
1457
1330
  STRING: 1,
1458
1331
  HYPHENATED_STRING: 2,
@@ -1535,7 +1408,7 @@ function getSegments(attributes) {
1535
1408
  if (current.length > 0) result.push(current);
1536
1409
  return result;
1537
1410
  }
1538
- const jsxSortProps = createRule$18({
1411
+ const jsxSortProps = createRule$14({
1539
1412
  name: "jsx-sort-props",
1540
1413
  meta: {
1541
1414
  type: "suggestion",
@@ -1590,7 +1463,7 @@ const jsxSpreadPropsLast = _typescript_eslint_utils.ESLintUtils.RuleCreator((nam
1590
1463
  });
1591
1464
  //#endregion
1592
1465
  //#region src/rules/newline-after-multiline-block.ts
1593
- const createRule$17 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
1466
+ const createRule$13 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
1594
1467
  function isImportDeclaration(node) {
1595
1468
  return node.type === _typescript_eslint_utils.AST_NODE_TYPES.ImportDeclaration;
1596
1469
  }
@@ -1615,7 +1488,7 @@ function checkStatements(statements, context) {
1615
1488
  });
1616
1489
  });
1617
1490
  }
1618
- const newlineAfterMultilineBlock = createRule$17({
1491
+ const newlineAfterMultilineBlock = createRule$13({
1619
1492
  name: "newline-after-multiline-block",
1620
1493
  meta: {
1621
1494
  type: "layout",
@@ -1801,12 +1674,12 @@ const noEnvFallback = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) =>
1801
1674
  });
1802
1675
  //#endregion
1803
1676
  //#region src/rules/no-ghost-wrapper.ts
1804
- const createRule$16 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
1677
+ const createRule$12 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
1805
1678
  const GHOST_TAGS = new Set(["div", "span"]);
1806
1679
  function isKeyAttribute(attribute) {
1807
1680
  return attribute.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXAttribute && attribute.name.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXIdentifier && attribute.name.name === "key";
1808
1681
  }
1809
- const noGhostWrapper = createRule$16({
1682
+ const noGhostWrapper = createRule$12({
1810
1683
  name: "no-ghost-wrapper",
1811
1684
  meta: {
1812
1685
  type: "problem",
@@ -1903,82 +1776,8 @@ const noHelperFunctionInTest = _typescript_eslint_utils.ESLintUtils.RuleCreator(
1903
1776
  }
1904
1777
  });
1905
1778
  //#endregion
1906
- //#region src/rules/no-inline-default-export.ts
1907
- const noInlineDefaultExport = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`)({
1908
- name: "no-inline-default-export",
1909
- meta: {
1910
- type: "suggestion",
1911
- docs: { description: "Disallow inline exports. Prefer declaring first, then exporting separately." },
1912
- messages: {
1913
- noInlineDefaultExport: "Avoid inline default export. Declare the {{type}} first, then export it separately: `export default {{name}};`",
1914
- noAnonymousDefaultExport: "Avoid anonymous default export. Declare a named {{type}} first, then export it separately.",
1915
- noInlineNamedExport: "Avoid inline named export. Declare the {{type}} first, then export it separately: `export { {{name}} };`"
1916
- },
1917
- schema: []
1918
- },
1919
- defaultOptions: [],
1920
- create(context) {
1921
- return {
1922
- ExportDefaultDeclaration(node) {
1923
- const { declaration } = node;
1924
- if (declaration.type === _typescript_eslint_utils.AST_NODE_TYPES.FunctionDeclaration) if (declaration.id) context.report({
1925
- node,
1926
- messageId: "noInlineDefaultExport",
1927
- data: {
1928
- type: "function",
1929
- name: declaration.id.name
1930
- }
1931
- });
1932
- else context.report({
1933
- node,
1934
- messageId: "noAnonymousDefaultExport",
1935
- data: { type: "function" }
1936
- });
1937
- if (declaration.type === _typescript_eslint_utils.AST_NODE_TYPES.ClassDeclaration) if (declaration.id) context.report({
1938
- node,
1939
- messageId: "noInlineDefaultExport",
1940
- data: {
1941
- type: "class",
1942
- name: declaration.id.name
1943
- }
1944
- });
1945
- else context.report({
1946
- node,
1947
- messageId: "noAnonymousDefaultExport",
1948
- data: { type: "class" }
1949
- });
1950
- if (declaration.type === _typescript_eslint_utils.AST_NODE_TYPES.ArrowFunctionExpression || declaration.type === _typescript_eslint_utils.AST_NODE_TYPES.FunctionExpression) context.report({
1951
- node,
1952
- messageId: "noAnonymousDefaultExport",
1953
- data: { type: "function" }
1954
- });
1955
- },
1956
- ExportNamedDeclaration(node) {
1957
- const { declaration } = node;
1958
- if (!declaration) return;
1959
- if (declaration.type === _typescript_eslint_utils.AST_NODE_TYPES.FunctionDeclaration && declaration.id) context.report({
1960
- node,
1961
- messageId: "noInlineNamedExport",
1962
- data: {
1963
- type: "function",
1964
- name: declaration.id.name
1965
- }
1966
- });
1967
- if (declaration.type === _typescript_eslint_utils.AST_NODE_TYPES.ClassDeclaration && declaration.id) context.report({
1968
- node,
1969
- messageId: "noInlineNamedExport",
1970
- data: {
1971
- type: "class",
1972
- name: declaration.id.name
1973
- }
1974
- });
1975
- }
1976
- };
1977
- }
1978
- });
1979
- //#endregion
1980
1779
  //#region src/rules/no-inline-nested-object.ts
1981
- const createRule$15 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
1780
+ const createRule$11 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
1982
1781
  function isObjectOrArray(node) {
1983
1782
  return node.type === _typescript_eslint_utils.AST_NODE_TYPES.ObjectExpression || node.type === _typescript_eslint_utils.AST_NODE_TYPES.ArrayExpression || node.type === _typescript_eslint_utils.AST_NODE_TYPES.TSAsExpression;
1984
1783
  }
@@ -2000,7 +1799,7 @@ function containsNestedStructure(node) {
2000
1799
  return isNestedStructure(el);
2001
1800
  });
2002
1801
  }
2003
- const noInlineNestedObject = createRule$15({
1802
+ const noInlineNestedObject = createRule$11({
2004
1803
  name: "no-inline-nested-object",
2005
1804
  meta: {
2006
1805
  type: "layout",
@@ -2042,13 +1841,13 @@ const noInlineNestedObject = createRule$15({
2042
1841
  });
2043
1842
  //#endregion
2044
1843
  //#region src/rules/no-inline-return-properties.ts
2045
- const createRule$14 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
1844
+ const createRule$10 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
2046
1845
  const isShorthandProperty = (property) => {
2047
1846
  if (property.type === _typescript_eslint_utils.AST_NODE_TYPES.SpreadElement) return true;
2048
1847
  if (property.type !== _typescript_eslint_utils.AST_NODE_TYPES.Property) return false;
2049
1848
  return property.shorthand;
2050
1849
  };
2051
- const noInlineReturnProperties = createRule$14({
1850
+ const noInlineReturnProperties = createRule$10({
2052
1851
  name: "no-inline-return-properties",
2053
1852
  meta: {
2054
1853
  type: "suggestion",
@@ -2077,9 +1876,9 @@ const noInlineReturnProperties = createRule$14({
2077
1876
  });
2078
1877
  //#endregion
2079
1878
  //#region src/rules/no-inline-type-import.ts
2080
- const createRule$13 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
1879
+ const createRule$9 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
2081
1880
  const isInlineTypeSpecifier = (specifier) => specifier.type === _typescript_eslint_utils.AST_NODE_TYPES.ImportSpecifier && specifier.importKind === "type";
2082
- const noInlineTypeImport = createRule$13({
1881
+ const noInlineTypeImport = createRule$9({
2083
1882
  name: "no-inline-type-import",
2084
1883
  meta: {
2085
1884
  type: "suggestion",
@@ -2121,7 +1920,7 @@ const noInlineTypeImport = createRule$13({
2121
1920
  });
2122
1921
  //#endregion
2123
1922
  //#region src/rules/no-lazy-identifiers.ts
2124
- const createRule$12 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
1923
+ const createRule$8 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
2125
1924
  const KEYBOARD_ROWS = [
2126
1925
  "qwertyuiop",
2127
1926
  "asdfghjkl",
@@ -2152,7 +1951,7 @@ const isLazyIdentifier = (name) => {
2152
1951
  if (hasKeyboardSequence(name)) return true;
2153
1952
  return false;
2154
1953
  };
2155
- const noLazyIdentifiers = createRule$12({
1954
+ const noLazyIdentifiers = createRule$8({
2156
1955
  name: "no-lazy-identifiers",
2157
1956
  meta: {
2158
1957
  type: "problem",
@@ -2271,7 +2070,7 @@ const noLogicInParams = _typescript_eslint_utils.ESLintUtils.RuleCreator((name)
2271
2070
  });
2272
2071
  //#endregion
2273
2072
  //#region src/rules/no-misleading-constant-case.ts
2274
- const createRule$11 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
2073
+ const createRule$7 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
2275
2074
  const SCREAMING_SNAKE_CASE_REGEX = /^[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)*$/;
2276
2075
  const isAsConstAssertion = (node) => node.type === _typescript_eslint_utils.AST_NODE_TYPES.TSAsExpression && node.typeAnnotation.type === _typescript_eslint_utils.AST_NODE_TYPES.TSTypeReference && node.typeAnnotation.typeName.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && node.typeAnnotation.typeName.name === "const";
2277
2076
  const isStaticValue = (init) => {
@@ -2289,7 +2088,7 @@ const isGlobalScope = (node) => {
2289
2088
  if (parent.type === _typescript_eslint_utils.AST_NODE_TYPES.ExportNamedDeclaration && parent.parent?.type === _typescript_eslint_utils.AST_NODE_TYPES.Program) return true;
2290
2089
  return false;
2291
2090
  };
2292
- const noMisleadingConstantCase = createRule$11({
2091
+ const noMisleadingConstantCase = createRule$7({
2293
2092
  name: "no-misleading-constant-case",
2294
2093
  meta: {
2295
2094
  type: "suggestion",
@@ -2377,82 +2176,6 @@ const noNestedInterfaceDeclaration = _typescript_eslint_utils.ESLintUtils.RuleCr
2377
2176
  }
2378
2177
  });
2379
2178
  //#endregion
2380
- //#region src/rules/no-nested-ternary.ts
2381
- const noNestedTernary = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`)({
2382
- name: "no-nested-ternary",
2383
- meta: {
2384
- type: "suggestion",
2385
- docs: { description: "Disallow nested ternary expressions" },
2386
- messages: { noNestedTernary: "Nested ternary expressions are not allowed. Use a function with early returns instead." },
2387
- schema: []
2388
- },
2389
- defaultOptions: [],
2390
- create(context) {
2391
- return { ConditionalExpression(node) {
2392
- const { consequent, alternate } = node;
2393
- if (consequent.type === _typescript_eslint_utils.AST_NODE_TYPES.ConditionalExpression) context.report({
2394
- node: consequent,
2395
- messageId: "noNestedTernary"
2396
- });
2397
- if (alternate.type === _typescript_eslint_utils.AST_NODE_TYPES.ConditionalExpression) context.report({
2398
- node: alternate,
2399
- messageId: "noNestedTernary"
2400
- });
2401
- } };
2402
- }
2403
- });
2404
- //#endregion
2405
- //#region src/rules/no-redundant-fragment.ts
2406
- const createRule$10 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
2407
- function isFragmentName(name) {
2408
- if (name.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXIdentifier && name.name === "Fragment") return true;
2409
- if (name.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXMemberExpression && name.object.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXIdentifier && name.object.name === "React" && name.property.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXIdentifier && name.property.name === "Fragment") return true;
2410
- return false;
2411
- }
2412
- function hasKeyAttribute(attributes) {
2413
- return attributes.some((attribute) => attribute.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXAttribute && attribute.name.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXIdentifier && attribute.name.name === "key");
2414
- }
2415
- function countMeaningfulChildren(children) {
2416
- return children.filter((child) => {
2417
- if (child.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXText) return child.value.trim() !== "";
2418
- return true;
2419
- }).length;
2420
- }
2421
- const noRedundantFragment = createRule$10({
2422
- name: "no-redundant-fragment",
2423
- meta: {
2424
- type: "problem",
2425
- docs: { description: "Disallow Fragments that wrap zero or one child (unless a key prop is needed)" },
2426
- schema: [],
2427
- messages: { redundantFragment: "Fragment is redundant when wrapping {{ count }} child. Remove the Fragment or replace it with the child directly." }
2428
- },
2429
- defaultOptions: [],
2430
- create(context) {
2431
- if (!isJsxFile(context.filename)) return {};
2432
- return {
2433
- JSXFragment(node) {
2434
- const count = countMeaningfulChildren(node.children);
2435
- if (count <= 1) context.report({
2436
- node,
2437
- messageId: "redundantFragment",
2438
- data: { count: String(count) }
2439
- });
2440
- },
2441
- JSXElement(node) {
2442
- const opening = node.openingElement;
2443
- if (!isFragmentName(opening.name)) return;
2444
- if (hasKeyAttribute(opening.attributes)) return;
2445
- const count = countMeaningfulChildren(node.children);
2446
- if (count <= 1) context.report({
2447
- node,
2448
- messageId: "redundantFragment",
2449
- data: { count: String(count) }
2450
- });
2451
- }
2452
- };
2453
- }
2454
- });
2455
- //#endregion
2456
2179
  //#region src/rules/no-relative-imports.ts
2457
2180
  const noRelativeImports = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`)({
2458
2181
  name: "no-relative-imports",
@@ -2487,88 +2210,6 @@ const noRelativeImports = _typescript_eslint_utils.ESLintUtils.RuleCreator((name
2487
2210
  }
2488
2211
  });
2489
2212
  //#endregion
2490
- //#region src/rules/no-single-char-variables.ts
2491
- const createRule$9 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
2492
- const ALLOWED_IN_FOR_LOOPS = new Set([
2493
- "i",
2494
- "j",
2495
- "k",
2496
- "n"
2497
- ]);
2498
- const ALLOWED_UNDERSCORE = "_";
2499
- const isForLoopInit = (node) => {
2500
- let current = node;
2501
- while (current) {
2502
- const parentNode = current.parent;
2503
- if (!parentNode) return false;
2504
- if (parentNode.type === _typescript_eslint_utils.AST_NODE_TYPES.ForStatement) {
2505
- const { init } = parentNode;
2506
- if (init && init === current) return true;
2507
- }
2508
- current = parentNode;
2509
- }
2510
- return false;
2511
- };
2512
- const isAllowedInContext = (name, node) => {
2513
- if (name === ALLOWED_UNDERSCORE) return true;
2514
- if (ALLOWED_IN_FOR_LOOPS.has(name) && isForLoopInit(node)) return true;
2515
- return false;
2516
- };
2517
- const noSingleCharVariables = createRule$9({
2518
- name: "no-single-char-variables",
2519
- meta: {
2520
- type: "suggestion",
2521
- docs: { description: "Disallow single character variable and parameter names for better code readability" },
2522
- messages: { noSingleChar: "Avoid single character variable name '{{name}}'. Use a descriptive name that clearly indicates the purpose." },
2523
- schema: []
2524
- },
2525
- defaultOptions: [],
2526
- create(context) {
2527
- const checkIdentifier = (node, declarationNode) => {
2528
- const { name } = node;
2529
- if (name.length !== 1) return;
2530
- if (isAllowedInContext(name, declarationNode)) return;
2531
- context.report({
2532
- node,
2533
- messageId: "noSingleChar",
2534
- data: { name }
2535
- });
2536
- };
2537
- const checkPattern = (pattern, declarationNode) => {
2538
- if (pattern.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier) checkIdentifier(pattern, declarationNode);
2539
- else if (pattern.type === _typescript_eslint_utils.AST_NODE_TYPES.ObjectPattern) pattern.properties.forEach((prop) => {
2540
- if (prop.type === _typescript_eslint_utils.AST_NODE_TYPES.Property && prop.value.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier) checkIdentifier(prop.value, declarationNode);
2541
- else if (prop.type === _typescript_eslint_utils.AST_NODE_TYPES.RestElement && prop.argument.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier) checkIdentifier(prop.argument, declarationNode);
2542
- });
2543
- else if (pattern.type === _typescript_eslint_utils.AST_NODE_TYPES.ArrayPattern) pattern.elements.forEach((element) => {
2544
- if (element?.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier) checkIdentifier(element, declarationNode);
2545
- else if (element?.type === _typescript_eslint_utils.AST_NODE_TYPES.RestElement && element.argument.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier) checkIdentifier(element.argument, declarationNode);
2546
- });
2547
- else if (pattern.type === _typescript_eslint_utils.AST_NODE_TYPES.AssignmentPattern && pattern.left.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier) checkIdentifier(pattern.left, declarationNode);
2548
- else if (pattern.type === _typescript_eslint_utils.AST_NODE_TYPES.RestElement && pattern.argument.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier) checkIdentifier(pattern.argument, declarationNode);
2549
- };
2550
- return {
2551
- VariableDeclarator(node) {
2552
- checkPattern(node.id, node);
2553
- },
2554
- FunctionDeclaration(node) {
2555
- if (node.id) checkIdentifier(node.id, node);
2556
- node.params.forEach((param) => checkPattern(param, node));
2557
- },
2558
- FunctionExpression(node) {
2559
- if (node.id) checkIdentifier(node.id, node);
2560
- node.params.forEach((param) => checkPattern(param, node));
2561
- },
2562
- ArrowFunctionExpression(node) {
2563
- node.params.forEach((param) => checkPattern(param, node));
2564
- },
2565
- CatchClause(node) {
2566
- if (node.param) checkPattern(node.param, node);
2567
- }
2568
- };
2569
- }
2570
- });
2571
- //#endregion
2572
2213
  //#region src/rules/prefer-async-await.ts
2573
2214
  const preferAsyncAwait = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`)({
2574
2215
  name: "prefer-async-await",
@@ -2635,61 +2276,6 @@ const preferDestructuringParams = _typescript_eslint_utils.ESLintUtils.RuleCreat
2635
2276
  }
2636
2277
  });
2637
2278
  //#endregion
2638
- //#region src/rules/prefer-function-declaration.ts
2639
- const createRule$8 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
2640
- const isTsFile = (filename) => filename.endsWith(".ts") && !filename.endsWith(".d.ts");
2641
- const isCallbackContext = (node) => {
2642
- const { parent } = node;
2643
- if (!parent) return false;
2644
- if (parent.type === _typescript_eslint_utils.AST_NODE_TYPES.CallExpression && parent.arguments.includes(node)) return true;
2645
- if (parent.type === _typescript_eslint_utils.AST_NODE_TYPES.NewExpression && parent.arguments.includes(node)) return true;
2646
- if (parent.type === _typescript_eslint_utils.AST_NODE_TYPES.ReturnStatement) return true;
2647
- if (parent.type === _typescript_eslint_utils.AST_NODE_TYPES.Property) return true;
2648
- if (parent.type === _typescript_eslint_utils.AST_NODE_TYPES.ArrayExpression) return true;
2649
- if (parent.type === _typescript_eslint_utils.AST_NODE_TYPES.ConditionalExpression) return true;
2650
- if (parent.type === _typescript_eslint_utils.AST_NODE_TYPES.LogicalExpression) return true;
2651
- if (parent.type === _typescript_eslint_utils.AST_NODE_TYPES.AssignmentExpression && parent.left !== node) return true;
2652
- return false;
2653
- };
2654
- const preferFunctionDeclaration = createRule$8({
2655
- name: "prefer-function-declaration",
2656
- meta: {
2657
- type: "suggestion",
2658
- docs: { description: "Enforce function declarations over arrow functions assigned to variables in .ts files for better readability and hoisting" },
2659
- messages: {
2660
- preferDeclaration: "Use function declaration instead of arrow function. Replace 'const {{name}} = () => ...' with 'function {{name}}() ...'",
2661
- preferDeclarationExpr: "Use function declaration instead of function expression. Replace 'const {{name}} = function() ...' with 'function {{name}}() ...'"
2662
- },
2663
- schema: []
2664
- },
2665
- defaultOptions: [],
2666
- create(context) {
2667
- const { filename } = context;
2668
- if (!isTsFile(filename)) return {};
2669
- return { VariableDeclarator(node) {
2670
- if (node.id.type !== _typescript_eslint_utils.AST_NODE_TYPES.Identifier) return;
2671
- const { init } = node;
2672
- if (!init) return;
2673
- if (init.type === _typescript_eslint_utils.AST_NODE_TYPES.ArrowFunctionExpression) {
2674
- if (isCallbackContext(init)) return;
2675
- context.report({
2676
- node: init,
2677
- messageId: "preferDeclaration",
2678
- data: { name: node.id.name }
2679
- });
2680
- }
2681
- if (init.type === _typescript_eslint_utils.AST_NODE_TYPES.FunctionExpression) {
2682
- if (isCallbackContext(init)) return;
2683
- context.report({
2684
- node: init,
2685
- messageId: "preferDeclarationExpr",
2686
- data: { name: node.id.name }
2687
- });
2688
- }
2689
- } };
2690
- }
2691
- });
2692
- //#endregion
2693
2279
  //#region src/rules/prefer-guard-clause.ts
2694
2280
  const preferGuardClause = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`)({
2695
2281
  name: "prefer-guard-clause",
@@ -2766,6 +2352,7 @@ const preferImportType = _typescript_eslint_utils.ESLintUtils.RuleCreator((name)
2766
2352
  switch (parent.type) {
2767
2353
  case _typescript_eslint_utils.AST_NODE_TYPES.CallExpression:
2768
2354
  case _typescript_eslint_utils.AST_NODE_TYPES.NewExpression:
2355
+ case _typescript_eslint_utils.AST_NODE_TYPES.JSXMemberExpression:
2769
2356
  case _typescript_eslint_utils.AST_NODE_TYPES.JSXOpeningElement:
2770
2357
  case _typescript_eslint_utils.AST_NODE_TYPES.JSXClosingElement:
2771
2358
  case _typescript_eslint_utils.AST_NODE_TYPES.MemberExpression:
@@ -2819,12 +2406,12 @@ const preferImportType = _typescript_eslint_utils.ESLintUtils.RuleCreator((name)
2819
2406
  });
2820
2407
  //#endregion
2821
2408
  //#region src/rules/prefer-inline-literal-union.ts
2822
- const createRule$7 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
2409
+ const createRule$6 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
2823
2410
  function isLiteralUnionType(node) {
2824
2411
  if (node.type !== _typescript_eslint_utils.AST_NODE_TYPES.TSUnionType) return false;
2825
2412
  return node.types.every((member) => member.type === _typescript_eslint_utils.AST_NODE_TYPES.TSLiteralType || member.type === _typescript_eslint_utils.AST_NODE_TYPES.TSNullKeyword || member.type === _typescript_eslint_utils.AST_NODE_TYPES.TSUndefinedKeyword);
2826
2413
  }
2827
- const preferInlineLiteralUnion = createRule$7({
2414
+ const preferInlineLiteralUnion = createRule$6({
2828
2415
  name: "prefer-inline-literal-union",
2829
2416
  meta: {
2830
2417
  type: "suggestion",
@@ -2862,65 +2449,6 @@ const preferInlineLiteralUnion = createRule$7({
2862
2449
  }
2863
2450
  });
2864
2451
  //#endregion
2865
- //#region src/rules/prefer-inline-type-export.ts
2866
- const createRule$6 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
2867
- const isTypeDeclaration = (node) => node.type === _typescript_eslint_utils.AST_NODE_TYPES.TSInterfaceDeclaration || node.type === _typescript_eslint_utils.AST_NODE_TYPES.TSTypeAliasDeclaration;
2868
- const preferInlineTypeExport = createRule$6({
2869
- name: "prefer-inline-type-export",
2870
- meta: {
2871
- type: "suggestion",
2872
- docs: { description: "Require type and interface declarations to be exported inline rather than via a separate export statement" },
2873
- fixable: "code",
2874
- messages: { preferInlineExport: "Export '{{name}}' inline at its declaration instead of using a separate export statement." },
2875
- schema: []
2876
- },
2877
- defaultOptions: [],
2878
- create(context) {
2879
- const typeDeclarations = /* @__PURE__ */ new Map();
2880
- function collectDeclaration(node) {
2881
- if (node.parent.type !== _typescript_eslint_utils.AST_NODE_TYPES.ExportNamedDeclaration) typeDeclarations.set(node.id.name, node);
2882
- }
2883
- function reportSpecifier(specifier, statement, declarationNode) {
2884
- if (specifier.local.type !== _typescript_eslint_utils.AST_NODE_TYPES.Identifier) return;
2885
- const { name } = specifier.local;
2886
- context.report({
2887
- node: specifier,
2888
- messageId: "preferInlineExport",
2889
- data: { name },
2890
- fix(fixer) {
2891
- const { sourceCode } = context;
2892
- const declarationToken = sourceCode.getFirstToken(declarationNode);
2893
- if (!declarationToken) return null;
2894
- if (statement.specifiers.length === 1) {
2895
- const nextToken = sourceCode.getTokenAfter(statement);
2896
- const end = nextToken ? nextToken.range[0] : statement.range[1];
2897
- return [fixer.insertTextBefore(declarationToken, "export "), fixer.removeRange([statement.range[0], end])];
2898
- }
2899
- const tokenBefore = sourceCode.getTokenBefore(specifier);
2900
- const tokenAfter = sourceCode.getTokenAfter(specifier);
2901
- if (!tokenBefore || !tokenAfter) return null;
2902
- const removalRange = statement.specifiers.at(-1) === specifier && tokenBefore.value === "," ? [tokenBefore.range[0], specifier.range[1]] : [specifier.range[0], tokenAfter.range[1]];
2903
- return [fixer.insertTextBefore(declarationToken, "export "), fixer.removeRange(removalRange)];
2904
- }
2905
- });
2906
- }
2907
- return { Program(node) {
2908
- node.body.forEach((statement) => {
2909
- if (statement.type === _typescript_eslint_utils.AST_NODE_TYPES.TSInterfaceDeclaration || statement.type === _typescript_eslint_utils.AST_NODE_TYPES.TSTypeAliasDeclaration) collectDeclaration(statement);
2910
- });
2911
- node.body.forEach((statement) => {
2912
- if (statement.type !== _typescript_eslint_utils.AST_NODE_TYPES.ExportNamedDeclaration || statement.declaration !== null) return;
2913
- statement.specifiers.forEach((specifier) => {
2914
- if (specifier.local.type !== _typescript_eslint_utils.AST_NODE_TYPES.Identifier) return;
2915
- const declarationNode = typeDeclarations.get(specifier.local.name);
2916
- if (!declarationNode || !isTypeDeclaration(declarationNode)) return;
2917
- reportSpecifier(specifier, statement, declarationNode);
2918
- });
2919
- });
2920
- } };
2921
- }
2922
- });
2923
- //#endregion
2924
2452
  //#region src/rules/prefer-interface-for-component-props.ts
2925
2453
  const preferInterfaceForComponentProps = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`)({
2926
2454
  name: "prefer-interface-for-component-props",
@@ -3021,64 +2549,6 @@ const preferInterfaceOverInlineTypes = _typescript_eslint_utils.ESLintUtils.Rule
3021
2549
  }
3022
2550
  });
3023
2551
  //#endregion
3024
- //#region src/rules/prefer-jsx-template-literals.ts
3025
- const preferJSXTemplateLiterals = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`)({
3026
- name: "prefer-jsx-template-literals",
3027
- meta: {
3028
- type: "suggestion",
3029
- docs: { description: "Enforce using template literals instead of mixing text and JSX expressions" },
3030
- fixable: "code",
3031
- schema: [],
3032
- messages: { preferTemplate: "Use template literal instead of mixing text with JSX expressions" }
3033
- },
3034
- defaultOptions: [],
3035
- create(context) {
3036
- if (!isJsxFile(context.filename)) return {};
3037
- function handleTextBeforeExpression(textNode, exprNode) {
3038
- const textValue = textNode.value;
3039
- const trimmedText = textValue.trim();
3040
- if (!trimmedText) return;
3041
- const hasTextContent = trimmedText.length > 0 && textValue !== trimmedText;
3042
- const hasNoTrailingSpace = trimmedText.length > 0 && /\S$/.test(textValue);
3043
- if (!hasTextContent && !hasNoTrailingSpace) return;
3044
- context.report({
3045
- node: textNode,
3046
- messageId: "preferTemplate",
3047
- fix(fixer) {
3048
- const templateLiteral = `{\`${textValue.trimEnd()}\${${context.sourceCode.getText(exprNode.expression)}}\`}`;
3049
- return [fixer.replaceText(textNode, templateLiteral), fixer.remove(exprNode)];
3050
- }
3051
- });
3052
- }
3053
- function handleExpressionBeforeText(exprNode, textNode) {
3054
- const textValue = textNode.value;
3055
- const trimmedText = textValue.trim();
3056
- if (!trimmedText) return;
3057
- if (!/^\S/.test(trimmedText)) return;
3058
- context.report({
3059
- node: textNode,
3060
- messageId: "preferTemplate",
3061
- fix(fixer) {
3062
- const templateLiteral = `{\`\${${context.sourceCode.getText(exprNode.expression)}}${textValue.trim()}\`}`;
3063
- return [fixer.replaceText(exprNode, templateLiteral), fixer.remove(textNode)];
3064
- }
3065
- });
3066
- }
3067
- function checkJSXElement(node) {
3068
- const { children } = node;
3069
- if (children.length < 2) return;
3070
- for (let i = 0; i < children.length - 1; i += 1) {
3071
- const child = children[i];
3072
- const nextChild = children[i + 1];
3073
- if (!child || !nextChild) return;
3074
- if (child.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXText && nextChild.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXExpressionContainer) handleTextBeforeExpression(child, nextChild);
3075
- else if (child.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXExpressionContainer && nextChild.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXText) handleExpressionBeforeText(child, nextChild);
3076
- }
3077
- }
3078
- return { JSXElement: checkJSXElement };
3079
- }
3080
- });
3081
- //#endregion
3082
2552
  //#region src/rules/prefer-named-param-types.ts
3083
2553
  const createRule$5 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
3084
2554
  const returnsJsx = (node) => {
@@ -3141,7 +2611,7 @@ const preferPropsWithChildren = _typescript_eslint_utils.ESLintUtils.RuleCreator
3141
2611
  type: "suggestion",
3142
2612
  docs: { description: "Prefer PropsWithChildren<T> over manually declaring children: ReactNode in component props" },
3143
2613
  schema: [],
3144
- messages: { usePropsWithChildren: "Use 'PropsWithChildren<T>' instead of manually declaring 'children: ReactNode'." }
2614
+ messages: { usePropsWithChildren: "Use 'PropsWithChildren<T>' instead of manually declaring 'children?: ReactNode'." }
3145
2615
  },
3146
2616
  defaultOptions: [],
3147
2617
  create(context) {
@@ -3160,7 +2630,7 @@ const preferPropsWithChildren = _typescript_eslint_utils.ESLintUtils.RuleCreator
3160
2630
  if (member.key.type !== _typescript_eslint_utils.AST_NODE_TYPES.Identifier) continue;
3161
2631
  if (member.key.name !== "children") continue;
3162
2632
  if (!member.typeAnnotation) continue;
3163
- if (isReactNodeType(member.typeAnnotation.typeAnnotation)) return member;
2633
+ if (member.optional && isReactNodeType(member.typeAnnotation.typeAnnotation)) return member;
3164
2634
  }
3165
2635
  }
3166
2636
  return {
@@ -3295,65 +2765,6 @@ const preferReactImportTypes = _typescript_eslint_utils.ESLintUtils.RuleCreator(
3295
2765
  }
3296
2766
  });
3297
2767
  //#endregion
3298
- //#region src/rules/react-props-destructure.ts
3299
- const reactPropsDestructure = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`)({
3300
- name: "react-props-destructure",
3301
- meta: {
3302
- type: "suggestion",
3303
- docs: { description: "Enforce destructuring props inside React component body instead of parameters" },
3304
- fixable: void 0,
3305
- schema: [],
3306
- messages: { noParameterDestructuring: "Destructure props inside component body instead of parameters. Use 'const { {{properties}} } = props;'" }
3307
- },
3308
- defaultOptions: [],
3309
- create(context) {
3310
- if (!isJsxFile(context.filename)) return {};
3311
- function hasJSXInConditional(node) {
3312
- return node.consequent.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXElement || node.consequent.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXFragment || node.alternate.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXElement || node.alternate.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXFragment;
3313
- }
3314
- function hasJSXInLogical(node) {
3315
- return node.right.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXElement || node.right.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXFragment;
3316
- }
3317
- function hasJSXReturn(block) {
3318
- return block.body.some((stmt) => {
3319
- if (stmt.type === _typescript_eslint_utils.AST_NODE_TYPES.ReturnStatement && stmt.argument) return stmt.argument.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXElement || stmt.argument.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXFragment || stmt.argument.type === _typescript_eslint_utils.AST_NODE_TYPES.ConditionalExpression && hasJSXInConditional(stmt.argument) || stmt.argument.type === _typescript_eslint_utils.AST_NODE_TYPES.LogicalExpression && hasJSXInLogical(stmt.argument);
3320
- return false;
3321
- });
3322
- }
3323
- function isReactComponent(node) {
3324
- if (node.type === _typescript_eslint_utils.AST_NODE_TYPES.ArrowFunctionExpression) {
3325
- if (node.body.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXElement || node.body.type === _typescript_eslint_utils.AST_NODE_TYPES.JSXFragment) return true;
3326
- if (node.body.type === _typescript_eslint_utils.AST_NODE_TYPES.BlockStatement) return hasJSXReturn(node.body);
3327
- } else if (node.type === _typescript_eslint_utils.AST_NODE_TYPES.FunctionExpression || node.type === _typescript_eslint_utils.AST_NODE_TYPES.FunctionDeclaration) {
3328
- if (node.body && node.body.type === _typescript_eslint_utils.AST_NODE_TYPES.BlockStatement) return hasJSXReturn(node.body);
3329
- }
3330
- return false;
3331
- }
3332
- function checkFunction(node) {
3333
- if (!isReactComponent(node)) return;
3334
- if (node.params.length !== 1) return;
3335
- const param = node.params[0];
3336
- if (param.type === _typescript_eslint_utils.AST_NODE_TYPES.ObjectPattern) {
3337
- const properties = param.properties.filter((prop) => prop.type === _typescript_eslint_utils.AST_NODE_TYPES.Property).map((prop) => {
3338
- if (prop.key.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier) return prop.key.name;
3339
- return null;
3340
- }).filter((name) => name !== null);
3341
- if (properties.length === 0) return;
3342
- context.report({
3343
- node: param,
3344
- messageId: "noParameterDestructuring",
3345
- data: { properties: properties.join(", ") }
3346
- });
3347
- }
3348
- }
3349
- return {
3350
- ArrowFunctionExpression: checkFunction,
3351
- FunctionExpression: checkFunction,
3352
- FunctionDeclaration: checkFunction
3353
- };
3354
- }
3355
- });
3356
- //#endregion
3357
2768
  //#region src/rules/require-explicit-return-type.ts
3358
2769
  const createRule$4 = _typescript_eslint_utils.ESLintUtils.RuleCreator((name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`);
3359
2770
  const isReactComponent = (node) => {
@@ -3530,21 +2941,29 @@ const GROUP_NAMES = [
3530
2941
  "",
3531
2942
  "side-effect",
3532
2943
  "builtin",
2944
+ "builtin type",
3533
2945
  "external",
2946
+ "external type",
3534
2947
  "internal alias",
3535
- "relative"
2948
+ "internal alias type",
2949
+ "parent relative",
2950
+ "parent relative type",
2951
+ "relative",
2952
+ "relative type"
3536
2953
  ];
3537
- function getImportGroup(node) {
3538
- const source = node.source.value;
3539
- if (node.specifiers.length === 0 && node.importKind !== "type") return 1;
3540
- if (source.startsWith("node:") || NODE_BUILTINS.has(source.split("/")[0])) return 2;
3541
- if (source.startsWith("@/") || source.startsWith("~/") || source.startsWith("#")) return 4;
3542
- if (source.startsWith(".")) return 5;
3543
- return 3;
3544
- }
3545
2954
  function isTypeOnlyImport(node) {
3546
2955
  return node.importKind === "type" && node.specifiers.length > 0;
3547
2956
  }
2957
+ function getImportGroup(node) {
2958
+ const source = node.source.value;
2959
+ const isType = isTypeOnlyImport(node);
2960
+ if (node.specifiers.length === 0 && !isType) return 1;
2961
+ if (source.startsWith("node:") || NODE_BUILTINS.has(source.split("/")[0])) return isType ? 3 : 2;
2962
+ if (source.startsWith("@/") || source.startsWith("~/") || source.startsWith("#")) return isType ? 7 : 6;
2963
+ if (source.startsWith("../")) return isType ? 9 : 8;
2964
+ if (source.startsWith(".")) return isType ? 11 : 10;
2965
+ return isType ? 5 : 4;
2966
+ }
3548
2967
  const sortImports = createRule$2({
3549
2968
  name: "sort-imports",
3550
2969
  meta: {
@@ -3552,14 +2971,43 @@ const sortImports = createRule$2({
3552
2971
  docs: { description: "Enforce a consistent ordering of import groups" },
3553
2972
  fixable: "code",
3554
2973
  schema: [],
3555
- messages: { unsortedImports: "Import group '{{current}}' should come before '{{previous}}'. Expected order: side-effect, builtin, external, internal alias, relative." }
2974
+ messages: {
2975
+ unsortedImports: "Import group '{{current}}' should come before '{{previous}}'. Expected order: side-effect, builtin, external, internal alias, parent relative, relative — each followed by its type imports.",
2976
+ missingBlankLine: "Expected a blank line before '{{current}}' imports (new group after '{{previous}}')."
2977
+ }
3556
2978
  },
3557
2979
  defaultOptions: [],
3558
2980
  create(context) {
2981
+ function getMainGroup(group) {
2982
+ if (group === 1) return 1;
2983
+ return Math.floor((group - 2) / 2) + 2;
2984
+ }
2985
+ function checkBlankLines(imports) {
2986
+ const { sourceCode } = context;
2987
+ for (let i = 1; i < imports.length; i++) {
2988
+ const prev = imports[i - 1];
2989
+ const curr = imports[i];
2990
+ if (getMainGroup(prev.group) === getMainGroup(curr.group)) continue;
2991
+ if (curr.node.loc.start.line - prev.node.loc.end.line > 1) continue;
2992
+ context.report({
2993
+ node: curr.node,
2994
+ messageId: "missingBlankLine",
2995
+ data: {
2996
+ current: GROUP_NAMES[curr.group],
2997
+ previous: GROUP_NAMES[prev.group]
2998
+ },
2999
+ fix(fixer) {
3000
+ const firstToken = sourceCode.getFirstToken(curr.node);
3001
+ if (!firstToken) return null;
3002
+ return fixer.insertTextBefore(firstToken, "\n");
3003
+ }
3004
+ });
3005
+ }
3006
+ }
3559
3007
  function checkOrder(imports) {
3560
- if (imports.every((entry, index) => index === 0 || entry.group >= imports[index - 1].group)) return;
3008
+ if (imports.every((entry, index) => index === 0 || entry.group >= imports[index - 1].group)) return false;
3561
3009
  const firstUnsorted = imports.find((entry, index) => index > 0 && entry.group < imports[index - 1].group);
3562
- if (!firstUnsorted) return;
3010
+ if (!firstUnsorted) return false;
3563
3011
  const previous = imports[imports.indexOf(firstUnsorted) - 1];
3564
3012
  context.report({
3565
3013
  node: firstUnsorted.node,
@@ -3574,24 +3022,26 @@ const sortImports = createRule$2({
3574
3022
  return imports.map((entry, index) => fixer.replaceText(entry.node, sortedTexts[index]));
3575
3023
  }
3576
3024
  });
3025
+ return true;
3577
3026
  }
3578
3027
  return { Program(node) {
3579
3028
  const importGroups = [];
3580
3029
  node.body.forEach((statement) => {
3581
3030
  if (statement.type !== _typescript_eslint_utils.AST_NODE_TYPES.ImportDeclaration) {
3582
3031
  if (importGroups.length > 0) {
3583
- checkOrder(importGroups);
3032
+ if (!checkOrder(importGroups)) checkBlankLines(importGroups);
3584
3033
  importGroups.length = 0;
3585
3034
  }
3586
3035
  return;
3587
3036
  }
3588
- if (isTypeOnlyImport(statement)) return;
3589
3037
  importGroups.push({
3590
3038
  node: statement,
3591
3039
  group: getImportGroup(statement)
3592
3040
  });
3593
3041
  });
3594
- if (importGroups.length > 0) checkOrder(importGroups);
3042
+ if (importGroups.length > 0) {
3043
+ if (!checkOrder(importGroups)) checkBlankLines(importGroups);
3044
+ }
3595
3045
  } };
3596
3046
  }
3597
3047
  });
@@ -3724,11 +3174,9 @@ const meta = {
3724
3174
  };
3725
3175
  const rules = {
3726
3176
  "boolean-naming-prefix": booleanNamingPrefix,
3727
- "enforce-camel-case": enforceCamelCase,
3728
3177
  "enforce-constant-case": enforceConstantCase,
3729
3178
  "enforce-hook-filename": enforceHookFilename,
3730
3179
  "enforce-hook-naming": enforceHookNaming,
3731
- "enforce-property-case": enforcePropertyCase,
3732
3180
  "enforce-props-suffix": enforcePropsSuffix,
3733
3181
  "enforce-readonly-component-props": enforceReadonlyComponentProps,
3734
3182
  "enforce-render-naming": enforceRenderNaming,
@@ -3759,7 +3207,6 @@ const rules = {
3759
3207
  "no-ghost-wrapper": noGhostWrapper,
3760
3208
  "no-helper-function-in-hook": noHelperFunctionInHook,
3761
3209
  "no-helper-function-in-test": noHelperFunctionInTest,
3762
- "no-inline-default-export": noInlineDefaultExport,
3763
3210
  "no-inline-nested-object": noInlineNestedObject,
3764
3211
  "no-inline-return-properties": noInlineReturnProperties,
3765
3212
  "no-inline-type-import": noInlineTypeImport,
@@ -3767,24 +3214,17 @@ const rules = {
3767
3214
  "no-logic-in-params": noLogicInParams,
3768
3215
  "no-misleading-constant-case": noMisleadingConstantCase,
3769
3216
  "no-nested-interface-declaration": noNestedInterfaceDeclaration,
3770
- "no-nested-ternary": noNestedTernary,
3771
- "no-redundant-fragment": noRedundantFragment,
3772
3217
  "no-relative-imports": noRelativeImports,
3773
- "no-single-char-variables": noSingleCharVariables,
3774
3218
  "prefer-async-await": preferAsyncAwait,
3775
3219
  "prefer-destructuring-params": preferDestructuringParams,
3776
- "prefer-function-declaration": preferFunctionDeclaration,
3777
3220
  "prefer-guard-clause": preferGuardClause,
3778
3221
  "prefer-import-type": preferImportType,
3779
3222
  "prefer-inline-literal-union": preferInlineLiteralUnion,
3780
- "prefer-inline-type-export": preferInlineTypeExport,
3781
3223
  "prefer-interface-for-component-props": preferInterfaceForComponentProps,
3782
3224
  "prefer-interface-over-inline-types": preferInterfaceOverInlineTypes,
3783
- "prefer-jsx-template-literals": preferJSXTemplateLiterals,
3784
3225
  "prefer-named-param-types": preferNamedParamTypes,
3785
3226
  "prefer-props-with-children": preferPropsWithChildren,
3786
3227
  "prefer-react-import-types": preferReactImportTypes,
3787
- "react-props-destructure": reactPropsDestructure,
3788
3228
  "require-explicit-return-type": requireExplicitReturnType,
3789
3229
  "sort-exports": sortExports,
3790
3230
  "sort-imports": sortImports,
@@ -3797,11 +3237,9 @@ const plugin = {
3797
3237
  };
3798
3238
  const baseRules = {
3799
3239
  "nextfriday/boolean-naming-prefix": "warn",
3800
- "nextfriday/enforce-camel-case": "warn",
3801
3240
  "nextfriday/enforce-constant-case": "warn",
3802
3241
  "nextfriday/enforce-hook-filename": "warn",
3803
3242
  "nextfriday/enforce-hook-naming": "warn",
3804
- "nextfriday/enforce-property-case": "warn",
3805
3243
  "nextfriday/enforce-service-naming": "warn",
3806
3244
  "nextfriday/enforce-test-filename": "warn",
3807
3245
  "nextfriday/enforce-sorted-destructuring": "warn",
@@ -3815,7 +3253,6 @@ const baseRules = {
3815
3253
  "nextfriday/no-env-fallback": "warn",
3816
3254
  "nextfriday/no-helper-function-in-hook": "warn",
3817
3255
  "nextfriday/no-helper-function-in-test": "warn",
3818
- "nextfriday/no-inline-default-export": "warn",
3819
3256
  "nextfriday/no-inline-nested-object": "warn",
3820
3257
  "nextfriday/no-inline-return-properties": "warn",
3821
3258
  "nextfriday/no-inline-type-import": "warn",
@@ -3823,16 +3260,12 @@ const baseRules = {
3823
3260
  "nextfriday/no-logic-in-params": "warn",
3824
3261
  "nextfriday/no-misleading-constant-case": "warn",
3825
3262
  "nextfriday/no-nested-interface-declaration": "warn",
3826
- "nextfriday/no-nested-ternary": "warn",
3827
3263
  "nextfriday/no-relative-imports": "warn",
3828
- "nextfriday/no-single-char-variables": "warn",
3829
3264
  "nextfriday/prefer-async-await": "warn",
3830
3265
  "nextfriday/prefer-destructuring-params": "warn",
3831
- "nextfriday/prefer-function-declaration": "warn",
3832
3266
  "nextfriday/prefer-guard-clause": "warn",
3833
3267
  "nextfriday/prefer-import-type": "warn",
3834
3268
  "nextfriday/prefer-inline-literal-union": "warn",
3835
- "nextfriday/prefer-inline-type-export": "warn",
3836
3269
  "nextfriday/prefer-named-param-types": "warn",
3837
3270
  "nextfriday/prefer-react-import-types": "warn",
3838
3271
  "nextfriday/require-explicit-return-type": "warn",
@@ -3843,11 +3276,9 @@ const baseRules = {
3843
3276
  };
3844
3277
  const baseRecommendedRules = {
3845
3278
  "nextfriday/boolean-naming-prefix": "error",
3846
- "nextfriday/enforce-camel-case": "error",
3847
3279
  "nextfriday/enforce-constant-case": "error",
3848
3280
  "nextfriday/enforce-hook-filename": "error",
3849
3281
  "nextfriday/enforce-hook-naming": "error",
3850
- "nextfriday/enforce-property-case": "error",
3851
3282
  "nextfriday/enforce-service-naming": "error",
3852
3283
  "nextfriday/enforce-test-filename": "error",
3853
3284
  "nextfriday/enforce-sorted-destructuring": "error",
@@ -3861,7 +3292,6 @@ const baseRecommendedRules = {
3861
3292
  "nextfriday/no-env-fallback": "error",
3862
3293
  "nextfriday/no-helper-function-in-hook": "error",
3863
3294
  "nextfriday/no-helper-function-in-test": "error",
3864
- "nextfriday/no-inline-default-export": "error",
3865
3295
  "nextfriday/no-inline-nested-object": "error",
3866
3296
  "nextfriday/no-inline-return-properties": "error",
3867
3297
  "nextfriday/no-inline-type-import": "error",
@@ -3869,16 +3299,12 @@ const baseRecommendedRules = {
3869
3299
  "nextfriday/no-logic-in-params": "error",
3870
3300
  "nextfriday/no-misleading-constant-case": "error",
3871
3301
  "nextfriday/no-nested-interface-declaration": "error",
3872
- "nextfriday/no-nested-ternary": "error",
3873
3302
  "nextfriday/no-relative-imports": "error",
3874
- "nextfriday/no-single-char-variables": "error",
3875
3303
  "nextfriday/prefer-async-await": "error",
3876
3304
  "nextfriday/prefer-destructuring-params": "error",
3877
- "nextfriday/prefer-function-declaration": "error",
3878
3305
  "nextfriday/prefer-guard-clause": "error",
3879
3306
  "nextfriday/prefer-import-type": "error",
3880
3307
  "nextfriday/prefer-inline-literal-union": "error",
3881
- "nextfriday/prefer-inline-type-export": "error",
3882
3308
  "nextfriday/prefer-named-param-types": "error",
3883
3309
  "nextfriday/prefer-react-import-types": "error",
3884
3310
  "nextfriday/require-explicit-return-type": "error",
@@ -3905,12 +3331,9 @@ const jsxRules = {
3905
3331
  "nextfriday/jsx-sort-props": "warn",
3906
3332
  "nextfriday/jsx-spread-props-last": "warn",
3907
3333
  "nextfriday/no-ghost-wrapper": "warn",
3908
- "nextfriday/no-redundant-fragment": "warn",
3909
3334
  "nextfriday/prefer-interface-for-component-props": "warn",
3910
3335
  "nextfriday/prefer-interface-over-inline-types": "warn",
3911
- "nextfriday/prefer-jsx-template-literals": "warn",
3912
- "nextfriday/prefer-props-with-children": "warn",
3913
- "nextfriday/react-props-destructure": "warn"
3336
+ "nextfriday/prefer-props-with-children": "warn"
3914
3337
  };
3915
3338
  const jsxRecommendedRules = {
3916
3339
  "nextfriday/enforce-props-suffix": "error",
@@ -3930,12 +3353,9 @@ const jsxRecommendedRules = {
3930
3353
  "nextfriday/jsx-sort-props": "error",
3931
3354
  "nextfriday/jsx-spread-props-last": "error",
3932
3355
  "nextfriday/no-ghost-wrapper": "error",
3933
- "nextfriday/no-redundant-fragment": "error",
3934
3356
  "nextfriday/prefer-interface-for-component-props": "error",
3935
3357
  "nextfriday/prefer-interface-over-inline-types": "error",
3936
- "nextfriday/prefer-jsx-template-literals": "error",
3937
- "nextfriday/prefer-props-with-children": "error",
3938
- "nextfriday/react-props-destructure": "error"
3358
+ "nextfriday/prefer-props-with-children": "error"
3939
3359
  };
3940
3360
  const createConfig = (configRules) => ({
3941
3361
  plugins: { nextfriday: plugin },