@sarj/eslint-plugin 2.4.1 → 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
@@ -3246,8 +3246,54 @@ var no_secret_in_log_default = import_utils25.ESLintUtils.RuleCreator(
3246
3246
  }
3247
3247
  });
3248
3248
 
3249
- // src/rules/prefer-string-literal-union.ts
3249
+ // src/rules/no-unsafe-cast.ts
3250
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");
3251
3297
  var ts = __toESM(require("typescript"), 1);
3252
3298
  var CHOICE_TOKENS = /* @__PURE__ */ new Set([
3253
3299
  "status",
@@ -3290,19 +3336,19 @@ function isChoiceLikeName(name) {
3290
3336
  return CHOICE_TOKENS.has(lastWord(name));
3291
3337
  }
3292
3338
  function keyName(key) {
3293
- if (key.type === import_utils26.AST_NODE_TYPES.Identifier) {
3339
+ if (key.type === import_utils28.AST_NODE_TYPES.Identifier) {
3294
3340
  return key.name;
3295
3341
  }
3296
- 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") {
3297
3343
  return key.value;
3298
3344
  }
3299
3345
  return null;
3300
3346
  }
3301
3347
  function isStringLiteralMember(t) {
3302
- 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";
3303
3349
  }
3304
3350
  function isStringLiteralUnion(node) {
3305
- if (node?.type !== import_utils26.AST_NODE_TYPES.TSUnionType) {
3351
+ if (node?.type !== import_utils28.AST_NODE_TYPES.TSUnionType) {
3306
3352
  return false;
3307
3353
  }
3308
3354
  return node.types.filter(isStringLiteralMember).length >= MIN_CLUSTER_SIZE;
@@ -3331,12 +3377,12 @@ function bindingSourceExpression(decl) {
3331
3377
  return ts.isForOfStatement(node) ? node.expression : node.initializer;
3332
3378
  }
3333
3379
  function refKey(node) {
3334
- if (node.type === import_utils26.AST_NODE_TYPES.Identifier) {
3380
+ if (node.type === import_utils28.AST_NODE_TYPES.Identifier) {
3335
3381
  return node.name;
3336
3382
  }
3337
- if (node.type === import_utils26.AST_NODE_TYPES.MemberExpression && !node.computed) {
3383
+ if (node.type === import_utils28.AST_NODE_TYPES.MemberExpression && !node.computed) {
3338
3384
  const inner = refKey(node.object);
3339
- 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) {
3340
3386
  return null;
3341
3387
  }
3342
3388
  return `${inner}.${node.property.name}`;
@@ -3344,12 +3390,12 @@ function refKey(node) {
3344
3390
  return null;
3345
3391
  }
3346
3392
  function strLiteral(node) {
3347
- 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") {
3348
3394
  return node.value;
3349
3395
  }
3350
3396
  return null;
3351
3397
  }
3352
- var prefer_string_literal_union_default = import_utils26.ESLintUtils.RuleCreator(
3398
+ var prefer_string_literal_union_default = import_utils28.ESLintUtils.RuleCreator(
3353
3399
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
3354
3400
  )({
3355
3401
  name: "prefer-string-literal-union",
@@ -3373,7 +3419,7 @@ var prefer_string_literal_union_default = import_utils26.ESLintUtils.RuleCreator
3373
3419
  }
3374
3420
  let services;
3375
3421
  try {
3376
- services = import_utils26.ESLintUtils.getParserServices(context);
3422
+ services = import_utils28.ESLintUtils.getParserServices(context);
3377
3423
  } catch {
3378
3424
  services = null;
3379
3425
  }
@@ -3457,7 +3503,7 @@ var prefer_string_literal_union_default = import_utils26.ESLintUtils.RuleCreator
3457
3503
  containersWithUnion.add(container);
3458
3504
  return;
3459
3505
  }
3460
- if (typeNode?.type !== import_utils26.AST_NODE_TYPES.TSStringKeyword) {
3506
+ if (typeNode?.type !== import_utils28.AST_NODE_TYPES.TSStringKeyword) {
3461
3507
  return;
3462
3508
  }
3463
3509
  const name = keyName(key);
@@ -3545,10 +3591,10 @@ var prefer_string_literal_union_default = import_utils26.ESLintUtils.RuleCreator
3545
3591
  }
3546
3592
  };
3547
3593
  function refKeyText(node) {
3548
- if (node.type === import_utils26.AST_NODE_TYPES.BinaryExpression) {
3594
+ if (node.type === import_utils28.AST_NODE_TYPES.BinaryExpression) {
3549
3595
  return refKey(node.left) ?? refKey(node.right) ?? "value";
3550
3596
  }
3551
- if (node.type === import_utils26.AST_NODE_TYPES.SwitchStatement) {
3597
+ if (node.type === import_utils28.AST_NODE_TYPES.SwitchStatement) {
3552
3598
  return refKey(node.discriminant) ?? "value";
3553
3599
  }
3554
3600
  return "value";
@@ -3557,7 +3603,7 @@ var prefer_string_literal_union_default = import_utils26.ESLintUtils.RuleCreator
3557
3603
  });
3558
3604
 
3559
3605
  // src/rules/single-public-export.ts
3560
- var import_utils27 = require("@typescript-eslint/utils");
3606
+ var import_utils29 = require("@typescript-eslint/utils");
3561
3607
  var JUNK_DRAWER_STEMS = /* @__PURE__ */ new Set([
3562
3608
  "util",
3563
3609
  "utils",
@@ -3591,12 +3637,12 @@ var kebabCase2 = (name) => {
3591
3637
  }
3592
3638
  return normalized.replace(CAMEL_BOUNDARY_RE, "-").toLowerCase();
3593
3639
  };
3594
- 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);
3595
3641
  var functionConstName = (decl) => {
3596
3642
  if (decl.declarations.length !== 1) return null;
3597
3643
  const [declarator] = decl.declarations;
3598
3644
  if (declarator === void 0) return null;
3599
- 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;
3600
3646
  if (!isFunctionExpression(declarator.init)) return null;
3601
3647
  return declarator.id.name;
3602
3648
  };
@@ -3610,20 +3656,20 @@ var summarizeExports = (body) => {
3610
3656
  };
3611
3657
  for (const statement of body) {
3612
3658
  switch (statement.type) {
3613
- case import_utils27.AST_NODE_TYPES.ExportAllDeclaration:
3659
+ case import_utils29.AST_NODE_TYPES.ExportAllDeclaration:
3614
3660
  hasReExport = true;
3615
3661
  break;
3616
- case import_utils27.AST_NODE_TYPES.ExportDefaultDeclaration: {
3662
+ case import_utils29.AST_NODE_TYPES.ExportDefaultDeclaration: {
3617
3663
  names += 1;
3618
3664
  const decl = statement.declaration;
3619
- 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) {
3620
3666
  candidate = { name: decl.id.name, node: statement };
3621
- } 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) {
3622
3668
  candidate = { name: decl.id.name, node: statement };
3623
3669
  }
3624
3670
  break;
3625
3671
  }
3626
- case import_utils27.AST_NODE_TYPES.ExportNamedDeclaration: {
3672
+ case import_utils29.AST_NODE_TYPES.ExportNamedDeclaration: {
3627
3673
  if (statement.source !== null) {
3628
3674
  hasReExport = true;
3629
3675
  break;
@@ -3634,15 +3680,15 @@ var summarizeExports = (body) => {
3634
3680
  break;
3635
3681
  }
3636
3682
  switch (decl.type) {
3637
- case import_utils27.AST_NODE_TYPES.FunctionDeclaration:
3683
+ case import_utils29.AST_NODE_TYPES.FunctionDeclaration:
3638
3684
  if (decl.id !== null) addCandidate(decl.id.name, statement);
3639
3685
  else names += 1;
3640
3686
  break;
3641
- case import_utils27.AST_NODE_TYPES.ClassDeclaration:
3687
+ case import_utils29.AST_NODE_TYPES.ClassDeclaration:
3642
3688
  if (decl.id !== null) addCandidate(decl.id.name, statement);
3643
3689
  else names += 1;
3644
3690
  break;
3645
- case import_utils27.AST_NODE_TYPES.VariableDeclaration: {
3691
+ case import_utils29.AST_NODE_TYPES.VariableDeclaration: {
3646
3692
  const fnName = functionConstName(decl);
3647
3693
  if (fnName !== null && decl.declarations.length === 1) {
3648
3694
  addCandidate(fnName, statement);
@@ -3662,7 +3708,7 @@ var summarizeExports = (body) => {
3662
3708
  }
3663
3709
  return { names, hasReExport, candidate };
3664
3710
  };
3665
- var single_public_export_default = import_utils27.ESLintUtils.RuleCreator(
3711
+ var single_public_export_default = import_utils29.ESLintUtils.RuleCreator(
3666
3712
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
3667
3713
  )({
3668
3714
  name: "single-public-export",
@@ -3726,13 +3772,14 @@ var rules = {
3726
3772
  "no-cors-wildcard-with-credentials": no_cors_wildcard_with_credentials_default,
3727
3773
  "no-fat-try-blocks": no_fat_try_blocks_default,
3728
3774
  "no-secret-in-log": no_secret_in_log_default,
3775
+ "no-unsafe-cast": no_unsafe_cast_default,
3729
3776
  "prefer-string-literal-union": prefer_string_literal_union_default,
3730
3777
  "single-public-export": single_public_export_default
3731
3778
  };
3732
3779
  var plugin = {
3733
3780
  meta: {
3734
3781
  name: "@sarj/eslint-plugin",
3735
- version: "2.4.1"
3782
+ version: "2.5.0"
3736
3783
  },
3737
3784
  rules,
3738
3785
  configs: {
@@ -3762,6 +3809,7 @@ var plugin = {
3762
3809
  "@sarj/no-fat-try-blocks": "warn",
3763
3810
  "@sarj/no-cors-wildcard-with-credentials": "warn",
3764
3811
  "@sarj/no-secret-in-log": "warn",
3812
+ "@sarj/no-unsafe-cast": "warn",
3765
3813
  "@sarj/single-public-export": "warn",
3766
3814
  "@sarj/prefer-string-literal-union": "warn"
3767
3815
  }
@@ -3796,6 +3844,7 @@ var plugin = {
3796
3844
  "@sarj/no-fat-try-blocks": "error",
3797
3845
  "@sarj/no-cors-wildcard-with-credentials": "error",
3798
3846
  "@sarj/no-secret-in-log": "error",
3847
+ "@sarj/no-unsafe-cast": "warn",
3799
3848
  "@sarj/single-public-export": "error",
3800
3849
  // High-volume/stylistic — warn until rollout proves FP rate.
3801
3850
  "@sarj/prefer-string-literal-union": "warn"