@blumintinc/eslint-plugin-blumint 1.20.65 → 1.20.66

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
@@ -223,7 +223,7 @@ function noFrontendImportsFromFunctionsPatterns(pattern) {
223
223
  module.exports = {
224
224
  meta: {
225
225
  name: '@blumintinc/eslint-plugin-blumint',
226
- version: '1.20.65',
226
+ version: '1.20.66',
227
227
  },
228
228
  parseOptions: {
229
229
  ecmaVersion: 2020,
@@ -655,10 +655,50 @@ exports.enforceFirestoreDocRefGeneric = (0, createRule_1.createRule)({
655
655
  return tracesToRulesUnitTesting(node.expression, visited);
656
656
  case utils_1.AST_NODE_TYPES.Identifier:
657
657
  return identifierTracesToRulesUnitTesting(node, visited);
658
+ case utils_1.AST_NODE_TYPES.ArrowFunctionExpression:
659
+ case utils_1.AST_NODE_TYPES.FunctionExpression:
660
+ case utils_1.AST_NODE_TYPES.FunctionDeclaration:
661
+ return functionReturnTracesToRulesUnitTesting(node, visited);
658
662
  default:
659
663
  return false;
660
664
  }
661
665
  }
666
+ /**
667
+ * Reached when a receiver is the result of calling a local helper, so what
668
+ * the helper hands back decides the surface. Only top-level returns are
669
+ * read; a return nested inside another function belongs to that one.
670
+ */
671
+ function functionReturnTracesToRulesUnitTesting(node, visited) {
672
+ if (node.body.type !== utils_1.AST_NODE_TYPES.BlockStatement) {
673
+ return tracesToRulesUnitTesting(node.body, visited);
674
+ }
675
+ return node.body.body.some((statement) => statement.type === utils_1.AST_NODE_TYPES.ReturnStatement &&
676
+ tracesToRulesUnitTesting(statement.argument, visited));
677
+ }
678
+ /**
679
+ * `withSecurityRulesDisabled` is the one API here that delivers a context
680
+ * through a callback rather than a return value, and the documented spelling
681
+ * leaves the parameter unannotated, so the call it belongs to is the only
682
+ * evidence of the surface.
683
+ */
684
+ const CONTEXT_CALLBACK_METHOD = 'withSecurityRulesDisabled';
685
+ function parameterTracesToRulesUnitTesting(name, owner, visited) {
686
+ if (name.type === utils_1.AST_NODE_TYPES.Identifier &&
687
+ name.typeAnnotation &&
688
+ isRulesUnitTestingType(name.typeAnnotation.typeAnnotation)) {
689
+ return true;
690
+ }
691
+ const call = owner.parent;
692
+ if (!call ||
693
+ call.type !== utils_1.AST_NODE_TYPES.CallExpression ||
694
+ !call.arguments.includes(owner) ||
695
+ call.callee.type !== utils_1.AST_NODE_TYPES.MemberExpression ||
696
+ call.callee.property.type !== utils_1.AST_NODE_TYPES.Identifier ||
697
+ call.callee.property.name !== CONTEXT_CALLBACK_METHOD) {
698
+ return false;
699
+ }
700
+ return tracesToRulesUnitTesting(call.callee.object, visited);
701
+ }
662
702
  function identifierTracesToRulesUnitTesting(node, visited) {
663
703
  const scope = ASTHelpers_1.ASTHelpers.getScope(context, node);
664
704
  const variable = ASTHelpers_1.ASTHelpers.findVariableInScope(scope, node.name);
@@ -670,24 +710,36 @@ exports.enforceFirestoreDocRefGeneric = (0, createRule_1.createRule)({
670
710
  return (def.parent?.type === utils_1.AST_NODE_TYPES.ImportDeclaration &&
671
711
  def.parent.source.value === RULES_UNIT_TESTING_MODULE);
672
712
  }
673
- // Covers the `withSecurityRulesDisabled(async (ctx: RulesTestContext) =>
674
- // ...)` callback, where the compat handle never appears as an initializer.
675
713
  if (def.type === 'Parameter') {
676
- const annotation = def.name.typeAnnotation;
677
- return (!!annotation && isRulesUnitTestingType(annotation.typeAnnotation));
714
+ return parameterTracesToRulesUnitTesting(def.name, def.node, visited);
715
+ }
716
+ // A hoisted declaration binds the helper the same way a `const` arrow
717
+ // does; an ambient `declare function` has no body and falls through.
718
+ if (def.type === 'FunctionName') {
719
+ return tracesToRulesUnitTesting(def.node, visited);
678
720
  }
679
721
  if (def.type !== 'Variable' ||
680
- def.node.type !== utils_1.AST_NODE_TYPES.VariableDeclarator ||
681
- def.parent?.type !== utils_1.AST_NODE_TYPES.VariableDeclaration ||
682
- def.parent.kind !== 'const') {
722
+ def.node.type !== utils_1.AST_NODE_TYPES.VariableDeclarator) {
683
723
  return false;
684
724
  }
685
725
  const declarator = def.node;
726
+ // An annotation constrains every assignment rather than just the
727
+ // initializer, so unlike an initializer it survives a `let`. The
728
+ // environment handle is created in `beforeAll` and so cannot be `const`;
729
+ // `let testEnv: RulesTestEnvironment` is the documented spelling, and
730
+ // TypeScript refuses to put another surface in it.
686
731
  if (declarator.id.type === utils_1.AST_NODE_TYPES.Identifier &&
687
732
  declarator.id.typeAnnotation &&
688
733
  isRulesUnitTestingType(declarator.id.typeAnnotation.typeAnnotation)) {
689
734
  return true;
690
735
  }
736
+ // Without that guarantee only a `const` initializer is followed, mirroring
737
+ // `isTypedCollectionBinding`: an unannotated reassignable binding can hold
738
+ // an Admin SDK handle by the time it reaches `.doc()`.
739
+ if (def.parent?.type !== utils_1.AST_NODE_TYPES.VariableDeclaration ||
740
+ def.parent.kind !== 'const') {
741
+ return false;
742
+ }
691
743
  return tracesToRulesUnitTesting(declarator.init, visited);
692
744
  }
693
745
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blumintinc/eslint-plugin-blumint",
3
- "version": "1.20.65",
3
+ "version": "1.20.66",
4
4
  "description": "Custom eslint rules for use within BluMint",
5
5
  "author": {
6
6
  "name": "Brodie McGuire",
@@ -1,4 +1,18 @@
1
1
  [
2
+ {
3
+ "version": "1.20.66",
4
+ "date": "2026-08-01T13:53:31.680Z",
5
+ "rules": [
6
+ {
7
+ "name": "enforce-firestore-doc-ref-generic",
8
+ "changeType": "fix",
9
+ "issues": [
10
+ 1564
11
+ ],
12
+ "summary": "trace compat receivers through annotated lets and seeding callbacks (closes #1564)"
13
+ }
14
+ ]
15
+ },
2
16
  {
3
17
  "version": "1.20.65",
4
18
  "date": "2026-08-01T13:35:40.762Z",