@sarj/eslint-plugin 2.4.0 → 2.5.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/dist/index.cjs CHANGED
@@ -37,7 +37,6 @@ module.exports = __toCommonJS(index_exports);
37
37
 
38
38
  // src/rules/enforce-file-structure.ts
39
39
  var import_utils = require("@typescript-eslint/utils");
40
- var SERVER_ACTION_FILE_RE = /(?:^|\/)actions\/|\.action\.[jt]sx?$|(?:^|\/)actions\.[jt]sx?$/;
41
40
  var classifyStatement = (statement) => {
42
41
  switch (statement.type) {
43
42
  case import_utils.AST_NODE_TYPES.ImportDeclaration:
@@ -52,7 +51,6 @@ var classifyStatement = (statement) => {
52
51
  };
53
52
  var isStringDirective = (statement) => statement.type === import_utils.AST_NODE_TYPES.ExpressionStatement && statement.expression.type === import_utils.AST_NODE_TYPES.Literal && typeof statement.expression.value === "string" && statement.expression.value.startsWith("use ");
54
53
  var isUseServerDirective = (statement) => {
55
- if (statement === void 0) return false;
56
54
  if (statement.type !== import_utils.AST_NODE_TYPES.ExpressionStatement) return false;
57
55
  const expr = statement.expression;
58
56
  if (expr.type !== import_utils.AST_NODE_TYPES.Literal) return false;
@@ -65,23 +63,25 @@ var enforce_file_structure_default = import_utils.ESLintUtils.RuleCreator(
65
63
  meta: {
66
64
  type: "suggestion",
67
65
  docs: {
68
- description: "Require `import` statements to come first, then allow step-down ordering (public API first, private helpers below) for the rest of the file. Exported statements are classified by WHAT they export \u2014 an exported interface is a declaration, an exported function is a function \u2014 so a public exported function followed by a private helper, or an exported interface among declarations, is allowed. Re-exports (`export { \u2026 } from`, `export *`, `export { \u2026 }`) are a neutral group, so generated namespace barrels pass. Server-action files (under `/actions/`, named `*.action.ts`, or `actions.ts`) must also begin with a `use server` directive."
66
+ description: "Require `import` statements to come first, then allow step-down ordering (public API first, private helpers below) for the rest of the file. Exported statements are classified by WHAT they export \u2014 an exported interface is a declaration, an exported function is a function \u2014 so a public exported function followed by a private helper, or an exported interface among declarations, is allowed. Re-exports (`export { \u2026 } from`, `export *`, `export { \u2026 }`) are a neutral group, so generated namespace barrels pass. When a module contains a `use server` directive, it must be the first statement in the file."
69
67
  },
70
68
  schema: [],
71
69
  messages: {
72
70
  importsFirst: "File structure violation: import statements must come before other declarations",
73
- useServerDirective: "Server action files must start with 'use server' directive"
71
+ useServerDirective: "A 'use server' directive must be the first statement in the file"
74
72
  }
75
73
  },
76
74
  defaultOptions: [],
77
75
  create(context) {
78
- const isServerAction = SERVER_ACTION_FILE_RE.test(context.filename);
79
76
  return {
80
77
  Program(node) {
81
78
  const body = node.body;
82
- if (isServerAction && !isUseServerDirective(body[0])) {
79
+ const misplacedUseServer = body.find(
80
+ (statement, index) => index > 0 && isUseServerDirective(statement)
81
+ );
82
+ if (misplacedUseServer !== void 0) {
83
83
  context.report({
84
- node,
84
+ node: misplacedUseServer,
85
85
  messageId: "useServerDirective"
86
86
  });
87
87
  }
@@ -663,12 +663,49 @@ function instanceofErrorSubject(test) {
663
663
  }
664
664
  return null;
665
665
  }
666
+ var TYPE_GUARD_PATTERN = /^(is|has)[A-Z]/;
667
+ function typeGuardSubject(test) {
668
+ const arg = test.type === "CallExpression" ? test.arguments[0] : void 0;
669
+ if (test.type === "CallExpression" && test.callee.type === "Identifier" && TYPE_GUARD_PATTERN.test(test.callee.name) && test.arguments.length === 1 && arg !== void 0 && arg.type !== "SpreadElement") {
670
+ return arg;
671
+ }
672
+ return null;
673
+ }
674
+ function positiveErrorSubject(test) {
675
+ return instanceofErrorSubject(test) ?? typeGuardSubject(test);
676
+ }
666
677
  function negatedInstanceofErrorSubject(test) {
667
678
  if (test.type === "UnaryExpression" && test.operator === "!") {
668
- return instanceofErrorSubject(test.argument);
679
+ return positiveErrorSubject(test.argument);
669
680
  }
670
681
  return null;
671
682
  }
683
+ function branchTerminates(branch) {
684
+ const body = branch.type === "BlockStatement" ? branch.body : [branch];
685
+ const last = body[body.length - 1];
686
+ return last !== void 0 && (last.type === "ReturnStatement" || last.type === "ThrowStatement");
687
+ }
688
+ function isNarrowedByEarlyReturn(node, argExpr, sourceCode) {
689
+ const argText = sourceCode.getText(argExpr);
690
+ let current = node.parent;
691
+ while (current) {
692
+ if (current.type === "BlockStatement" || current.type === "Program") {
693
+ for (const stmt of current.body) {
694
+ if (stmt.range[0] >= node.range[0]) {
695
+ break;
696
+ }
697
+ if (stmt.type === "IfStatement" && stmt.alternate === null && branchTerminates(stmt.consequent)) {
698
+ const subject = positiveErrorSubject(stmt.test);
699
+ if (subject && sourceCode.getText(subject) === argText) {
700
+ return true;
701
+ }
702
+ }
703
+ }
704
+ }
705
+ current = current.parent;
706
+ }
707
+ return false;
708
+ }
672
709
  function nodeWithin(node, container) {
673
710
  return container !== null && node.range[0] >= container.range[0] && node.range[1] <= container.range[1];
674
711
  }
@@ -678,7 +715,7 @@ function isGuardedByInstanceofError(node, argExpr, sourceCode) {
678
715
  let current = node.parent;
679
716
  while (current) {
680
717
  if (current.type === "ConditionalExpression") {
681
- const subject = instanceofErrorSubject(current.test);
718
+ const subject = positiveErrorSubject(current.test);
682
719
  if (subject && sameSubject(subject) && nodeWithin(node, current.alternate)) {
683
720
  return true;
684
721
  }
@@ -687,7 +724,7 @@ function isGuardedByInstanceofError(node, argExpr, sourceCode) {
687
724
  return true;
688
725
  }
689
726
  } else if (current.type === "IfStatement") {
690
- const subject = instanceofErrorSubject(current.test);
727
+ const subject = positiveErrorSubject(current.test);
691
728
  if (subject && sameSubject(subject) && nodeWithin(node, current.alternate)) {
692
729
  return true;
693
730
  }
@@ -740,7 +777,7 @@ var no_json_stringify_error_default = import_utils6.ESLintUtils.RuleCreator(
740
777
  if (!suggestsError) {
741
778
  return;
742
779
  }
743
- if (isGuardedByInstanceofError(node, firstArg, context.sourceCode)) {
780
+ if (isGuardedByInstanceofError(node, firstArg, context.sourceCode) || isNarrowedByEarlyReturn(node, firstArg, context.sourceCode)) {
744
781
  return;
745
782
  }
746
783
  context.report({
@@ -883,6 +920,17 @@ function isProcessEnv(node) {
883
920
  function isImportMetaEnv(node) {
884
921
  return !node.computed && node.property.type === "Identifier" && node.property.name === "env" && node.object.type === "MetaProperty" && node.object.meta.name === "import" && node.object.property.name === "meta";
885
922
  }
923
+ var BUILD_TIME_CONSTANTS = /* @__PURE__ */ new Set([
924
+ "NODE_ENV",
925
+ "MODE",
926
+ "DEV",
927
+ "PROD",
928
+ "SSR"
929
+ ]);
930
+ function isBuildTimeConstantAccess(node) {
931
+ const parent = node.parent;
932
+ return parent.type === "MemberExpression" && parent.object === node && !parent.computed && parent.property.type === "Identifier" && BUILD_TIME_CONSTANTS.has(parent.property.name);
933
+ }
886
934
  var no_raw_env_default = import_utils9.ESLintUtils.RuleCreator(
887
935
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
888
936
  )({
@@ -901,7 +949,7 @@ var no_raw_env_default = import_utils9.ESLintUtils.RuleCreator(
901
949
  create(context) {
902
950
  return {
903
951
  MemberExpression(node) {
904
- if (isProcessEnv(node) || isImportMetaEnv(node)) {
952
+ if ((isProcessEnv(node) || isImportMetaEnv(node)) && !isBuildTimeConstantAccess(node)) {
905
953
  context.report({
906
954
  node,
907
955
  messageId: "noRawEnv"
@@ -1137,7 +1185,7 @@ var no_sentinel_return_on_catch_default = import_utils10.ESLintUtils.RuleCreator
1137
1185
  // src/rules/no-sequential-await.ts
1138
1186
  var import_utils11 = require("@typescript-eslint/utils");
1139
1187
  var ARRAY_ITERATION_METHODS = /* @__PURE__ */ new Set(["forEach", "map", "filter"]);
1140
- var SEQUENTIAL_ITERABLE_HINT = /sort|reverse|ordered|sequence|hook|middleware|pipeline|\bstage|\bstep|\bphase|migration|chain/i;
1188
+ var SEQUENTIAL_ITERABLE_HINT = /sort|reverse|ordered|sequence|hook|middleware|pipeline|\bstage|\bstep|\bphase|migration|chain|buffer|stream|teleport|chunk|\bqueue|drain/i;
1141
1189
  function isFunctionLike(node) {
1142
1190
  return node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression";
1143
1191
  }
@@ -1180,9 +1228,29 @@ function hasEarlyExit(root) {
1180
1228
  });
1181
1229
  return found;
1182
1230
  }
1231
+ var TIMER_HELPER_RE = /^(sleep|timeout|delay|wait|pause|tick)$/i;
1232
+ function calleeName2(callee) {
1233
+ if (callee.type === "Identifier") return callee.name;
1234
+ if (callee.type === "MemberExpression" && !callee.computed && callee.property.type === "Identifier") {
1235
+ return callee.property.name;
1236
+ }
1237
+ return null;
1238
+ }
1183
1239
  function isTimerYield(node) {
1184
1240
  const arg = node.argument;
1185
- return arg.type === "NewExpression" && arg.callee.type === "Identifier" && arg.callee.name === "Promise";
1241
+ if (arg.type === "NewExpression" && arg.callee.type === "Identifier" && arg.callee.name === "Promise") {
1242
+ return true;
1243
+ }
1244
+ if (arg.type === "CallExpression") {
1245
+ const name = calleeName2(arg.callee);
1246
+ return name !== null && TIMER_HELPER_RE.test(name);
1247
+ }
1248
+ return false;
1249
+ }
1250
+ var QUEUE_DRAIN_METHODS = /^(shift|pop|dequeue|next|poll)$/;
1251
+ function isQueueDrain(node) {
1252
+ const arg = node.argument;
1253
+ return arg.type === "CallExpression" && arg.callee.type === "MemberExpression" && !arg.callee.computed && arg.callee.property.type === "Identifier" && QUEUE_DRAIN_METHODS.test(arg.callee.property.name);
1186
1254
  }
1187
1255
  function referencesName(root, name) {
1188
1256
  let found = false;
@@ -1217,7 +1285,7 @@ function shouldReport(awaits, earlyExit, iterableText) {
1217
1285
  return false;
1218
1286
  }
1219
1287
  return awaits.some(
1220
- (node) => !isTimerYield(node) && !isThreadedAccumulator(node)
1288
+ (node) => !isTimerYield(node) && !isThreadedAccumulator(node) && !isQueueDrain(node)
1221
1289
  );
1222
1290
  }
1223
1291
  var no_sequential_await_default = import_utils11.ESLintUtils.RuleCreator(
@@ -1238,10 +1306,10 @@ var no_sequential_await_default = import_utils11.ESLintUtils.RuleCreator(
1238
1306
  create(context) {
1239
1307
  function loopParts(node) {
1240
1308
  if (node.type === "ForStatement") {
1241
- return [node.body, node.init, node.test, node.update];
1309
+ return [node.body, node.test, node.update];
1242
1310
  }
1243
1311
  if (node.type === "ForOfStatement" || node.type === "ForInStatement") {
1244
- return [node.body, node.right];
1312
+ return [node.body];
1245
1313
  }
1246
1314
  return [node.body, node.test];
1247
1315
  }
@@ -1897,10 +1965,10 @@ var SVG_EXEMPT_COLOR_VALUES = /* @__PURE__ */ new Set([
1897
1965
  "currentcolor",
1898
1966
  "inherit"
1899
1967
  ]);
1900
- var isInsideSvgDefsContainer = (node) => {
1968
+ var isInsideSvg = (node) => {
1901
1969
  let current = node.parent;
1902
1970
  while (current !== void 0 && current !== null) {
1903
- if (current.type === import_utils17.AST_NODE_TYPES.JSXElement && current.openingElement.name.type === import_utils17.AST_NODE_TYPES.JSXIdentifier && SVG_DEFS_CONTAINERS.has(current.openingElement.name.name)) {
1971
+ if (current.type === import_utils17.AST_NODE_TYPES.JSXElement && current.openingElement.name.type === import_utils17.AST_NODE_TYPES.JSXIdentifier && (current.openingElement.name.name === "svg" || SVG_DEFS_CONTAINERS.has(current.openingElement.name.name))) {
1904
1972
  return true;
1905
1973
  }
1906
1974
  current = current.parent;
@@ -2010,7 +2078,7 @@ var prefer_semantic_colors_default = import_utils17.ESLintUtils.RuleCreator(
2010
2078
  if (typeof node.value.value === "string" && SVG_EXEMPT_COLOR_VALUES.has(node.value.value.toLowerCase())) {
2011
2079
  return;
2012
2080
  }
2013
- if (isInsideSvgDefsContainer(node)) return;
2081
+ if (isInsideSvg(node)) return;
2014
2082
  checkColorValueNode(node.value);
2015
2083
  },
2016
2084
  // Inline style objects: style={{ color: "#111827", backgroundColor: "#fff" }}
@@ -2538,7 +2606,7 @@ function propertyKeyName(prop) {
2538
2606
  }
2539
2607
  return void 0;
2540
2608
  }
2541
- function calleeName2(node) {
2609
+ function calleeName3(node) {
2542
2610
  const callee = node.callee;
2543
2611
  if (callee.type === "Identifier") {
2544
2612
  return callee.name;
@@ -2549,7 +2617,7 @@ function calleeName2(node) {
2549
2617
  return void 0;
2550
2618
  }
2551
2619
  function isCorsWildcardCredentialsCall(node) {
2552
- const name = calleeName2(node);
2620
+ const name = calleeName3(node);
2553
2621
  if (name === void 0 || name.toLowerCase() !== "cors") {
2554
2622
  return false;
2555
2623
  }
@@ -3178,8 +3246,54 @@ var no_secret_in_log_default = import_utils25.ESLintUtils.RuleCreator(
3178
3246
  }
3179
3247
  });
3180
3248
 
3181
- // src/rules/prefer-string-literal-union.ts
3249
+ // src/rules/no-unsafe-cast.ts
3182
3250
  var import_utils26 = require("@typescript-eslint/utils");
3251
+ var import_utils27 = require("@typescript-eslint/utils");
3252
+ function isAnyAnnotation(node) {
3253
+ return node.type === import_utils27.AST_NODE_TYPES.TSAnyKeyword;
3254
+ }
3255
+ function isConstAssertion(typeAnnotation) {
3256
+ return typeAnnotation.type === import_utils27.AST_NODE_TYPES.TSTypeReference && typeAnnotation.typeName.type === import_utils27.AST_NODE_TYPES.Identifier && typeAnnotation.typeName.name === "const";
3257
+ }
3258
+ var no_unsafe_cast_default = import_utils26.ESLintUtils.RuleCreator(
3259
+ (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
3260
+ )({
3261
+ name: "no-unsafe-cast",
3262
+ meta: {
3263
+ type: "problem",
3264
+ docs: {
3265
+ description: "Disallow `as any`/`<any>` casts and `as unknown as T` double-casts, which fully disable type checking."
3266
+ },
3267
+ schema: [],
3268
+ messages: {
3269
+ asAny: "`as any` disables type checking on this value. Narrow with a type guard, model the shape, or cast to a specific type instead.",
3270
+ doubleCast: "`as unknown as T` double-cast bypasses the compiler's structural check. Prefer a runtime validator (e.g. a zod schema) or an accurate type at the boundary."
3271
+ }
3272
+ },
3273
+ defaultOptions: [],
3274
+ create(context) {
3275
+ function checkAssertion(node) {
3276
+ if (isConstAssertion(node.typeAnnotation)) {
3277
+ return;
3278
+ }
3279
+ if (isAnyAnnotation(node.typeAnnotation)) {
3280
+ context.report({ node, messageId: "asAny" });
3281
+ return;
3282
+ }
3283
+ const inner = node.expression;
3284
+ if (inner.type === import_utils27.AST_NODE_TYPES.TSAsExpression || inner.type === import_utils27.AST_NODE_TYPES.TSTypeAssertion) {
3285
+ context.report({ node, messageId: "doubleCast" });
3286
+ }
3287
+ }
3288
+ return {
3289
+ TSAsExpression: checkAssertion,
3290
+ TSTypeAssertion: checkAssertion
3291
+ };
3292
+ }
3293
+ });
3294
+
3295
+ // src/rules/prefer-string-literal-union.ts
3296
+ var import_utils28 = require("@typescript-eslint/utils");
3183
3297
  var ts = __toESM(require("typescript"), 1);
3184
3298
  var CHOICE_TOKENS = /* @__PURE__ */ new Set([
3185
3299
  "status",
@@ -3222,19 +3336,19 @@ function isChoiceLikeName(name) {
3222
3336
  return CHOICE_TOKENS.has(lastWord(name));
3223
3337
  }
3224
3338
  function keyName(key) {
3225
- if (key.type === import_utils26.AST_NODE_TYPES.Identifier) {
3339
+ if (key.type === import_utils28.AST_NODE_TYPES.Identifier) {
3226
3340
  return key.name;
3227
3341
  }
3228
- if (key.type === import_utils26.AST_NODE_TYPES.Literal && typeof key.value === "string") {
3342
+ if (key.type === import_utils28.AST_NODE_TYPES.Literal && typeof key.value === "string") {
3229
3343
  return key.value;
3230
3344
  }
3231
3345
  return null;
3232
3346
  }
3233
3347
  function isStringLiteralMember(t) {
3234
- return t.type === import_utils26.AST_NODE_TYPES.TSLiteralType && t.literal.type === import_utils26.AST_NODE_TYPES.Literal && typeof t.literal.value === "string";
3348
+ return t.type === import_utils28.AST_NODE_TYPES.TSLiteralType && t.literal.type === import_utils28.AST_NODE_TYPES.Literal && typeof t.literal.value === "string";
3235
3349
  }
3236
3350
  function isStringLiteralUnion(node) {
3237
- if (node?.type !== import_utils26.AST_NODE_TYPES.TSUnionType) {
3351
+ if (node?.type !== import_utils28.AST_NODE_TYPES.TSUnionType) {
3238
3352
  return false;
3239
3353
  }
3240
3354
  return node.types.filter(isStringLiteralMember).length >= MIN_CLUSTER_SIZE;
@@ -3263,12 +3377,12 @@ function bindingSourceExpression(decl) {
3263
3377
  return ts.isForOfStatement(node) ? node.expression : node.initializer;
3264
3378
  }
3265
3379
  function refKey(node) {
3266
- if (node.type === import_utils26.AST_NODE_TYPES.Identifier) {
3380
+ if (node.type === import_utils28.AST_NODE_TYPES.Identifier) {
3267
3381
  return node.name;
3268
3382
  }
3269
- if (node.type === import_utils26.AST_NODE_TYPES.MemberExpression && !node.computed) {
3383
+ if (node.type === import_utils28.AST_NODE_TYPES.MemberExpression && !node.computed) {
3270
3384
  const inner = refKey(node.object);
3271
- if (inner === null || node.property.type !== import_utils26.AST_NODE_TYPES.Identifier) {
3385
+ if (inner === null || node.property.type !== import_utils28.AST_NODE_TYPES.Identifier) {
3272
3386
  return null;
3273
3387
  }
3274
3388
  return `${inner}.${node.property.name}`;
@@ -3276,12 +3390,12 @@ function refKey(node) {
3276
3390
  return null;
3277
3391
  }
3278
3392
  function strLiteral(node) {
3279
- if (node.type === import_utils26.AST_NODE_TYPES.Literal && typeof node.value === "string") {
3393
+ if (node.type === import_utils28.AST_NODE_TYPES.Literal && typeof node.value === "string") {
3280
3394
  return node.value;
3281
3395
  }
3282
3396
  return null;
3283
3397
  }
3284
- var prefer_string_literal_union_default = import_utils26.ESLintUtils.RuleCreator(
3398
+ var prefer_string_literal_union_default = import_utils28.ESLintUtils.RuleCreator(
3285
3399
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
3286
3400
  )({
3287
3401
  name: "prefer-string-literal-union",
@@ -3305,7 +3419,7 @@ var prefer_string_literal_union_default = import_utils26.ESLintUtils.RuleCreator
3305
3419
  }
3306
3420
  let services;
3307
3421
  try {
3308
- services = import_utils26.ESLintUtils.getParserServices(context);
3422
+ services = import_utils28.ESLintUtils.getParserServices(context);
3309
3423
  } catch {
3310
3424
  services = null;
3311
3425
  }
@@ -3389,7 +3503,7 @@ var prefer_string_literal_union_default = import_utils26.ESLintUtils.RuleCreator
3389
3503
  containersWithUnion.add(container);
3390
3504
  return;
3391
3505
  }
3392
- if (typeNode?.type !== import_utils26.AST_NODE_TYPES.TSStringKeyword) {
3506
+ if (typeNode?.type !== import_utils28.AST_NODE_TYPES.TSStringKeyword) {
3393
3507
  return;
3394
3508
  }
3395
3509
  const name = keyName(key);
@@ -3477,10 +3591,10 @@ var prefer_string_literal_union_default = import_utils26.ESLintUtils.RuleCreator
3477
3591
  }
3478
3592
  };
3479
3593
  function refKeyText(node) {
3480
- if (node.type === import_utils26.AST_NODE_TYPES.BinaryExpression) {
3594
+ if (node.type === import_utils28.AST_NODE_TYPES.BinaryExpression) {
3481
3595
  return refKey(node.left) ?? refKey(node.right) ?? "value";
3482
3596
  }
3483
- if (node.type === import_utils26.AST_NODE_TYPES.SwitchStatement) {
3597
+ if (node.type === import_utils28.AST_NODE_TYPES.SwitchStatement) {
3484
3598
  return refKey(node.discriminant) ?? "value";
3485
3599
  }
3486
3600
  return "value";
@@ -3489,7 +3603,7 @@ var prefer_string_literal_union_default = import_utils26.ESLintUtils.RuleCreator
3489
3603
  });
3490
3604
 
3491
3605
  // src/rules/single-public-export.ts
3492
- var import_utils27 = require("@typescript-eslint/utils");
3606
+ var import_utils29 = require("@typescript-eslint/utils");
3493
3607
  var JUNK_DRAWER_STEMS = /* @__PURE__ */ new Set([
3494
3608
  "util",
3495
3609
  "utils",
@@ -3523,12 +3637,12 @@ var kebabCase2 = (name) => {
3523
3637
  }
3524
3638
  return normalized.replace(CAMEL_BOUNDARY_RE, "-").toLowerCase();
3525
3639
  };
3526
- var isFunctionExpression = (node) => node !== null && (node.type === import_utils27.AST_NODE_TYPES.ArrowFunctionExpression || node.type === import_utils27.AST_NODE_TYPES.FunctionExpression);
3640
+ var isFunctionExpression = (node) => node !== null && (node.type === import_utils29.AST_NODE_TYPES.ArrowFunctionExpression || node.type === import_utils29.AST_NODE_TYPES.FunctionExpression);
3527
3641
  var functionConstName = (decl) => {
3528
3642
  if (decl.declarations.length !== 1) return null;
3529
3643
  const [declarator] = decl.declarations;
3530
3644
  if (declarator === void 0) return null;
3531
- if (declarator.id.type !== import_utils27.AST_NODE_TYPES.Identifier) return null;
3645
+ if (declarator.id.type !== import_utils29.AST_NODE_TYPES.Identifier) return null;
3532
3646
  if (!isFunctionExpression(declarator.init)) return null;
3533
3647
  return declarator.id.name;
3534
3648
  };
@@ -3542,20 +3656,20 @@ var summarizeExports = (body) => {
3542
3656
  };
3543
3657
  for (const statement of body) {
3544
3658
  switch (statement.type) {
3545
- case import_utils27.AST_NODE_TYPES.ExportAllDeclaration:
3659
+ case import_utils29.AST_NODE_TYPES.ExportAllDeclaration:
3546
3660
  hasReExport = true;
3547
3661
  break;
3548
- case import_utils27.AST_NODE_TYPES.ExportDefaultDeclaration: {
3662
+ case import_utils29.AST_NODE_TYPES.ExportDefaultDeclaration: {
3549
3663
  names += 1;
3550
3664
  const decl = statement.declaration;
3551
- if (decl.type === import_utils27.AST_NODE_TYPES.FunctionDeclaration && decl.id !== null) {
3665
+ if (decl.type === import_utils29.AST_NODE_TYPES.FunctionDeclaration && decl.id !== null) {
3552
3666
  candidate = { name: decl.id.name, node: statement };
3553
- } else if (decl.type === import_utils27.AST_NODE_TYPES.ClassDeclaration && decl.id !== null) {
3667
+ } else if (decl.type === import_utils29.AST_NODE_TYPES.ClassDeclaration && decl.id !== null) {
3554
3668
  candidate = { name: decl.id.name, node: statement };
3555
3669
  }
3556
3670
  break;
3557
3671
  }
3558
- case import_utils27.AST_NODE_TYPES.ExportNamedDeclaration: {
3672
+ case import_utils29.AST_NODE_TYPES.ExportNamedDeclaration: {
3559
3673
  if (statement.source !== null) {
3560
3674
  hasReExport = true;
3561
3675
  break;
@@ -3566,15 +3680,15 @@ var summarizeExports = (body) => {
3566
3680
  break;
3567
3681
  }
3568
3682
  switch (decl.type) {
3569
- case import_utils27.AST_NODE_TYPES.FunctionDeclaration:
3683
+ case import_utils29.AST_NODE_TYPES.FunctionDeclaration:
3570
3684
  if (decl.id !== null) addCandidate(decl.id.name, statement);
3571
3685
  else names += 1;
3572
3686
  break;
3573
- case import_utils27.AST_NODE_TYPES.ClassDeclaration:
3687
+ case import_utils29.AST_NODE_TYPES.ClassDeclaration:
3574
3688
  if (decl.id !== null) addCandidate(decl.id.name, statement);
3575
3689
  else names += 1;
3576
3690
  break;
3577
- case import_utils27.AST_NODE_TYPES.VariableDeclaration: {
3691
+ case import_utils29.AST_NODE_TYPES.VariableDeclaration: {
3578
3692
  const fnName = functionConstName(decl);
3579
3693
  if (fnName !== null && decl.declarations.length === 1) {
3580
3694
  addCandidate(fnName, statement);
@@ -3594,7 +3708,7 @@ var summarizeExports = (body) => {
3594
3708
  }
3595
3709
  return { names, hasReExport, candidate };
3596
3710
  };
3597
- var single_public_export_default = import_utils27.ESLintUtils.RuleCreator(
3711
+ var single_public_export_default = import_utils29.ESLintUtils.RuleCreator(
3598
3712
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
3599
3713
  )({
3600
3714
  name: "single-public-export",
@@ -3658,13 +3772,14 @@ var rules = {
3658
3772
  "no-cors-wildcard-with-credentials": no_cors_wildcard_with_credentials_default,
3659
3773
  "no-fat-try-blocks": no_fat_try_blocks_default,
3660
3774
  "no-secret-in-log": no_secret_in_log_default,
3775
+ "no-unsafe-cast": no_unsafe_cast_default,
3661
3776
  "prefer-string-literal-union": prefer_string_literal_union_default,
3662
3777
  "single-public-export": single_public_export_default
3663
3778
  };
3664
3779
  var plugin = {
3665
3780
  meta: {
3666
3781
  name: "@sarj/eslint-plugin",
3667
- version: "2.4.0"
3782
+ version: "2.5.0"
3668
3783
  },
3669
3784
  rules,
3670
3785
  configs: {
@@ -3694,6 +3809,7 @@ var plugin = {
3694
3809
  "@sarj/no-fat-try-blocks": "warn",
3695
3810
  "@sarj/no-cors-wildcard-with-credentials": "warn",
3696
3811
  "@sarj/no-secret-in-log": "warn",
3812
+ "@sarj/no-unsafe-cast": "warn",
3697
3813
  "@sarj/single-public-export": "warn",
3698
3814
  "@sarj/prefer-string-literal-union": "warn"
3699
3815
  }
@@ -3728,6 +3844,7 @@ var plugin = {
3728
3844
  "@sarj/no-fat-try-blocks": "error",
3729
3845
  "@sarj/no-cors-wildcard-with-credentials": "error",
3730
3846
  "@sarj/no-secret-in-log": "error",
3847
+ "@sarj/no-unsafe-cast": "warn",
3731
3848
  "@sarj/single-public-export": "error",
3732
3849
  // High-volume/stylistic — warn until rollout proves FP rate.
3733
3850
  "@sarj/prefer-string-literal-union": "warn"