eslint-plugin-nextfriday 1.6.0 → 1.8.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.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // package.json
2
2
  var package_default = {
3
3
  name: "eslint-plugin-nextfriday",
4
- version: "1.6.0",
4
+ version: "1.8.0",
5
5
  description: "A comprehensive ESLint plugin providing custom rules and configurations for Next Friday development workflows.",
6
6
  keywords: [
7
7
  "eslint",
@@ -115,12 +115,143 @@ var package_default = {
115
115
  }
116
116
  };
117
117
 
118
- // src/rules/enforce-readonly-component-props.ts
119
- import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils";
118
+ // src/rules/boolean-naming-prefix.ts
119
+ import { ESLintUtils, AST_NODE_TYPES } from "@typescript-eslint/utils";
120
120
  var createRule = ESLintUtils.RuleCreator(
121
121
  (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
122
122
  );
123
- var enforceReadonlyComponentProps = createRule({
123
+ var BOOLEAN_PREFIXES = ["is", "has", "should", "can", "did", "will", "was", "are", "does", "had"];
124
+ var startsWithBooleanPrefix = (name) => {
125
+ const lowerName = name.toLowerCase();
126
+ return BOOLEAN_PREFIXES.some((prefix) => {
127
+ if (!lowerName.startsWith(prefix)) {
128
+ return false;
129
+ }
130
+ if (name.length === prefix.length) {
131
+ return true;
132
+ }
133
+ const nextChar = name.charAt(prefix.length);
134
+ return nextChar === nextChar.toUpperCase();
135
+ });
136
+ };
137
+ var isBooleanLiteral = (node) => node.type === AST_NODE_TYPES.Literal && typeof node.value === "boolean";
138
+ var isBooleanExpression = (node) => {
139
+ if (isBooleanLiteral(node)) {
140
+ return true;
141
+ }
142
+ if (node.type === AST_NODE_TYPES.UnaryExpression && node.operator === "!") {
143
+ return true;
144
+ }
145
+ if (node.type === AST_NODE_TYPES.BinaryExpression) {
146
+ const comparisonOperators = ["===", "!==", "==", "!=", "<", ">", "<=", ">=", "in", "instanceof"];
147
+ return comparisonOperators.includes(node.operator);
148
+ }
149
+ if (node.type === AST_NODE_TYPES.LogicalExpression) {
150
+ return node.operator === "&&" || node.operator === "||";
151
+ }
152
+ return false;
153
+ };
154
+ var hasBooleanTypeAnnotation = (node) => {
155
+ if (node.type === AST_NODE_TYPES.Identifier) {
156
+ const { typeAnnotation } = node;
157
+ if (typeAnnotation?.typeAnnotation.type === AST_NODE_TYPES.TSBooleanKeyword) {
158
+ return true;
159
+ }
160
+ }
161
+ if ("id" in node && node.id.type === AST_NODE_TYPES.Identifier) {
162
+ const { typeAnnotation } = node.id;
163
+ if (typeAnnotation?.typeAnnotation.type === AST_NODE_TYPES.TSBooleanKeyword) {
164
+ return true;
165
+ }
166
+ }
167
+ return false;
168
+ };
169
+ var booleanNamingPrefix = createRule({
170
+ name: "boolean-naming-prefix",
171
+ meta: {
172
+ type: "suggestion",
173
+ docs: {
174
+ description: "Enforce boolean variables and parameters to have a prefix like is, has, should, can, did, will for better readability"
175
+ },
176
+ messages: {
177
+ missingPrefix: "Boolean variable '{{name}}' should have a prefix like is, has, should, can, did, or will. Example: 'is{{suggestedName}}' or 'has{{suggestedName}}'."
178
+ },
179
+ schema: []
180
+ },
181
+ defaultOptions: [],
182
+ create(context) {
183
+ const checkBooleanNaming = (name, node) => {
184
+ if (startsWithBooleanPrefix(name)) {
185
+ return;
186
+ }
187
+ const suggestedName = name.charAt(0).toUpperCase() + name.slice(1);
188
+ context.report({
189
+ node,
190
+ messageId: "missingPrefix",
191
+ data: { name, suggestedName }
192
+ });
193
+ };
194
+ return {
195
+ VariableDeclarator(node) {
196
+ if (node.id.type !== AST_NODE_TYPES.Identifier) {
197
+ return;
198
+ }
199
+ const { name } = node.id;
200
+ if (hasBooleanTypeAnnotation(node)) {
201
+ checkBooleanNaming(name, node.id);
202
+ return;
203
+ }
204
+ if (node.init && isBooleanExpression(node.init)) {
205
+ checkBooleanNaming(name, node.id);
206
+ }
207
+ },
208
+ FunctionDeclaration(node) {
209
+ node.params.forEach((param) => {
210
+ if (param.type === AST_NODE_TYPES.Identifier && hasBooleanTypeAnnotation(param)) {
211
+ checkBooleanNaming(param.name, param);
212
+ }
213
+ if (param.type === AST_NODE_TYPES.AssignmentPattern) {
214
+ if (param.left.type === AST_NODE_TYPES.Identifier && param.right && isBooleanLiteral(param.right)) {
215
+ checkBooleanNaming(param.left.name, param.left);
216
+ }
217
+ }
218
+ });
219
+ },
220
+ FunctionExpression(node) {
221
+ node.params.forEach((param) => {
222
+ if (param.type === AST_NODE_TYPES.Identifier && hasBooleanTypeAnnotation(param)) {
223
+ checkBooleanNaming(param.name, param);
224
+ }
225
+ if (param.type === AST_NODE_TYPES.AssignmentPattern) {
226
+ if (param.left.type === AST_NODE_TYPES.Identifier && param.right && isBooleanLiteral(param.right)) {
227
+ checkBooleanNaming(param.left.name, param.left);
228
+ }
229
+ }
230
+ });
231
+ },
232
+ ArrowFunctionExpression(node) {
233
+ node.params.forEach((param) => {
234
+ if (param.type === AST_NODE_TYPES.Identifier && hasBooleanTypeAnnotation(param)) {
235
+ checkBooleanNaming(param.name, param);
236
+ }
237
+ if (param.type === AST_NODE_TYPES.AssignmentPattern) {
238
+ if (param.left.type === AST_NODE_TYPES.Identifier && param.right && isBooleanLiteral(param.right)) {
239
+ checkBooleanNaming(param.left.name, param.left);
240
+ }
241
+ }
242
+ });
243
+ }
244
+ };
245
+ }
246
+ });
247
+ var boolean_naming_prefix_default = booleanNamingPrefix;
248
+
249
+ // src/rules/enforce-readonly-component-props.ts
250
+ import { AST_NODE_TYPES as AST_NODE_TYPES2, ESLintUtils as ESLintUtils2 } from "@typescript-eslint/utils";
251
+ var createRule2 = ESLintUtils2.RuleCreator(
252
+ (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
253
+ );
254
+ var enforceReadonlyComponentProps = createRule2({
124
255
  name: "enforce-readonly-component-props",
125
256
  meta: {
126
257
  type: "suggestion",
@@ -136,54 +267,54 @@ var enforceReadonlyComponentProps = createRule({
136
267
  defaultOptions: [],
137
268
  create(context) {
138
269
  function hasJSXInConditional(node) {
139
- 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;
270
+ return node.consequent.type === AST_NODE_TYPES2.JSXElement || node.consequent.type === AST_NODE_TYPES2.JSXFragment || node.alternate.type === AST_NODE_TYPES2.JSXElement || node.alternate.type === AST_NODE_TYPES2.JSXFragment;
140
271
  }
141
272
  function hasJSXInLogical(node) {
142
- return node.right.type === AST_NODE_TYPES.JSXElement || node.right.type === AST_NODE_TYPES.JSXFragment;
273
+ return node.right.type === AST_NODE_TYPES2.JSXElement || node.right.type === AST_NODE_TYPES2.JSXFragment;
143
274
  }
144
275
  function hasJSXReturn(block) {
145
276
  return block.body.some((stmt) => {
146
- if (stmt.type === AST_NODE_TYPES.ReturnStatement && stmt.argument) {
147
- 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);
277
+ if (stmt.type === AST_NODE_TYPES2.ReturnStatement && stmt.argument) {
278
+ return stmt.argument.type === AST_NODE_TYPES2.JSXElement || stmt.argument.type === AST_NODE_TYPES2.JSXFragment || stmt.argument.type === AST_NODE_TYPES2.ConditionalExpression && hasJSXInConditional(stmt.argument) || stmt.argument.type === AST_NODE_TYPES2.LogicalExpression && hasJSXInLogical(stmt.argument);
148
279
  }
149
280
  return false;
150
281
  });
151
282
  }
152
- function isReactComponent(node) {
153
- if (node.type === AST_NODE_TYPES.ArrowFunctionExpression) {
154
- if (node.body.type === AST_NODE_TYPES.JSXElement || node.body.type === AST_NODE_TYPES.JSXFragment) {
283
+ function isReactComponent2(node) {
284
+ if (node.type === AST_NODE_TYPES2.ArrowFunctionExpression) {
285
+ if (node.body.type === AST_NODE_TYPES2.JSXElement || node.body.type === AST_NODE_TYPES2.JSXFragment) {
155
286
  return true;
156
287
  }
157
- if (node.body.type === AST_NODE_TYPES.BlockStatement) {
288
+ if (node.body.type === AST_NODE_TYPES2.BlockStatement) {
158
289
  return hasJSXReturn(node.body);
159
290
  }
160
- } else if (node.type === AST_NODE_TYPES.FunctionExpression || node.type === AST_NODE_TYPES.FunctionDeclaration) {
161
- if (node.body && node.body.type === AST_NODE_TYPES.BlockStatement) {
291
+ } else if (node.type === AST_NODE_TYPES2.FunctionExpression || node.type === AST_NODE_TYPES2.FunctionDeclaration) {
292
+ if (node.body && node.body.type === AST_NODE_TYPES2.BlockStatement) {
162
293
  return hasJSXReturn(node.body);
163
294
  }
164
295
  }
165
296
  return false;
166
297
  }
167
298
  function isNamedType(node) {
168
- return node.type === AST_NODE_TYPES.TSTypeReference;
299
+ return node.type === AST_NODE_TYPES2.TSTypeReference;
169
300
  }
170
301
  function isAlreadyReadonly(node) {
171
- if (node.type === AST_NODE_TYPES.TSTypeReference && node.typeName) {
172
- if (node.typeName.type === AST_NODE_TYPES.Identifier && node.typeName.name === "Readonly") {
302
+ if (node.type === AST_NODE_TYPES2.TSTypeReference && node.typeName) {
303
+ if (node.typeName.type === AST_NODE_TYPES2.Identifier && node.typeName.name === "Readonly") {
173
304
  return true;
174
305
  }
175
306
  }
176
307
  return false;
177
308
  }
178
309
  function checkFunction(node) {
179
- if (!isReactComponent(node)) {
310
+ if (!isReactComponent2(node)) {
180
311
  return;
181
312
  }
182
313
  if (node.params.length !== 1) {
183
314
  return;
184
315
  }
185
316
  const param = node.params[0];
186
- if (param.type === AST_NODE_TYPES.Identifier && param.typeAnnotation) {
317
+ if (param.type === AST_NODE_TYPES2.Identifier && param.typeAnnotation) {
187
318
  const { typeAnnotation } = param.typeAnnotation;
188
319
  if (isNamedType(typeAnnotation) && !isAlreadyReadonly(typeAnnotation)) {
189
320
  const { sourceCode } = context;
@@ -208,11 +339,11 @@ var enforceReadonlyComponentProps = createRule({
208
339
  var enforce_readonly_component_props_default = enforceReadonlyComponentProps;
209
340
 
210
341
  // src/rules/enforce-sorted-destructuring.ts
211
- import { AST_NODE_TYPES as AST_NODE_TYPES2, ESLintUtils as ESLintUtils2 } from "@typescript-eslint/utils";
212
- var createRule2 = ESLintUtils2.RuleCreator(
342
+ import { AST_NODE_TYPES as AST_NODE_TYPES3, ESLintUtils as ESLintUtils3 } from "@typescript-eslint/utils";
343
+ var createRule3 = ESLintUtils3.RuleCreator(
213
344
  (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
214
345
  );
215
- var enforceSortedDestructuring = createRule2({
346
+ var enforceSortedDestructuring = createRule3({
216
347
  name: "enforce-sorted-destructuring",
217
348
  meta: {
218
349
  type: "suggestion",
@@ -227,16 +358,16 @@ var enforceSortedDestructuring = createRule2({
227
358
  defaultOptions: [],
228
359
  create(context) {
229
360
  function getPropertyName(property) {
230
- if (property.type === AST_NODE_TYPES2.RestElement) {
361
+ if (property.type === AST_NODE_TYPES3.RestElement) {
231
362
  return null;
232
363
  }
233
- if (property.key.type === AST_NODE_TYPES2.Identifier) {
364
+ if (property.key.type === AST_NODE_TYPES3.Identifier) {
234
365
  return property.key.name;
235
366
  }
236
367
  return null;
237
368
  }
238
369
  function hasDefaultValue(property) {
239
- return property.value.type === AST_NODE_TYPES2.AssignmentPattern && Boolean(property.value.right);
370
+ return property.value.type === AST_NODE_TYPES3.AssignmentPattern && Boolean(property.value.right);
240
371
  }
241
372
  function getDefaultValueType(property) {
242
373
  if (!hasDefaultValue(property)) {
@@ -248,7 +379,7 @@ var enforceSortedDestructuring = createRule2({
248
379
  return "none";
249
380
  }
250
381
  switch (right.type) {
251
- case AST_NODE_TYPES2.Literal:
382
+ case AST_NODE_TYPES3.Literal:
252
383
  if (typeof right.value === "string") {
253
384
  return "string";
254
385
  }
@@ -259,10 +390,10 @@ var enforceSortedDestructuring = createRule2({
259
390
  return "boolean";
260
391
  }
261
392
  return "other";
262
- case AST_NODE_TYPES2.TemplateLiteral:
393
+ case AST_NODE_TYPES3.TemplateLiteral:
263
394
  return "string";
264
- case AST_NODE_TYPES2.ObjectExpression:
265
- case AST_NODE_TYPES2.ArrayExpression:
395
+ case AST_NODE_TYPES3.ObjectExpression:
396
+ case AST_NODE_TYPES3.ArrayExpression:
266
397
  return "object";
267
398
  default:
268
399
  return "other";
@@ -280,7 +411,7 @@ var enforceSortedDestructuring = createRule2({
280
411
  return order[type] ?? 5;
281
412
  }
282
413
  function checkVariableDeclarator(node) {
283
- if (node.id.type !== AST_NODE_TYPES2.ObjectPattern) {
414
+ if (node.id.type !== AST_NODE_TYPES3.ObjectPattern) {
284
415
  return;
285
416
  }
286
417
  const { properties } = node.id;
@@ -288,7 +419,7 @@ var enforceSortedDestructuring = createRule2({
288
419
  return;
289
420
  }
290
421
  const propertyInfo = properties.map((prop) => {
291
- if (prop.type === AST_NODE_TYPES2.RestElement) {
422
+ if (prop.type === AST_NODE_TYPES3.RestElement) {
292
423
  return null;
293
424
  }
294
425
  return {
@@ -330,8 +461,8 @@ var enforce_sorted_destructuring_default = enforceSortedDestructuring;
330
461
 
331
462
  // src/rules/file-kebab-case.ts
332
463
  import path from "path";
333
- import { ESLintUtils as ESLintUtils3 } from "@typescript-eslint/utils";
334
- var createRule3 = ESLintUtils3.RuleCreator(
464
+ import { ESLintUtils as ESLintUtils4 } from "@typescript-eslint/utils";
465
+ var createRule4 = ESLintUtils4.RuleCreator(
335
466
  (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
336
467
  );
337
468
  var isKebabCase = (str) => {
@@ -340,7 +471,7 @@ var isKebabCase = (str) => {
340
471
  }
341
472
  return /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(str);
342
473
  };
343
- var fileKebabCase = createRule3({
474
+ var fileKebabCase = createRule4({
344
475
  name: "file-kebab-case",
345
476
  meta: {
346
477
  type: "problem",
@@ -376,12 +507,12 @@ var file_kebab_case_default = fileKebabCase;
376
507
 
377
508
  // src/rules/jsx-pascal-case.ts
378
509
  import path2 from "path";
379
- import { ESLintUtils as ESLintUtils4 } from "@typescript-eslint/utils";
380
- var createRule4 = ESLintUtils4.RuleCreator(
510
+ import { ESLintUtils as ESLintUtils5 } from "@typescript-eslint/utils";
511
+ var createRule5 = ESLintUtils5.RuleCreator(
381
512
  (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
382
513
  );
383
514
  var isPascalCase = (str) => /^[A-Z][a-zA-Z0-9]*$/.test(str) && !/^[A-Z]+$/.test(str);
384
- var jsxPascalCase = createRule4({
515
+ var jsxPascalCase = createRule5({
385
516
  name: "jsx-pascal-case",
386
517
  meta: {
387
518
  type: "problem",
@@ -415,12 +546,64 @@ var jsxPascalCase = createRule4({
415
546
  });
416
547
  var jsx_pascal_case_default = jsxPascalCase;
417
548
 
549
+ // src/rules/no-direct-date.ts
550
+ import { ESLintUtils as ESLintUtils6, AST_NODE_TYPES as AST_NODE_TYPES4 } from "@typescript-eslint/utils";
551
+ var createRule6 = ESLintUtils6.RuleCreator(
552
+ (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
553
+ );
554
+ var noDirectDate = createRule6({
555
+ name: "no-direct-date",
556
+ meta: {
557
+ type: "problem",
558
+ docs: {
559
+ description: "Disallow direct usage of Date constructor and methods to enforce centralized date utilities"
560
+ },
561
+ messages: {
562
+ noNewDate: "Avoid using 'new Date()'. Use a centralized date utility like dayjs instead.",
563
+ noDateNow: "Avoid using 'Date.now()'. Use a centralized date utility like dayjs instead.",
564
+ noDateParse: "Avoid using 'Date.parse()'. Use a centralized date utility like dayjs instead."
565
+ },
566
+ schema: []
567
+ },
568
+ defaultOptions: [],
569
+ create(context) {
570
+ return {
571
+ NewExpression(node) {
572
+ if (node.callee.type === AST_NODE_TYPES4.Identifier && node.callee.name === "Date") {
573
+ context.report({
574
+ node,
575
+ messageId: "noNewDate"
576
+ });
577
+ }
578
+ },
579
+ CallExpression(node) {
580
+ if (node.callee.type === AST_NODE_TYPES4.MemberExpression && node.callee.object.type === AST_NODE_TYPES4.Identifier && node.callee.object.name === "Date" && node.callee.property.type === AST_NODE_TYPES4.Identifier) {
581
+ const methodName = node.callee.property.name;
582
+ if (methodName === "now") {
583
+ context.report({
584
+ node,
585
+ messageId: "noDateNow"
586
+ });
587
+ }
588
+ if (methodName === "parse") {
589
+ context.report({
590
+ node,
591
+ messageId: "noDateParse"
592
+ });
593
+ }
594
+ }
595
+ }
596
+ };
597
+ }
598
+ });
599
+ var no_direct_date_default = noDirectDate;
600
+
418
601
  // src/rules/jsx-no-variable-in-callback.ts
419
- import { AST_NODE_TYPES as AST_NODE_TYPES3, ESLintUtils as ESLintUtils5 } from "@typescript-eslint/utils";
420
- var createRule5 = ESLintUtils5.RuleCreator(
602
+ import { AST_NODE_TYPES as AST_NODE_TYPES5, ESLintUtils as ESLintUtils7 } from "@typescript-eslint/utils";
603
+ var createRule7 = ESLintUtils7.RuleCreator(
421
604
  (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
422
605
  );
423
- var jsxNoVariableInCallback = createRule5({
606
+ var jsxNoVariableInCallback = createRule7({
424
607
  name: "jsx-no-variable-in-callback",
425
608
  meta: {
426
609
  type: "suggestion",
@@ -437,7 +620,7 @@ var jsxNoVariableInCallback = createRule5({
437
620
  function isInsideJSX(node) {
438
621
  let current = node.parent;
439
622
  while (current) {
440
- if (current.type === AST_NODE_TYPES3.JSXElement || current.type === AST_NODE_TYPES3.JSXFragment) {
623
+ if (current.type === AST_NODE_TYPES5.JSXElement || current.type === AST_NODE_TYPES5.JSXFragment) {
441
624
  return true;
442
625
  }
443
626
  current = current.parent;
@@ -451,11 +634,11 @@ var jsxNoVariableInCallback = createRule5({
451
634
  if (!isInsideJSX(node)) {
452
635
  return false;
453
636
  }
454
- if (node.parent.type === AST_NODE_TYPES3.CallExpression || node.parent.type === AST_NODE_TYPES3.JSXExpressionContainer) {
637
+ if (node.parent.type === AST_NODE_TYPES5.CallExpression || node.parent.type === AST_NODE_TYPES5.JSXExpressionContainer) {
455
638
  return true;
456
639
  }
457
- if (node.parent.type === AST_NODE_TYPES3.ArrayExpression && node.parent.parent) {
458
- if (node.parent.parent.type === AST_NODE_TYPES3.CallExpression || node.parent.parent.type === AST_NODE_TYPES3.JSXExpressionContainer) {
640
+ if (node.parent.type === AST_NODE_TYPES5.ArrayExpression && node.parent.parent) {
641
+ if (node.parent.parent.type === AST_NODE_TYPES5.CallExpression || node.parent.parent.type === AST_NODE_TYPES5.JSXExpressionContainer) {
459
642
  return true;
460
643
  }
461
644
  }
@@ -466,11 +649,11 @@ var jsxNoVariableInCallback = createRule5({
466
649
  return;
467
650
  }
468
651
  const { body } = node;
469
- if (body.type !== AST_NODE_TYPES3.BlockStatement) {
652
+ if (body.type !== AST_NODE_TYPES5.BlockStatement) {
470
653
  return;
471
654
  }
472
655
  body.body.forEach((statement) => {
473
- if (statement.type === AST_NODE_TYPES3.VariableDeclaration) {
656
+ if (statement.type === AST_NODE_TYPES5.VariableDeclaration) {
474
657
  context.report({
475
658
  node: statement,
476
659
  messageId: "noVariableInCallback"
@@ -488,11 +671,11 @@ var jsx_no_variable_in_callback_default = jsxNoVariableInCallback;
488
671
 
489
672
  // src/rules/md-filename-case-restriction.ts
490
673
  import path3 from "path";
491
- import { ESLintUtils as ESLintUtils6 } from "@typescript-eslint/utils";
492
- var createRule6 = ESLintUtils6.RuleCreator(
674
+ import { ESLintUtils as ESLintUtils8 } from "@typescript-eslint/utils";
675
+ var createRule8 = ESLintUtils8.RuleCreator(
493
676
  (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
494
677
  );
495
- var mdFilenameCaseRestriction = createRule6({
678
+ var mdFilenameCaseRestriction = createRule8({
496
679
  name: "md-filename-case-restriction",
497
680
  meta: {
498
681
  type: "problem",
@@ -533,11 +716,11 @@ var mdFilenameCaseRestriction = createRule6({
533
716
  var md_filename_case_restriction_default = mdFilenameCaseRestriction;
534
717
 
535
718
  // src/rules/no-complex-inline-return.ts
536
- import { ESLintUtils as ESLintUtils7, AST_NODE_TYPES as AST_NODE_TYPES4 } from "@typescript-eslint/utils";
537
- var createRule7 = ESLintUtils7.RuleCreator(
719
+ import { ESLintUtils as ESLintUtils9, AST_NODE_TYPES as AST_NODE_TYPES6 } from "@typescript-eslint/utils";
720
+ var createRule9 = ESLintUtils9.RuleCreator(
538
721
  (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
539
722
  );
540
- var noComplexInlineReturn = createRule7({
723
+ var noComplexInlineReturn = createRule9({
541
724
  name: "no-complex-inline-return",
542
725
  meta: {
543
726
  type: "suggestion",
@@ -553,13 +736,13 @@ var noComplexInlineReturn = createRule7({
553
736
  create(context) {
554
737
  const isComplexExpression = (node) => {
555
738
  if (!node) return false;
556
- if (node.type === AST_NODE_TYPES4.ConditionalExpression) {
739
+ if (node.type === AST_NODE_TYPES6.ConditionalExpression) {
557
740
  return true;
558
741
  }
559
- if (node.type === AST_NODE_TYPES4.LogicalExpression) {
742
+ if (node.type === AST_NODE_TYPES6.LogicalExpression) {
560
743
  return true;
561
744
  }
562
- if (node.type === AST_NODE_TYPES4.NewExpression) {
745
+ if (node.type === AST_NODE_TYPES6.NewExpression) {
563
746
  return true;
564
747
  }
565
748
  return false;
@@ -580,11 +763,11 @@ var no_complex_inline_return_default = noComplexInlineReturn;
580
763
 
581
764
  // src/rules/no-emoji.ts
582
765
  import emojiRegex from "emoji-regex";
583
- import { ESLintUtils as ESLintUtils8 } from "@typescript-eslint/utils";
584
- var createRule8 = ESLintUtils8.RuleCreator(
766
+ import { ESLintUtils as ESLintUtils10 } from "@typescript-eslint/utils";
767
+ var createRule10 = ESLintUtils10.RuleCreator(
585
768
  (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
586
769
  );
587
- var noEmoji = createRule8({
770
+ var noEmoji = createRule10({
588
771
  name: "no-emoji",
589
772
  meta: {
590
773
  type: "problem",
@@ -618,11 +801,11 @@ var noEmoji = createRule8({
618
801
  var no_emoji_default = noEmoji;
619
802
 
620
803
  // src/rules/no-env-fallback.ts
621
- import { ESLintUtils as ESLintUtils9, AST_NODE_TYPES as AST_NODE_TYPES5 } from "@typescript-eslint/utils";
622
- var createRule9 = ESLintUtils9.RuleCreator(
804
+ import { ESLintUtils as ESLintUtils11, AST_NODE_TYPES as AST_NODE_TYPES7 } from "@typescript-eslint/utils";
805
+ var createRule11 = ESLintUtils11.RuleCreator(
623
806
  (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
624
807
  );
625
- var noEnvFallback = createRule9({
808
+ var noEnvFallback = createRule11({
626
809
  name: "no-env-fallback",
627
810
  meta: {
628
811
  type: "problem",
@@ -637,16 +820,16 @@ var noEnvFallback = createRule9({
637
820
  defaultOptions: [],
638
821
  create(context) {
639
822
  const isProcessEnvAccess = (node) => {
640
- if (node.type !== AST_NODE_TYPES5.MemberExpression) {
823
+ if (node.type !== AST_NODE_TYPES7.MemberExpression) {
641
824
  return false;
642
825
  }
643
826
  const { object } = node;
644
- if (object.type !== AST_NODE_TYPES5.MemberExpression) {
827
+ if (object.type !== AST_NODE_TYPES7.MemberExpression) {
645
828
  return false;
646
829
  }
647
830
  const processNode = object.object;
648
831
  const envNode = object.property;
649
- return processNode.type === AST_NODE_TYPES5.Identifier && processNode.name === "process" && envNode.type === AST_NODE_TYPES5.Identifier && envNode.name === "env";
832
+ return processNode.type === AST_NODE_TYPES7.Identifier && processNode.name === "process" && envNode.type === AST_NODE_TYPES7.Identifier && envNode.name === "env";
650
833
  };
651
834
  return {
652
835
  LogicalExpression(node) {
@@ -670,38 +853,93 @@ var noEnvFallback = createRule9({
670
853
  });
671
854
  var no_env_fallback_default = noEnvFallback;
672
855
 
673
- // src/rules/no-explicit-return-type.ts
674
- import { ESLintUtils as ESLintUtils10 } from "@typescript-eslint/utils";
675
- var createRule10 = ESLintUtils10.RuleCreator(
856
+ // src/rules/require-explicit-return-type.ts
857
+ import { ESLintUtils as ESLintUtils12, AST_NODE_TYPES as AST_NODE_TYPES8 } from "@typescript-eslint/utils";
858
+ var createRule12 = ESLintUtils12.RuleCreator(
676
859
  (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
677
860
  );
678
- var noExplicitReturnType = createRule10({
679
- name: "no-explicit-return-type",
861
+ var isReactComponent = (node) => {
862
+ if (node.type === AST_NODE_TYPES8.ArrowFunctionExpression) {
863
+ const { parent } = node;
864
+ if (parent?.type === AST_NODE_TYPES8.VariableDeclarator) {
865
+ const { id } = parent;
866
+ if (id.type === AST_NODE_TYPES8.Identifier) {
867
+ return /^[A-Z]/.test(id.name);
868
+ }
869
+ }
870
+ }
871
+ if (node.type === AST_NODE_TYPES8.FunctionDeclaration && node.id) {
872
+ return /^[A-Z]/.test(node.id.name);
873
+ }
874
+ return false;
875
+ };
876
+ var isCallbackFunction = (node) => {
877
+ if (node.type === AST_NODE_TYPES8.FunctionDeclaration) {
878
+ return false;
879
+ }
880
+ const { parent } = node;
881
+ if (!parent) {
882
+ return false;
883
+ }
884
+ if (parent.type === AST_NODE_TYPES8.CallExpression && parent.arguments.includes(node)) {
885
+ return true;
886
+ }
887
+ if (parent.type === AST_NODE_TYPES8.Property) {
888
+ return true;
889
+ }
890
+ if (parent.type === AST_NODE_TYPES8.ArrayExpression) {
891
+ return true;
892
+ }
893
+ return false;
894
+ };
895
+ var getFunctionName = (node) => {
896
+ if (node.type === AST_NODE_TYPES8.FunctionDeclaration && node.id) {
897
+ return node.id.name;
898
+ }
899
+ if (node.type === AST_NODE_TYPES8.FunctionExpression && node.id) {
900
+ return node.id.name;
901
+ }
902
+ if ((node.type === AST_NODE_TYPES8.ArrowFunctionExpression || node.type === AST_NODE_TYPES8.FunctionExpression) && node.parent?.type === AST_NODE_TYPES8.VariableDeclarator && node.parent.id.type === AST_NODE_TYPES8.Identifier) {
903
+ return node.parent.id.name;
904
+ }
905
+ return null;
906
+ };
907
+ var requireExplicitReturnType = createRule12({
908
+ name: "require-explicit-return-type",
680
909
  meta: {
681
910
  type: "suggestion",
682
911
  docs: {
683
- description: "Disallow explicit return types on functions"
912
+ description: "Require explicit return types on functions for better code documentation and type safety"
684
913
  },
685
- fixable: "code",
686
- schema: [],
687
914
  messages: {
688
- noExplicitReturnType: "Remove explicit return type '{{returnType}}' - TypeScript can infer it automatically"
689
- }
915
+ missingReturnType: "Function '{{name}}' is missing an explicit return type. Add a return type annotation for better documentation.",
916
+ missingReturnTypeAnonymous: "Function is missing an explicit return type. Add a return type annotation for better documentation."
917
+ },
918
+ schema: []
690
919
  },
691
920
  defaultOptions: [],
692
921
  create(context) {
693
922
  const checkFunction = (node) => {
694
923
  if (node.returnType) {
695
- const returnTypeText = context.sourceCode.getText(node.returnType);
924
+ return;
925
+ }
926
+ if (isCallbackFunction(node)) {
927
+ return;
928
+ }
929
+ if (isReactComponent(node)) {
930
+ return;
931
+ }
932
+ const functionName = getFunctionName(node);
933
+ if (functionName) {
696
934
  context.report({
697
- node: node.returnType,
698
- messageId: "noExplicitReturnType",
699
- data: {
700
- returnType: returnTypeText
701
- },
702
- fix(fixer) {
703
- return fixer.remove(node.returnType);
704
- }
935
+ node,
936
+ messageId: "missingReturnType",
937
+ data: { name: functionName }
938
+ });
939
+ } else {
940
+ context.report({
941
+ node,
942
+ messageId: "missingReturnTypeAnonymous"
705
943
  });
706
944
  }
707
945
  };
@@ -712,21 +950,21 @@ var noExplicitReturnType = createRule10({
712
950
  };
713
951
  }
714
952
  });
715
- var no_explicit_return_type_default = noExplicitReturnType;
953
+ var require_explicit_return_type_default = requireExplicitReturnType;
716
954
 
717
955
  // src/rules/jsx-no-non-component-function.ts
718
- import { AST_NODE_TYPES as AST_NODE_TYPES7, ESLintUtils as ESLintUtils11 } from "@typescript-eslint/utils";
956
+ import { AST_NODE_TYPES as AST_NODE_TYPES10, ESLintUtils as ESLintUtils13 } from "@typescript-eslint/utils";
719
957
 
720
958
  // src/utils.ts
721
959
  import { basename, extname } from "path";
722
- import { AST_NODE_TYPES as AST_NODE_TYPES6 } from "@typescript-eslint/utils";
960
+ import { AST_NODE_TYPES as AST_NODE_TYPES9 } from "@typescript-eslint/utils";
723
961
  var getFileExtension = (filename) => extname(filename).slice(1);
724
962
 
725
963
  // src/rules/jsx-no-non-component-function.ts
726
- var createRule11 = ESLintUtils11.RuleCreator(
964
+ var createRule13 = ESLintUtils13.RuleCreator(
727
965
  (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
728
966
  );
729
- var jsxNoNonComponentFunction = createRule11({
967
+ var jsxNoNonComponentFunction = createRule13({
730
968
  name: "jsx-no-non-component-function",
731
969
  meta: {
732
970
  type: "problem",
@@ -745,14 +983,14 @@ var jsxNoNonComponentFunction = createRule11({
745
983
  if (extension !== "tsx" && extension !== "jsx") {
746
984
  return {};
747
985
  }
748
- function isReactComponent(node) {
749
- const functionName = node.type === AST_NODE_TYPES7.FunctionDeclaration && node.id ? node.id.name : null;
986
+ function isReactComponent2(node) {
987
+ const functionName = node.type === AST_NODE_TYPES10.FunctionDeclaration && node.id ? node.id.name : null;
750
988
  if (functionName && /^[A-Z]/.test(functionName)) {
751
989
  return true;
752
990
  }
753
991
  if (node.returnType?.typeAnnotation) {
754
992
  const returnTypeNode = node.returnType.typeAnnotation;
755
- if (returnTypeNode.type === AST_NODE_TYPES7.TSTypeReference && returnTypeNode.typeName.type === AST_NODE_TYPES7.Identifier) {
993
+ if (returnTypeNode.type === AST_NODE_TYPES10.TSTypeReference && returnTypeNode.typeName.type === AST_NODE_TYPES10.Identifier) {
756
994
  const typeName = returnTypeNode.typeName.name;
757
995
  if (typeName === "JSX" || typeName === "ReactElement" || typeName === "ReactNode") {
758
996
  return true;
@@ -762,20 +1000,20 @@ var jsxNoNonComponentFunction = createRule11({
762
1000
  return false;
763
1001
  }
764
1002
  function checkTopLevelFunction(node, declaratorNode) {
765
- if (isReactComponent(node)) {
1003
+ if (isReactComponent2(node)) {
766
1004
  return;
767
1005
  }
768
1006
  const { parent } = node;
769
1007
  if (!parent) {
770
1008
  return;
771
1009
  }
772
- if (parent.type === AST_NODE_TYPES7.ExportDefaultDeclaration || parent.type === AST_NODE_TYPES7.ExportNamedDeclaration) {
1010
+ if (parent.type === AST_NODE_TYPES10.ExportDefaultDeclaration || parent.type === AST_NODE_TYPES10.ExportNamedDeclaration) {
773
1011
  return;
774
1012
  }
775
- if (declaratorNode?.parent?.parent?.type === AST_NODE_TYPES7.ExportNamedDeclaration) {
1013
+ if (declaratorNode?.parent?.parent?.type === AST_NODE_TYPES10.ExportNamedDeclaration) {
776
1014
  return;
777
1015
  }
778
- if (declaratorNode?.id.type === AST_NODE_TYPES7.Identifier) {
1016
+ if (declaratorNode?.id.type === AST_NODE_TYPES10.Identifier) {
779
1017
  const varName = declaratorNode.id.name;
780
1018
  if (/^[A-Z]/.test(varName)) {
781
1019
  return;
@@ -800,11 +1038,11 @@ var jsxNoNonComponentFunction = createRule11({
800
1038
  var jsx_no_non_component_function_default = jsxNoNonComponentFunction;
801
1039
 
802
1040
  // src/rules/no-logic-in-params.ts
803
- import { ESLintUtils as ESLintUtils12, AST_NODE_TYPES as AST_NODE_TYPES8 } from "@typescript-eslint/utils";
804
- var createRule12 = ESLintUtils12.RuleCreator(
1041
+ import { ESLintUtils as ESLintUtils14, AST_NODE_TYPES as AST_NODE_TYPES11 } from "@typescript-eslint/utils";
1042
+ var createRule14 = ESLintUtils14.RuleCreator(
805
1043
  (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
806
1044
  );
807
- var noLogicInParams = createRule12({
1045
+ var noLogicInParams = createRule14({
808
1046
  name: "no-logic-in-params",
809
1047
  meta: {
810
1048
  type: "suggestion",
@@ -819,20 +1057,20 @@ var noLogicInParams = createRule12({
819
1057
  defaultOptions: [],
820
1058
  create(context) {
821
1059
  const isComplexExpression = (node) => {
822
- if (node.type === AST_NODE_TYPES8.SpreadElement) {
1060
+ if (node.type === AST_NODE_TYPES11.SpreadElement) {
823
1061
  return false;
824
1062
  }
825
- if (node.type === AST_NODE_TYPES8.ConditionalExpression) {
1063
+ if (node.type === AST_NODE_TYPES11.ConditionalExpression) {
826
1064
  return true;
827
1065
  }
828
- if (node.type === AST_NODE_TYPES8.LogicalExpression) {
1066
+ if (node.type === AST_NODE_TYPES11.LogicalExpression) {
829
1067
  return true;
830
1068
  }
831
- if (node.type === AST_NODE_TYPES8.BinaryExpression) {
1069
+ if (node.type === AST_NODE_TYPES11.BinaryExpression) {
832
1070
  const logicalOperators = ["==", "===", "!=", "!==", "<", ">", "<=", ">=", "in", "instanceof"];
833
1071
  return logicalOperators.includes(node.operator);
834
1072
  }
835
- if (node.type === AST_NODE_TYPES8.UnaryExpression) {
1073
+ if (node.type === AST_NODE_TYPES11.UnaryExpression) {
836
1074
  return node.operator === "!";
837
1075
  }
838
1076
  return false;
@@ -863,12 +1101,263 @@ var noLogicInParams = createRule12({
863
1101
  });
864
1102
  var no_logic_in_params_default = noLogicInParams;
865
1103
 
1104
+ // src/rules/no-lazy-identifiers.ts
1105
+ import { ESLintUtils as ESLintUtils15, AST_NODE_TYPES as AST_NODE_TYPES12 } from "@typescript-eslint/utils";
1106
+ var createRule15 = ESLintUtils15.RuleCreator(
1107
+ (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
1108
+ );
1109
+ var KEYBOARD_ROWS = ["qwertyuiop", "asdfghjkl", "zxcvbnm", "1234567890"];
1110
+ var MIN_LENGTH = 3;
1111
+ var MIN_SEQUENCE_LENGTH = 4;
1112
+ var hasRepeatedChars = (name) => {
1113
+ const lowerName = name.toLowerCase();
1114
+ return lowerName.split("").some((char, index) => {
1115
+ if (index > lowerName.length - 3) {
1116
+ return false;
1117
+ }
1118
+ return char === lowerName[index + 1] && char === lowerName[index + 2];
1119
+ });
1120
+ };
1121
+ var hasKeyboardSequence = (name) => {
1122
+ const lowerName = name.toLowerCase();
1123
+ if (lowerName.length < MIN_SEQUENCE_LENGTH) {
1124
+ return false;
1125
+ }
1126
+ return KEYBOARD_ROWS.some((row) => {
1127
+ const positions = Array.from({ length: row.length - MIN_SEQUENCE_LENGTH + 1 }, (_, i) => i);
1128
+ return positions.some((start) => {
1129
+ const sequence = row.slice(start, start + MIN_SEQUENCE_LENGTH);
1130
+ const reverseSequence = sequence.split("").reverse().join("");
1131
+ return lowerName.includes(sequence) || lowerName.includes(reverseSequence);
1132
+ });
1133
+ });
1134
+ };
1135
+ var isLazyIdentifier = (name) => {
1136
+ if (name.length < MIN_LENGTH) {
1137
+ return false;
1138
+ }
1139
+ if (name.startsWith("_")) {
1140
+ return false;
1141
+ }
1142
+ if (hasRepeatedChars(name)) {
1143
+ return true;
1144
+ }
1145
+ if (hasKeyboardSequence(name)) {
1146
+ return true;
1147
+ }
1148
+ return false;
1149
+ };
1150
+ var noLazyIdentifiers = createRule15({
1151
+ name: "no-lazy-identifiers",
1152
+ meta: {
1153
+ type: "problem",
1154
+ docs: {
1155
+ description: "Disallow lazy, meaningless variable names that hurt code readability"
1156
+ },
1157
+ messages: {
1158
+ noLazyIdentifier: "Avoid lazy identifier '{{name}}'. Use a descriptive name that clearly indicates the purpose."
1159
+ },
1160
+ schema: []
1161
+ },
1162
+ defaultOptions: [],
1163
+ create(context) {
1164
+ const checkIdentifier = (node) => {
1165
+ const { name } = node;
1166
+ if (!isLazyIdentifier(name)) {
1167
+ return;
1168
+ }
1169
+ context.report({
1170
+ node,
1171
+ messageId: "noLazyIdentifier",
1172
+ data: { name }
1173
+ });
1174
+ };
1175
+ const checkPattern = (pattern) => {
1176
+ if (pattern.type === AST_NODE_TYPES12.Identifier) {
1177
+ checkIdentifier(pattern);
1178
+ } else if (pattern.type === AST_NODE_TYPES12.ObjectPattern) {
1179
+ pattern.properties.forEach((prop) => {
1180
+ if (prop.type === AST_NODE_TYPES12.Property && prop.value.type === AST_NODE_TYPES12.Identifier) {
1181
+ checkIdentifier(prop.value);
1182
+ } else if (prop.type === AST_NODE_TYPES12.RestElement && prop.argument.type === AST_NODE_TYPES12.Identifier) {
1183
+ checkIdentifier(prop.argument);
1184
+ }
1185
+ });
1186
+ } else if (pattern.type === AST_NODE_TYPES12.ArrayPattern) {
1187
+ pattern.elements.forEach((element) => {
1188
+ if (element?.type === AST_NODE_TYPES12.Identifier) {
1189
+ checkIdentifier(element);
1190
+ } else if (element?.type === AST_NODE_TYPES12.RestElement && element.argument.type === AST_NODE_TYPES12.Identifier) {
1191
+ checkIdentifier(element.argument);
1192
+ }
1193
+ });
1194
+ } else if (pattern.type === AST_NODE_TYPES12.AssignmentPattern && pattern.left.type === AST_NODE_TYPES12.Identifier) {
1195
+ checkIdentifier(pattern.left);
1196
+ } else if (pattern.type === AST_NODE_TYPES12.RestElement && pattern.argument.type === AST_NODE_TYPES12.Identifier) {
1197
+ checkIdentifier(pattern.argument);
1198
+ }
1199
+ };
1200
+ return {
1201
+ VariableDeclarator(node) {
1202
+ checkPattern(node.id);
1203
+ },
1204
+ FunctionDeclaration(node) {
1205
+ if (node.id) {
1206
+ checkIdentifier(node.id);
1207
+ }
1208
+ node.params.forEach((param) => checkPattern(param));
1209
+ },
1210
+ FunctionExpression(node) {
1211
+ if (node.id) {
1212
+ checkIdentifier(node.id);
1213
+ }
1214
+ node.params.forEach((param) => checkPattern(param));
1215
+ },
1216
+ ArrowFunctionExpression(node) {
1217
+ node.params.forEach((param) => checkPattern(param));
1218
+ },
1219
+ CatchClause(node) {
1220
+ if (node.param) {
1221
+ checkPattern(node.param);
1222
+ }
1223
+ },
1224
+ ClassDeclaration(node) {
1225
+ if (node.id) {
1226
+ checkIdentifier(node.id);
1227
+ }
1228
+ },
1229
+ TSTypeAliasDeclaration(node) {
1230
+ checkIdentifier(node.id);
1231
+ },
1232
+ TSInterfaceDeclaration(node) {
1233
+ checkIdentifier(node.id);
1234
+ }
1235
+ };
1236
+ }
1237
+ });
1238
+ var no_lazy_identifiers_default = noLazyIdentifiers;
1239
+
1240
+ // src/rules/no-single-char-variables.ts
1241
+ import { ESLintUtils as ESLintUtils16, AST_NODE_TYPES as AST_NODE_TYPES13 } from "@typescript-eslint/utils";
1242
+ var createRule16 = ESLintUtils16.RuleCreator(
1243
+ (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
1244
+ );
1245
+ var ALLOWED_IN_FOR_LOOPS = /* @__PURE__ */ new Set(["i", "j", "k", "n"]);
1246
+ var ALLOWED_UNDERSCORE = "_";
1247
+ var isForLoopInit = (node) => {
1248
+ let current = node;
1249
+ while (current) {
1250
+ const parentNode = current.parent;
1251
+ if (!parentNode) {
1252
+ return false;
1253
+ }
1254
+ if (parentNode.type === AST_NODE_TYPES13.ForStatement) {
1255
+ const { init } = parentNode;
1256
+ if (init && init === current) {
1257
+ return true;
1258
+ }
1259
+ }
1260
+ current = parentNode;
1261
+ }
1262
+ return false;
1263
+ };
1264
+ var isAllowedInContext = (name, node) => {
1265
+ if (name === ALLOWED_UNDERSCORE) {
1266
+ return true;
1267
+ }
1268
+ if (ALLOWED_IN_FOR_LOOPS.has(name) && isForLoopInit(node)) {
1269
+ return true;
1270
+ }
1271
+ return false;
1272
+ };
1273
+ var noSingleCharVariables = createRule16({
1274
+ name: "no-single-char-variables",
1275
+ meta: {
1276
+ type: "suggestion",
1277
+ docs: {
1278
+ description: "Disallow single character variable and parameter names for better code readability"
1279
+ },
1280
+ messages: {
1281
+ noSingleChar: "Avoid single character variable name '{{name}}'. Use a descriptive name that clearly indicates the purpose."
1282
+ },
1283
+ schema: []
1284
+ },
1285
+ defaultOptions: [],
1286
+ create(context) {
1287
+ const checkIdentifier = (node, declarationNode) => {
1288
+ const { name } = node;
1289
+ if (name.length !== 1) {
1290
+ return;
1291
+ }
1292
+ if (isAllowedInContext(name, declarationNode)) {
1293
+ return;
1294
+ }
1295
+ context.report({
1296
+ node,
1297
+ messageId: "noSingleChar",
1298
+ data: { name }
1299
+ });
1300
+ };
1301
+ const checkPattern = (pattern, declarationNode) => {
1302
+ if (pattern.type === AST_NODE_TYPES13.Identifier) {
1303
+ checkIdentifier(pattern, declarationNode);
1304
+ } else if (pattern.type === AST_NODE_TYPES13.ObjectPattern) {
1305
+ pattern.properties.forEach((prop) => {
1306
+ if (prop.type === AST_NODE_TYPES13.Property && prop.value.type === AST_NODE_TYPES13.Identifier) {
1307
+ checkIdentifier(prop.value, declarationNode);
1308
+ } else if (prop.type === AST_NODE_TYPES13.RestElement && prop.argument.type === AST_NODE_TYPES13.Identifier) {
1309
+ checkIdentifier(prop.argument, declarationNode);
1310
+ }
1311
+ });
1312
+ } else if (pattern.type === AST_NODE_TYPES13.ArrayPattern) {
1313
+ pattern.elements.forEach((element) => {
1314
+ if (element?.type === AST_NODE_TYPES13.Identifier) {
1315
+ checkIdentifier(element, declarationNode);
1316
+ } else if (element?.type === AST_NODE_TYPES13.RestElement && element.argument.type === AST_NODE_TYPES13.Identifier) {
1317
+ checkIdentifier(element.argument, declarationNode);
1318
+ }
1319
+ });
1320
+ } else if (pattern.type === AST_NODE_TYPES13.AssignmentPattern && pattern.left.type === AST_NODE_TYPES13.Identifier) {
1321
+ checkIdentifier(pattern.left, declarationNode);
1322
+ } else if (pattern.type === AST_NODE_TYPES13.RestElement && pattern.argument.type === AST_NODE_TYPES13.Identifier) {
1323
+ checkIdentifier(pattern.argument, declarationNode);
1324
+ }
1325
+ };
1326
+ return {
1327
+ VariableDeclarator(node) {
1328
+ checkPattern(node.id, node);
1329
+ },
1330
+ FunctionDeclaration(node) {
1331
+ if (node.id) {
1332
+ checkIdentifier(node.id, node);
1333
+ }
1334
+ node.params.forEach((param) => checkPattern(param, node));
1335
+ },
1336
+ FunctionExpression(node) {
1337
+ if (node.id) {
1338
+ checkIdentifier(node.id, node);
1339
+ }
1340
+ node.params.forEach((param) => checkPattern(param, node));
1341
+ },
1342
+ ArrowFunctionExpression(node) {
1343
+ node.params.forEach((param) => checkPattern(param, node));
1344
+ },
1345
+ CatchClause(node) {
1346
+ if (node.param) {
1347
+ checkPattern(node.param, node);
1348
+ }
1349
+ }
1350
+ };
1351
+ }
1352
+ });
1353
+ var no_single_char_variables_default = noSingleCharVariables;
1354
+
866
1355
  // src/rules/prefer-destructuring-params.ts
867
- import { AST_NODE_TYPES as AST_NODE_TYPES9, ESLintUtils as ESLintUtils13 } from "@typescript-eslint/utils";
868
- var createRule13 = ESLintUtils13.RuleCreator(
1356
+ import { AST_NODE_TYPES as AST_NODE_TYPES14, ESLintUtils as ESLintUtils17 } from "@typescript-eslint/utils";
1357
+ var createRule17 = ESLintUtils17.RuleCreator(
869
1358
  (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
870
1359
  );
871
- var preferDestructuringParams = createRule13({
1360
+ var preferDestructuringParams = createRule17({
872
1361
  name: "prefer-destructuring-params",
873
1362
  meta: {
874
1363
  type: "suggestion",
@@ -882,20 +1371,20 @@ var preferDestructuringParams = createRule13({
882
1371
  },
883
1372
  defaultOptions: [],
884
1373
  create(context) {
885
- const isCallbackFunction = (node) => {
1374
+ const isCallbackFunction2 = (node) => {
886
1375
  const { parent } = node;
887
- return parent?.type === AST_NODE_TYPES9.CallExpression;
1376
+ return parent?.type === AST_NODE_TYPES14.CallExpression;
888
1377
  };
889
1378
  const isDeveloperFunction = (node) => {
890
- if (node.type === AST_NODE_TYPES9.FunctionDeclaration) {
1379
+ if (node.type === AST_NODE_TYPES14.FunctionDeclaration) {
891
1380
  return true;
892
1381
  }
893
- if (node.type === AST_NODE_TYPES9.FunctionExpression || node.type === AST_NODE_TYPES9.ArrowFunctionExpression) {
894
- if (isCallbackFunction(node)) {
1382
+ if (node.type === AST_NODE_TYPES14.FunctionExpression || node.type === AST_NODE_TYPES14.ArrowFunctionExpression) {
1383
+ if (isCallbackFunction2(node)) {
895
1384
  return false;
896
1385
  }
897
1386
  const { parent } = node;
898
- return parent?.type === AST_NODE_TYPES9.VariableDeclarator || parent?.type === AST_NODE_TYPES9.AssignmentExpression || parent?.type === AST_NODE_TYPES9.Property || parent?.type === AST_NODE_TYPES9.MethodDefinition;
1387
+ return parent?.type === AST_NODE_TYPES14.VariableDeclarator || parent?.type === AST_NODE_TYPES14.AssignmentExpression || parent?.type === AST_NODE_TYPES14.Property || parent?.type === AST_NODE_TYPES14.MethodDefinition;
899
1388
  }
900
1389
  return false;
901
1390
  };
@@ -907,7 +1396,7 @@ var preferDestructuringParams = createRule13({
907
1396
  if (!isDeveloperFunction(node)) {
908
1397
  return;
909
1398
  }
910
- if (node.type === AST_NODE_TYPES9.FunctionDeclaration && node.id) {
1399
+ if (node.type === AST_NODE_TYPES14.FunctionDeclaration && node.id) {
911
1400
  const functionName = node.id.name;
912
1401
  if (functionName.startsWith("_") || functionName.includes("$") || /^[A-Z][a-zA-Z]*$/.test(functionName)) {
913
1402
  return;
@@ -917,7 +1406,7 @@ var preferDestructuringParams = createRule13({
917
1406
  return;
918
1407
  }
919
1408
  const hasNonDestructuredParams = node.params.some(
920
- (param) => param.type !== AST_NODE_TYPES9.ObjectPattern && param.type !== AST_NODE_TYPES9.RestElement
1409
+ (param) => param.type !== AST_NODE_TYPES14.ObjectPattern && param.type !== AST_NODE_TYPES14.RestElement
921
1410
  );
922
1411
  if (hasNonDestructuredParams) {
923
1412
  context.report({
@@ -935,12 +1424,103 @@ var preferDestructuringParams = createRule13({
935
1424
  });
936
1425
  var prefer_destructuring_params_default = preferDestructuringParams;
937
1426
 
1427
+ // src/rules/prefer-function-declaration.ts
1428
+ import { ESLintUtils as ESLintUtils18, AST_NODE_TYPES as AST_NODE_TYPES15 } from "@typescript-eslint/utils";
1429
+ var createRule18 = ESLintUtils18.RuleCreator(
1430
+ (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
1431
+ );
1432
+ var isTsFile = (filename) => filename.endsWith(".ts") && !filename.endsWith(".d.ts");
1433
+ var isCallbackContext = (node) => {
1434
+ const { parent } = node;
1435
+ if (!parent) {
1436
+ return false;
1437
+ }
1438
+ if (parent.type === AST_NODE_TYPES15.CallExpression && parent.arguments.includes(node)) {
1439
+ return true;
1440
+ }
1441
+ if (parent.type === AST_NODE_TYPES15.NewExpression && parent.arguments.includes(node)) {
1442
+ return true;
1443
+ }
1444
+ if (parent.type === AST_NODE_TYPES15.ReturnStatement) {
1445
+ return true;
1446
+ }
1447
+ if (parent.type === AST_NODE_TYPES15.Property) {
1448
+ return true;
1449
+ }
1450
+ if (parent.type === AST_NODE_TYPES15.ArrayExpression) {
1451
+ return true;
1452
+ }
1453
+ if (parent.type === AST_NODE_TYPES15.ConditionalExpression) {
1454
+ return true;
1455
+ }
1456
+ if (parent.type === AST_NODE_TYPES15.LogicalExpression) {
1457
+ return true;
1458
+ }
1459
+ if (parent.type === AST_NODE_TYPES15.AssignmentExpression && parent.left !== node) {
1460
+ return true;
1461
+ }
1462
+ return false;
1463
+ };
1464
+ var preferFunctionDeclaration = createRule18({
1465
+ name: "prefer-function-declaration",
1466
+ meta: {
1467
+ type: "suggestion",
1468
+ docs: {
1469
+ description: "Enforce function declarations over arrow functions assigned to variables in .ts files for better readability and hoisting"
1470
+ },
1471
+ messages: {
1472
+ preferDeclaration: "Use function declaration instead of arrow function. Replace 'const {{name}} = () => ...' with 'function {{name}}() ...'",
1473
+ preferDeclarationExpr: "Use function declaration instead of function expression. Replace 'const {{name}} = function() ...' with 'function {{name}}() ...'"
1474
+ },
1475
+ schema: []
1476
+ },
1477
+ defaultOptions: [],
1478
+ create(context) {
1479
+ const { filename } = context;
1480
+ if (!isTsFile(filename)) {
1481
+ return {};
1482
+ }
1483
+ return {
1484
+ VariableDeclarator(node) {
1485
+ if (node.id.type !== AST_NODE_TYPES15.Identifier) {
1486
+ return;
1487
+ }
1488
+ const { init } = node;
1489
+ if (!init) {
1490
+ return;
1491
+ }
1492
+ if (init.type === AST_NODE_TYPES15.ArrowFunctionExpression) {
1493
+ if (isCallbackContext(init)) {
1494
+ return;
1495
+ }
1496
+ context.report({
1497
+ node: init,
1498
+ messageId: "preferDeclaration",
1499
+ data: { name: node.id.name }
1500
+ });
1501
+ }
1502
+ if (init.type === AST_NODE_TYPES15.FunctionExpression) {
1503
+ if (isCallbackContext(init)) {
1504
+ return;
1505
+ }
1506
+ context.report({
1507
+ node: init,
1508
+ messageId: "preferDeclarationExpr",
1509
+ data: { name: node.id.name }
1510
+ });
1511
+ }
1512
+ }
1513
+ };
1514
+ }
1515
+ });
1516
+ var prefer_function_declaration_default = preferFunctionDeclaration;
1517
+
938
1518
  // src/rules/prefer-import-type.ts
939
- import { AST_NODE_TYPES as AST_NODE_TYPES10, ESLintUtils as ESLintUtils14 } from "@typescript-eslint/utils";
940
- var createRule14 = ESLintUtils14.RuleCreator(
1519
+ import { AST_NODE_TYPES as AST_NODE_TYPES16, ESLintUtils as ESLintUtils19 } from "@typescript-eslint/utils";
1520
+ var createRule19 = ESLintUtils19.RuleCreator(
941
1521
  (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
942
1522
  );
943
- var preferImportType = createRule14({
1523
+ var preferImportType = createRule19({
944
1524
  name: "prefer-import-type",
945
1525
  meta: {
946
1526
  type: "suggestion",
@@ -959,22 +1539,22 @@ var preferImportType = createRule14({
959
1539
  let current = node;
960
1540
  while (current) {
961
1541
  switch (current.type) {
962
- case AST_NODE_TYPES10.TSTypeReference:
963
- case AST_NODE_TYPES10.TSTypeAnnotation:
964
- case AST_NODE_TYPES10.TSTypeParameterInstantiation:
965
- case AST_NODE_TYPES10.TSInterfaceHeritage:
966
- case AST_NODE_TYPES10.TSClassImplements:
967
- case AST_NODE_TYPES10.TSTypeQuery:
968
- case AST_NODE_TYPES10.TSTypeAssertion:
969
- case AST_NODE_TYPES10.TSAsExpression:
970
- case AST_NODE_TYPES10.TSSatisfiesExpression:
971
- case AST_NODE_TYPES10.TSTypeAliasDeclaration:
972
- case AST_NODE_TYPES10.TSInterfaceDeclaration:
973
- case AST_NODE_TYPES10.TSTypeParameter:
974
- case AST_NODE_TYPES10.TSQualifiedName:
1542
+ case AST_NODE_TYPES16.TSTypeReference:
1543
+ case AST_NODE_TYPES16.TSTypeAnnotation:
1544
+ case AST_NODE_TYPES16.TSTypeParameterInstantiation:
1545
+ case AST_NODE_TYPES16.TSInterfaceHeritage:
1546
+ case AST_NODE_TYPES16.TSClassImplements:
1547
+ case AST_NODE_TYPES16.TSTypeQuery:
1548
+ case AST_NODE_TYPES16.TSTypeAssertion:
1549
+ case AST_NODE_TYPES16.TSAsExpression:
1550
+ case AST_NODE_TYPES16.TSSatisfiesExpression:
1551
+ case AST_NODE_TYPES16.TSTypeAliasDeclaration:
1552
+ case AST_NODE_TYPES16.TSInterfaceDeclaration:
1553
+ case AST_NODE_TYPES16.TSTypeParameter:
1554
+ case AST_NODE_TYPES16.TSQualifiedName:
975
1555
  return true;
976
- case AST_NODE_TYPES10.MemberExpression:
977
- case AST_NODE_TYPES10.Identifier:
1556
+ case AST_NODE_TYPES16.MemberExpression:
1557
+ case AST_NODE_TYPES16.Identifier:
978
1558
  current = current.parent;
979
1559
  break;
980
1560
  default:
@@ -1004,26 +1584,26 @@ var preferImportType = createRule14({
1004
1584
  return false;
1005
1585
  }
1006
1586
  switch (parent.type) {
1007
- case AST_NODE_TYPES10.CallExpression:
1008
- case AST_NODE_TYPES10.NewExpression:
1009
- case AST_NODE_TYPES10.JSXOpeningElement:
1010
- case AST_NODE_TYPES10.JSXClosingElement:
1011
- case AST_NODE_TYPES10.MemberExpression:
1012
- case AST_NODE_TYPES10.VariableDeclarator:
1013
- case AST_NODE_TYPES10.TaggedTemplateExpression:
1014
- case AST_NODE_TYPES10.SpreadElement:
1015
- case AST_NODE_TYPES10.ExportSpecifier:
1016
- case AST_NODE_TYPES10.ArrayExpression:
1017
- case AST_NODE_TYPES10.ObjectExpression:
1018
- case AST_NODE_TYPES10.BinaryExpression:
1019
- case AST_NODE_TYPES10.LogicalExpression:
1020
- case AST_NODE_TYPES10.UnaryExpression:
1021
- case AST_NODE_TYPES10.ReturnStatement:
1022
- case AST_NODE_TYPES10.ArrowFunctionExpression:
1023
- case AST_NODE_TYPES10.ConditionalExpression:
1024
- case AST_NODE_TYPES10.AwaitExpression:
1025
- case AST_NODE_TYPES10.YieldExpression:
1026
- case AST_NODE_TYPES10.Property:
1587
+ case AST_NODE_TYPES16.CallExpression:
1588
+ case AST_NODE_TYPES16.NewExpression:
1589
+ case AST_NODE_TYPES16.JSXOpeningElement:
1590
+ case AST_NODE_TYPES16.JSXClosingElement:
1591
+ case AST_NODE_TYPES16.MemberExpression:
1592
+ case AST_NODE_TYPES16.VariableDeclarator:
1593
+ case AST_NODE_TYPES16.TaggedTemplateExpression:
1594
+ case AST_NODE_TYPES16.SpreadElement:
1595
+ case AST_NODE_TYPES16.ExportSpecifier:
1596
+ case AST_NODE_TYPES16.ArrayExpression:
1597
+ case AST_NODE_TYPES16.ObjectExpression:
1598
+ case AST_NODE_TYPES16.BinaryExpression:
1599
+ case AST_NODE_TYPES16.LogicalExpression:
1600
+ case AST_NODE_TYPES16.UnaryExpression:
1601
+ case AST_NODE_TYPES16.ReturnStatement:
1602
+ case AST_NODE_TYPES16.ArrowFunctionExpression:
1603
+ case AST_NODE_TYPES16.ConditionalExpression:
1604
+ case AST_NODE_TYPES16.AwaitExpression:
1605
+ case AST_NODE_TYPES16.YieldExpression:
1606
+ case AST_NODE_TYPES16.Property:
1027
1607
  return true;
1028
1608
  default:
1029
1609
  return false;
@@ -1047,13 +1627,13 @@ var preferImportType = createRule14({
1047
1627
  }
1048
1628
  const scope = context.sourceCode.getScope(node);
1049
1629
  const isTypeOnlyImport = node.specifiers.every((specifier) => {
1050
- if (specifier.type === AST_NODE_TYPES10.ImportDefaultSpecifier) {
1630
+ if (specifier.type === AST_NODE_TYPES16.ImportDefaultSpecifier) {
1051
1631
  return false;
1052
1632
  }
1053
- if (specifier.type === AST_NODE_TYPES10.ImportNamespaceSpecifier) {
1633
+ if (specifier.type === AST_NODE_TYPES16.ImportNamespaceSpecifier) {
1054
1634
  return false;
1055
1635
  }
1056
- if (specifier.type === AST_NODE_TYPES10.ImportSpecifier) {
1636
+ if (specifier.type === AST_NODE_TYPES16.ImportSpecifier) {
1057
1637
  const localName = specifier.local.name;
1058
1638
  return !isUsedAsValue(localName, scope);
1059
1639
  }
@@ -1079,11 +1659,11 @@ var preferImportType = createRule14({
1079
1659
  var prefer_import_type_default = preferImportType;
1080
1660
 
1081
1661
  // src/rules/prefer-interface-over-inline-types.ts
1082
- import { AST_NODE_TYPES as AST_NODE_TYPES11, ESLintUtils as ESLintUtils15 } from "@typescript-eslint/utils";
1083
- var createRule15 = ESLintUtils15.RuleCreator(
1662
+ import { AST_NODE_TYPES as AST_NODE_TYPES17, ESLintUtils as ESLintUtils20 } from "@typescript-eslint/utils";
1663
+ var createRule20 = ESLintUtils20.RuleCreator(
1084
1664
  (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
1085
1665
  );
1086
- var preferInterfaceOverInlineTypes = createRule15({
1666
+ var preferInterfaceOverInlineTypes = createRule20({
1087
1667
  name: "prefer-interface-over-inline-types",
1088
1668
  meta: {
1089
1669
  type: "suggestion",
@@ -1099,67 +1679,67 @@ var preferInterfaceOverInlineTypes = createRule15({
1099
1679
  defaultOptions: [],
1100
1680
  create(context) {
1101
1681
  function hasJSXInConditional(node) {
1102
- return node.consequent.type === AST_NODE_TYPES11.JSXElement || node.consequent.type === AST_NODE_TYPES11.JSXFragment || node.alternate.type === AST_NODE_TYPES11.JSXElement || node.alternate.type === AST_NODE_TYPES11.JSXFragment;
1682
+ return node.consequent.type === AST_NODE_TYPES17.JSXElement || node.consequent.type === AST_NODE_TYPES17.JSXFragment || node.alternate.type === AST_NODE_TYPES17.JSXElement || node.alternate.type === AST_NODE_TYPES17.JSXFragment;
1103
1683
  }
1104
1684
  function hasJSXInLogical(node) {
1105
- return node.right.type === AST_NODE_TYPES11.JSXElement || node.right.type === AST_NODE_TYPES11.JSXFragment;
1685
+ return node.right.type === AST_NODE_TYPES17.JSXElement || node.right.type === AST_NODE_TYPES17.JSXFragment;
1106
1686
  }
1107
1687
  function hasJSXReturn(block) {
1108
1688
  return block.body.some((stmt) => {
1109
- if (stmt.type === AST_NODE_TYPES11.ReturnStatement && stmt.argument) {
1110
- return stmt.argument.type === AST_NODE_TYPES11.JSXElement || stmt.argument.type === AST_NODE_TYPES11.JSXFragment || stmt.argument.type === AST_NODE_TYPES11.ConditionalExpression && hasJSXInConditional(stmt.argument) || stmt.argument.type === AST_NODE_TYPES11.LogicalExpression && hasJSXInLogical(stmt.argument);
1689
+ if (stmt.type === AST_NODE_TYPES17.ReturnStatement && stmt.argument) {
1690
+ return stmt.argument.type === AST_NODE_TYPES17.JSXElement || stmt.argument.type === AST_NODE_TYPES17.JSXFragment || stmt.argument.type === AST_NODE_TYPES17.ConditionalExpression && hasJSXInConditional(stmt.argument) || stmt.argument.type === AST_NODE_TYPES17.LogicalExpression && hasJSXInLogical(stmt.argument);
1111
1691
  }
1112
1692
  return false;
1113
1693
  });
1114
1694
  }
1115
- function isReactComponent(node) {
1116
- if (node.type === AST_NODE_TYPES11.ArrowFunctionExpression) {
1117
- if (node.body.type === AST_NODE_TYPES11.JSXElement || node.body.type === AST_NODE_TYPES11.JSXFragment) {
1695
+ function isReactComponent2(node) {
1696
+ if (node.type === AST_NODE_TYPES17.ArrowFunctionExpression) {
1697
+ if (node.body.type === AST_NODE_TYPES17.JSXElement || node.body.type === AST_NODE_TYPES17.JSXFragment) {
1118
1698
  return true;
1119
1699
  }
1120
- if (node.body.type === AST_NODE_TYPES11.BlockStatement) {
1700
+ if (node.body.type === AST_NODE_TYPES17.BlockStatement) {
1121
1701
  return hasJSXReturn(node.body);
1122
1702
  }
1123
- } else if (node.type === AST_NODE_TYPES11.FunctionExpression || node.type === AST_NODE_TYPES11.FunctionDeclaration) {
1124
- if (node.body && node.body.type === AST_NODE_TYPES11.BlockStatement) {
1703
+ } else if (node.type === AST_NODE_TYPES17.FunctionExpression || node.type === AST_NODE_TYPES17.FunctionDeclaration) {
1704
+ if (node.body && node.body.type === AST_NODE_TYPES17.BlockStatement) {
1125
1705
  return hasJSXReturn(node.body);
1126
1706
  }
1127
1707
  }
1128
1708
  return false;
1129
1709
  }
1130
1710
  function isInlineTypeAnnotation(node) {
1131
- if (node.type === AST_NODE_TYPES11.TSTypeLiteral) {
1711
+ if (node.type === AST_NODE_TYPES17.TSTypeLiteral) {
1132
1712
  return true;
1133
1713
  }
1134
- if (node.type === AST_NODE_TYPES11.TSTypeReference && node.typeArguments) {
1135
- return node.typeArguments.params.some((param) => param.type === AST_NODE_TYPES11.TSTypeLiteral);
1714
+ if (node.type === AST_NODE_TYPES17.TSTypeReference && node.typeArguments) {
1715
+ return node.typeArguments.params.some((param) => param.type === AST_NODE_TYPES17.TSTypeLiteral);
1136
1716
  }
1137
- if (node.type === AST_NODE_TYPES11.TSUnionType) {
1717
+ if (node.type === AST_NODE_TYPES17.TSUnionType) {
1138
1718
  return node.types.some((type) => isInlineTypeAnnotation(type));
1139
1719
  }
1140
1720
  return false;
1141
1721
  }
1142
1722
  function hasInlineObjectType(node) {
1143
- if (node.type === AST_NODE_TYPES11.TSTypeLiteral) {
1723
+ if (node.type === AST_NODE_TYPES17.TSTypeLiteral) {
1144
1724
  return true;
1145
1725
  }
1146
- if (node.type === AST_NODE_TYPES11.TSTypeReference && node.typeArguments) {
1147
- return node.typeArguments.params.some((param) => param.type === AST_NODE_TYPES11.TSTypeLiteral);
1726
+ if (node.type === AST_NODE_TYPES17.TSTypeReference && node.typeArguments) {
1727
+ return node.typeArguments.params.some((param) => param.type === AST_NODE_TYPES17.TSTypeLiteral);
1148
1728
  }
1149
- if (node.type === AST_NODE_TYPES11.TSUnionType) {
1729
+ if (node.type === AST_NODE_TYPES17.TSUnionType) {
1150
1730
  return node.types.some((type) => hasInlineObjectType(type));
1151
1731
  }
1152
1732
  return false;
1153
1733
  }
1154
1734
  function checkFunction(node) {
1155
- if (!isReactComponent(node)) {
1735
+ if (!isReactComponent2(node)) {
1156
1736
  return;
1157
1737
  }
1158
1738
  if (node.params.length !== 1) {
1159
1739
  return;
1160
1740
  }
1161
1741
  const param = node.params[0];
1162
- if (param.type === AST_NODE_TYPES11.Identifier && param.typeAnnotation) {
1742
+ if (param.type === AST_NODE_TYPES17.Identifier && param.typeAnnotation) {
1163
1743
  const { typeAnnotation } = param.typeAnnotation;
1164
1744
  if (isInlineTypeAnnotation(typeAnnotation) && hasInlineObjectType(typeAnnotation)) {
1165
1745
  context.report({
@@ -1179,11 +1759,11 @@ var preferInterfaceOverInlineTypes = createRule15({
1179
1759
  var prefer_interface_over_inline_types_default = preferInterfaceOverInlineTypes;
1180
1760
 
1181
1761
  // src/rules/prefer-jsx-template-literals.ts
1182
- import { AST_NODE_TYPES as AST_NODE_TYPES12, ESLintUtils as ESLintUtils16 } from "@typescript-eslint/utils";
1183
- var createRule16 = ESLintUtils16.RuleCreator(
1762
+ import { AST_NODE_TYPES as AST_NODE_TYPES18, ESLintUtils as ESLintUtils21 } from "@typescript-eslint/utils";
1763
+ var createRule21 = ESLintUtils21.RuleCreator(
1184
1764
  (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
1185
1765
  );
1186
- var preferJSXTemplateLiterals = createRule16({
1766
+ var preferJSXTemplateLiterals = createRule21({
1187
1767
  name: "prefer-jsx-template-literals",
1188
1768
  meta: {
1189
1769
  type: "suggestion",
@@ -1252,9 +1832,9 @@ var preferJSXTemplateLiterals = createRule16({
1252
1832
  if (!child || !nextChild) {
1253
1833
  return;
1254
1834
  }
1255
- if (child.type === AST_NODE_TYPES12.JSXText && nextChild.type === AST_NODE_TYPES12.JSXExpressionContainer) {
1835
+ if (child.type === AST_NODE_TYPES18.JSXText && nextChild.type === AST_NODE_TYPES18.JSXExpressionContainer) {
1256
1836
  handleTextBeforeExpression(child, nextChild);
1257
- } else if (child.type === AST_NODE_TYPES12.JSXExpressionContainer && nextChild.type === AST_NODE_TYPES12.JSXText) {
1837
+ } else if (child.type === AST_NODE_TYPES18.JSXExpressionContainer && nextChild.type === AST_NODE_TYPES18.JSXText) {
1258
1838
  handleExpressionBeforeText(child, nextChild);
1259
1839
  }
1260
1840
  }
@@ -1267,11 +1847,11 @@ var preferJSXTemplateLiterals = createRule16({
1267
1847
  var prefer_jsx_template_literals_default = preferJSXTemplateLiterals;
1268
1848
 
1269
1849
  // src/rules/prefer-named-param-types.ts
1270
- import { AST_NODE_TYPES as AST_NODE_TYPES13, ESLintUtils as ESLintUtils17 } from "@typescript-eslint/utils";
1271
- var createRule17 = ESLintUtils17.RuleCreator(
1850
+ import { AST_NODE_TYPES as AST_NODE_TYPES19, ESLintUtils as ESLintUtils22 } from "@typescript-eslint/utils";
1851
+ var createRule22 = ESLintUtils22.RuleCreator(
1272
1852
  (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
1273
1853
  );
1274
- var preferNamedParamTypes = createRule17({
1854
+ var preferNamedParamTypes = createRule22({
1275
1855
  name: "prefer-named-param-types",
1276
1856
  meta: {
1277
1857
  type: "suggestion",
@@ -1286,16 +1866,16 @@ var preferNamedParamTypes = createRule17({
1286
1866
  defaultOptions: [],
1287
1867
  create(context) {
1288
1868
  function hasInlineObjectType(param) {
1289
- if (param.type === AST_NODE_TYPES13.AssignmentPattern) {
1869
+ if (param.type === AST_NODE_TYPES19.AssignmentPattern) {
1290
1870
  return hasInlineObjectType(param.left);
1291
1871
  }
1292
- if (param.type === AST_NODE_TYPES13.ObjectPattern) {
1293
- if (param.typeAnnotation?.typeAnnotation.type === AST_NODE_TYPES13.TSTypeLiteral) {
1872
+ if (param.type === AST_NODE_TYPES19.ObjectPattern) {
1873
+ if (param.typeAnnotation?.typeAnnotation.type === AST_NODE_TYPES19.TSTypeLiteral) {
1294
1874
  return true;
1295
1875
  }
1296
1876
  }
1297
- if (param.type === AST_NODE_TYPES13.Identifier) {
1298
- if (param.typeAnnotation?.typeAnnotation.type === AST_NODE_TYPES13.TSTypeLiteral) {
1877
+ if (param.type === AST_NODE_TYPES19.Identifier) {
1878
+ if (param.typeAnnotation?.typeAnnotation.type === AST_NODE_TYPES19.TSTypeLiteral) {
1299
1879
  return true;
1300
1880
  }
1301
1881
  }
@@ -1329,11 +1909,11 @@ var preferNamedParamTypes = createRule17({
1329
1909
  var prefer_named_param_types_default = preferNamedParamTypes;
1330
1910
 
1331
1911
  // src/rules/prefer-react-import-types.ts
1332
- import { AST_NODE_TYPES as AST_NODE_TYPES14, ESLintUtils as ESLintUtils18 } from "@typescript-eslint/utils";
1333
- var createRule18 = ESLintUtils18.RuleCreator(
1912
+ import { AST_NODE_TYPES as AST_NODE_TYPES20, ESLintUtils as ESLintUtils23 } from "@typescript-eslint/utils";
1913
+ var createRule23 = ESLintUtils23.RuleCreator(
1334
1914
  (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
1335
1915
  );
1336
- var preferReactImportTypes = createRule18({
1916
+ var preferReactImportTypes = createRule23({
1337
1917
  name: "prefer-react-import-types",
1338
1918
  meta: {
1339
1919
  type: "suggestion",
@@ -1409,7 +1989,7 @@ var preferReactImportTypes = createRule18({
1409
1989
  ]);
1410
1990
  const allReactExports = /* @__PURE__ */ new Set([...reactTypes, ...reactRuntimeExports]);
1411
1991
  function checkMemberExpression(node) {
1412
- if (node.object.type === AST_NODE_TYPES14.Identifier && node.object.name === "React" && node.property.type === AST_NODE_TYPES14.Identifier && allReactExports.has(node.property.name)) {
1992
+ if (node.object.type === AST_NODE_TYPES20.Identifier && node.object.name === "React" && node.property.type === AST_NODE_TYPES20.Identifier && allReactExports.has(node.property.name)) {
1413
1993
  const typeName = node.property.name;
1414
1994
  const isType = reactTypes.has(typeName);
1415
1995
  const importStatement = isType ? `import type { ${typeName} } from "react"` : `import { ${typeName} } from "react"`;
@@ -1426,7 +2006,7 @@ var preferReactImportTypes = createRule18({
1426
2006
  return {
1427
2007
  MemberExpression: checkMemberExpression,
1428
2008
  "TSTypeReference > TSQualifiedName": (node) => {
1429
- if (node.left.type === AST_NODE_TYPES14.Identifier && node.left.name === "React" && node.right.type === AST_NODE_TYPES14.Identifier && allReactExports.has(node.right.name)) {
2009
+ if (node.left.type === AST_NODE_TYPES20.Identifier && node.left.name === "React" && node.right.type === AST_NODE_TYPES20.Identifier && allReactExports.has(node.right.name)) {
1430
2010
  const typeName = node.right.name;
1431
2011
  const isType = reactTypes.has(typeName);
1432
2012
  const importStatement = isType ? `import type { ${typeName} } from "react"` : `import { ${typeName} } from "react"`;
@@ -1446,11 +2026,11 @@ var preferReactImportTypes = createRule18({
1446
2026
  var prefer_react_import_types_default = preferReactImportTypes;
1447
2027
 
1448
2028
  // src/rules/react-props-destructure.ts
1449
- import { AST_NODE_TYPES as AST_NODE_TYPES15, ESLintUtils as ESLintUtils19 } from "@typescript-eslint/utils";
1450
- var createRule19 = ESLintUtils19.RuleCreator(
2029
+ import { AST_NODE_TYPES as AST_NODE_TYPES21, ESLintUtils as ESLintUtils24 } from "@typescript-eslint/utils";
2030
+ var createRule24 = ESLintUtils24.RuleCreator(
1451
2031
  (name) => `https://github.com/next-friday/eslint-plugin-nextfriday/blob/main/docs/rules/${name.replaceAll("-", "_").toUpperCase()}.md`
1452
2032
  );
1453
- var reactPropsDestructure = createRule19({
2033
+ var reactPropsDestructure = createRule24({
1454
2034
  name: "react-props-destructure",
1455
2035
  meta: {
1456
2036
  type: "suggestion",
@@ -1466,45 +2046,45 @@ var reactPropsDestructure = createRule19({
1466
2046
  defaultOptions: [],
1467
2047
  create(context) {
1468
2048
  function hasJSXInConditional(node) {
1469
- return node.consequent.type === AST_NODE_TYPES15.JSXElement || node.consequent.type === AST_NODE_TYPES15.JSXFragment || node.alternate.type === AST_NODE_TYPES15.JSXElement || node.alternate.type === AST_NODE_TYPES15.JSXFragment;
2049
+ return node.consequent.type === AST_NODE_TYPES21.JSXElement || node.consequent.type === AST_NODE_TYPES21.JSXFragment || node.alternate.type === AST_NODE_TYPES21.JSXElement || node.alternate.type === AST_NODE_TYPES21.JSXFragment;
1470
2050
  }
1471
2051
  function hasJSXInLogical(node) {
1472
- return node.right.type === AST_NODE_TYPES15.JSXElement || node.right.type === AST_NODE_TYPES15.JSXFragment;
2052
+ return node.right.type === AST_NODE_TYPES21.JSXElement || node.right.type === AST_NODE_TYPES21.JSXFragment;
1473
2053
  }
1474
2054
  function hasJSXReturn(block) {
1475
2055
  return block.body.some((stmt) => {
1476
- if (stmt.type === AST_NODE_TYPES15.ReturnStatement && stmt.argument) {
1477
- return stmt.argument.type === AST_NODE_TYPES15.JSXElement || stmt.argument.type === AST_NODE_TYPES15.JSXFragment || stmt.argument.type === AST_NODE_TYPES15.ConditionalExpression && hasJSXInConditional(stmt.argument) || stmt.argument.type === AST_NODE_TYPES15.LogicalExpression && hasJSXInLogical(stmt.argument);
2056
+ if (stmt.type === AST_NODE_TYPES21.ReturnStatement && stmt.argument) {
2057
+ return stmt.argument.type === AST_NODE_TYPES21.JSXElement || stmt.argument.type === AST_NODE_TYPES21.JSXFragment || stmt.argument.type === AST_NODE_TYPES21.ConditionalExpression && hasJSXInConditional(stmt.argument) || stmt.argument.type === AST_NODE_TYPES21.LogicalExpression && hasJSXInLogical(stmt.argument);
1478
2058
  }
1479
2059
  return false;
1480
2060
  });
1481
2061
  }
1482
- function isReactComponent(node) {
1483
- if (node.type === AST_NODE_TYPES15.ArrowFunctionExpression) {
1484
- if (node.body.type === AST_NODE_TYPES15.JSXElement || node.body.type === AST_NODE_TYPES15.JSXFragment) {
2062
+ function isReactComponent2(node) {
2063
+ if (node.type === AST_NODE_TYPES21.ArrowFunctionExpression) {
2064
+ if (node.body.type === AST_NODE_TYPES21.JSXElement || node.body.type === AST_NODE_TYPES21.JSXFragment) {
1485
2065
  return true;
1486
2066
  }
1487
- if (node.body.type === AST_NODE_TYPES15.BlockStatement) {
2067
+ if (node.body.type === AST_NODE_TYPES21.BlockStatement) {
1488
2068
  return hasJSXReturn(node.body);
1489
2069
  }
1490
- } else if (node.type === AST_NODE_TYPES15.FunctionExpression || node.type === AST_NODE_TYPES15.FunctionDeclaration) {
1491
- if (node.body && node.body.type === AST_NODE_TYPES15.BlockStatement) {
2070
+ } else if (node.type === AST_NODE_TYPES21.FunctionExpression || node.type === AST_NODE_TYPES21.FunctionDeclaration) {
2071
+ if (node.body && node.body.type === AST_NODE_TYPES21.BlockStatement) {
1492
2072
  return hasJSXReturn(node.body);
1493
2073
  }
1494
2074
  }
1495
2075
  return false;
1496
2076
  }
1497
2077
  function checkFunction(node) {
1498
- if (!isReactComponent(node)) {
2078
+ if (!isReactComponent2(node)) {
1499
2079
  return;
1500
2080
  }
1501
2081
  if (node.params.length !== 1) {
1502
2082
  return;
1503
2083
  }
1504
2084
  const param = node.params[0];
1505
- if (param.type === AST_NODE_TYPES15.ObjectPattern) {
1506
- const properties = param.properties.filter((prop) => prop.type === AST_NODE_TYPES15.Property).map((prop) => {
1507
- if (prop.key.type === AST_NODE_TYPES15.Identifier) {
2085
+ if (param.type === AST_NODE_TYPES21.ObjectPattern) {
2086
+ const properties = param.properties.filter((prop) => prop.type === AST_NODE_TYPES21.Property).map((prop) => {
2087
+ if (prop.key.type === AST_NODE_TYPES21.Identifier) {
1508
2088
  return prop.key.name;
1509
2089
  }
1510
2090
  return null;
@@ -1536,6 +2116,7 @@ var meta = {
1536
2116
  version: package_default.version
1537
2117
  };
1538
2118
  var rules = {
2119
+ "boolean-naming-prefix": boolean_naming_prefix_default,
1539
2120
  "enforce-readonly-component-props": enforce_readonly_component_props_default,
1540
2121
  "enforce-sorted-destructuring": enforce_sorted_destructuring_default,
1541
2122
  "file-kebab-case": file_kebab_case_default,
@@ -1544,11 +2125,15 @@ var rules = {
1544
2125
  "jsx-no-variable-in-callback": jsx_no_variable_in_callback_default,
1545
2126
  "md-filename-case-restriction": md_filename_case_restriction_default,
1546
2127
  "no-complex-inline-return": no_complex_inline_return_default,
2128
+ "no-direct-date": no_direct_date_default,
1547
2129
  "no-emoji": no_emoji_default,
1548
2130
  "no-env-fallback": no_env_fallback_default,
1549
- "no-explicit-return-type": no_explicit_return_type_default,
2131
+ "require-explicit-return-type": require_explicit_return_type_default,
2132
+ "no-lazy-identifiers": no_lazy_identifiers_default,
1550
2133
  "no-logic-in-params": no_logic_in_params_default,
2134
+ "no-single-char-variables": no_single_char_variables_default,
1551
2135
  "prefer-destructuring-params": prefer_destructuring_params_default,
2136
+ "prefer-function-declaration": prefer_function_declaration_default,
1552
2137
  "prefer-import-type": prefer_import_type_default,
1553
2138
  "prefer-interface-over-inline-types": prefer_interface_over_inline_types_default,
1554
2139
  "prefer-jsx-template-literals": prefer_jsx_template_literals_default,
@@ -1561,32 +2146,42 @@ var plugin = {
1561
2146
  rules
1562
2147
  };
1563
2148
  var baseRules = {
2149
+ "nextfriday/boolean-naming-prefix": "warn",
1564
2150
  "nextfriday/no-emoji": "warn",
1565
2151
  "nextfriday/enforce-sorted-destructuring": "warn",
1566
2152
  "nextfriday/file-kebab-case": "warn",
1567
2153
  "nextfriday/md-filename-case-restriction": "warn",
1568
2154
  "nextfriday/prefer-destructuring-params": "warn",
1569
- "nextfriday/no-explicit-return-type": "warn",
2155
+ "nextfriday/prefer-function-declaration": "warn",
2156
+ "nextfriday/require-explicit-return-type": "warn",
1570
2157
  "nextfriday/prefer-import-type": "warn",
1571
2158
  "nextfriday/prefer-named-param-types": "warn",
1572
2159
  "nextfriday/prefer-react-import-types": "warn",
1573
2160
  "nextfriday/no-complex-inline-return": "warn",
2161
+ "nextfriday/no-direct-date": "warn",
1574
2162
  "nextfriday/no-logic-in-params": "warn",
1575
- "nextfriday/no-env-fallback": "warn"
2163
+ "nextfriday/no-env-fallback": "warn",
2164
+ "nextfriday/no-lazy-identifiers": "warn",
2165
+ "nextfriday/no-single-char-variables": "warn"
1576
2166
  };
1577
2167
  var baseRecommendedRules = {
2168
+ "nextfriday/boolean-naming-prefix": "error",
1578
2169
  "nextfriday/no-emoji": "error",
1579
2170
  "nextfriday/enforce-sorted-destructuring": "error",
1580
2171
  "nextfriday/file-kebab-case": "error",
1581
2172
  "nextfriday/md-filename-case-restriction": "error",
1582
2173
  "nextfriday/prefer-destructuring-params": "error",
1583
- "nextfriday/no-explicit-return-type": "error",
2174
+ "nextfriday/prefer-function-declaration": "error",
2175
+ "nextfriday/require-explicit-return-type": "error",
1584
2176
  "nextfriday/prefer-import-type": "error",
1585
2177
  "nextfriday/prefer-named-param-types": "error",
1586
2178
  "nextfriday/prefer-react-import-types": "error",
1587
2179
  "nextfriday/no-complex-inline-return": "error",
2180
+ "nextfriday/no-direct-date": "error",
1588
2181
  "nextfriday/no-logic-in-params": "error",
1589
- "nextfriday/no-env-fallback": "error"
2182
+ "nextfriday/no-env-fallback": "error",
2183
+ "nextfriday/no-lazy-identifiers": "error",
2184
+ "nextfriday/no-single-char-variables": "error"
1590
2185
  };
1591
2186
  var jsxRules = {
1592
2187
  "nextfriday/jsx-pascal-case": "warn",