@blumintinc/eslint-plugin-blumint 1.20.43 → 1.20.44

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.43',
226
+ version: '1.20.44',
227
227
  },
228
228
  parseOptions: {
229
229
  ecmaVersion: 2020,
@@ -10,6 +10,7 @@ exports.enforceFirestoreDocRefGeneric = void 0;
10
10
  */
11
11
  const utils_1 = require("@typescript-eslint/utils");
12
12
  const createRule_1 = require("../utils/createRule");
13
+ const ASTHelpers_1 = require("../utils/ASTHelpers");
13
14
  /**
14
15
  * @type {import('eslint').Rule.RuleModule}
15
16
  */
@@ -305,8 +306,64 @@ exports.enforceFirestoreDocRefGeneric = (0, createRule_1.createRule)({
305
306
  if (findVariableDeclaration(node)) {
306
307
  return true;
307
308
  }
309
+ // Resolve the binding through the scope chain so that a typed collection
310
+ // stored in a variable still supplies the document generic to .doc().
311
+ if (isTypedCollectionBinding(node)) {
312
+ return true;
313
+ }
308
314
  return false;
309
315
  }
316
+ /**
317
+ * Resolves an identifier to its declaration and reports whether that
318
+ * declaration provably yields a typed CollectionReference.
319
+ *
320
+ * Deliberately conservative: only immutable (`const`) bindings with a
321
+ * single definition are followed, and only for one hop. An alias such as
322
+ * `const b = a;` is not resolved because chasing arbitrary dataflow
323
+ * syntactically produces unsound exemptions; `let`/`var` are refused
324
+ * because a later assignment can replace the value with an untyped
325
+ * collection. Anything unresolvable (parameters, imports, destructuring)
326
+ * keeps reporting, since the rule cannot prove the reference is typed.
327
+ */
328
+ function isTypedCollectionBinding(node) {
329
+ const scope = ASTHelpers_1.ASTHelpers.getScope(context, node);
330
+ const variable = ASTHelpers_1.ASTHelpers.findVariableInScope(scope, node.name);
331
+ if (!variable || variable.defs.length !== 1) {
332
+ return false;
333
+ }
334
+ const def = variable.defs[0];
335
+ if (def.type !== 'Variable' ||
336
+ def.node.type !== utils_1.AST_NODE_TYPES.VariableDeclarator ||
337
+ def.parent?.type !== utils_1.AST_NODE_TYPES.VariableDeclaration ||
338
+ def.parent.kind !== 'const') {
339
+ return false;
340
+ }
341
+ const declarator = def.node;
342
+ if (declarator.id.type === utils_1.AST_NODE_TYPES.Identifier &&
343
+ declarator.id.typeAnnotation) {
344
+ return hasCollectionReferenceType(declarator.id.typeAnnotation.typeAnnotation);
345
+ }
346
+ return isTypedCollectionInitializer(declarator.init);
347
+ }
348
+ function isTypedCollectionInitializer(init) {
349
+ if (!init) {
350
+ return false;
351
+ }
352
+ // An explicit assertion states the schema just as an annotation does.
353
+ if (init.type === utils_1.AST_NODE_TYPES.TSAsExpression) {
354
+ return hasCollectionReferenceType(init.typeAnnotation);
355
+ }
356
+ // Mirrors the chained `db.collection<T>('x').doc('y')` detection: the
357
+ // presence of the type argument is what matters here. An `any`/`{}`
358
+ // argument is already reported on the collection call itself, so it is
359
+ // not reported a second time on the derived document reference.
360
+ return (init.type === utils_1.AST_NODE_TYPES.CallExpression &&
361
+ init.callee.type === utils_1.AST_NODE_TYPES.MemberExpression &&
362
+ init.callee.property.type === utils_1.AST_NODE_TYPES.Identifier &&
363
+ init.callee.property.name === 'collection' &&
364
+ !!init.typeParameters &&
365
+ init.typeParameters.params.length > 0);
366
+ }
310
367
  function checkCallExpressionForCollectionReference(node) {
311
368
  // Check if this is a method call that returns CollectionReference
312
369
  if (node.callee.type === utils_1.AST_NODE_TYPES.MemberExpression) {
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.enforceTransformMemoization = void 0;
4
4
  const utils_1 = require("@typescript-eslint/utils");
5
5
  const createRule_1 = require("../utils/createRule");
6
+ const ASTHelpers_1 = require("../utils/ASTHelpers");
6
7
  exports.enforceTransformMemoization = (0, createRule_1.createRule)({
7
8
  name: 'enforce-transform-memoization',
8
9
  meta: {
@@ -395,6 +396,14 @@ exports.enforceTransformMemoization = (0, createRule_1.createRule)({
395
396
  !adaptValueNames.has(node.callee.name)) {
396
397
  return;
397
398
  }
399
+ // Every message this rule emits prescribes useMemo/useCallback, and a
400
+ // hook call is legal only inside a component or another hook. An
401
+ // adaptValue call at module scope, in a plain helper, or in a test body
402
+ // is not on a render path: nothing is "recreated on every render"
403
+ // there, and the prescribed fix would throw "Invalid hook call".
404
+ if (!ASTHelpers_1.ASTHelpers.isInsideComponentOrHook(node, context)) {
405
+ return;
406
+ }
398
407
  const optionsArg = node.arguments[0];
399
408
  if (!optionsArg)
400
409
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blumintinc/eslint-plugin-blumint",
3
- "version": "1.20.43",
3
+ "version": "1.20.44",
4
4
  "description": "Custom eslint rules for use within BluMint",
5
5
  "author": {
6
6
  "name": "Brodie McGuire",
@@ -1,4 +1,26 @@
1
1
  [
2
+ {
3
+ "version": "1.20.44",
4
+ "date": "2026-07-31T05:47:19.150Z",
5
+ "rules": [
6
+ {
7
+ "name": "enforce-firestore-doc-ref-generic",
8
+ "changeType": "fix",
9
+ "issues": [
10
+ 1498
11
+ ],
12
+ "summary": "honor a typed collection bound to a const (closes #1498)"
13
+ },
14
+ {
15
+ "name": "enforce-transform-memoization",
16
+ "changeType": "fix",
17
+ "issues": [
18
+ 1497
19
+ ],
20
+ "summary": "only report inside a component or hook (closes #1497)"
21
+ }
22
+ ]
23
+ },
2
24
  {
3
25
  "version": "1.20.43",
4
26
  "date": "2026-07-31T04:38:54.532Z",