eslint-plugin-firebase-ai-logic 1.4.0 → 1.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.js CHANGED
@@ -239,7 +239,7 @@ const configs = {
239
239
  const plugin = {
240
240
  meta: {
241
241
  name: 'eslint-plugin-firebase-ai-logic',
242
- version: '1.4.0',
242
+ version: '1.5.0',
243
243
  },
244
244
  rules,
245
245
  configs,
@@ -20,6 +20,10 @@ import type { Rule } from 'eslint';
20
20
  * 2. Risk exceeding context window limits
21
21
  * 3. Benefit from cost estimation before sending
22
22
  *
23
+ * IGNORED PATTERNS:
24
+ * - Arrays containing functionResponse (these are function call responses)
25
+ * - System instructions (static, known at dev time)
26
+ *
23
27
  * @see https://ai.google.dev/gemini-api/docs/tokens
24
28
  * @see https://ai.google.dev/gemini-api/docs/pricing
25
29
  */
@@ -1 +1 @@
1
- {"version":3,"file":"prefer-count-tokens.d.ts","sourceRoot":"","sources":["../../src/rules/prefer-count-tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAGnC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,UA4HhB,CAAC;AAEF,eAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"prefer-count-tokens.d.ts","sourceRoot":"","sources":["../../src/rules/prefer-count-tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAGnC;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,UA8JhB,CAAC;AAEF,eAAe,IAAI,CAAC"}
@@ -22,6 +22,10 @@ const ast_helpers_js_1 = require("../utils/ast-helpers.js");
22
22
  * 2. Risk exceeding context window limits
23
23
  * 3. Benefit from cost estimation before sending
24
24
  *
25
+ * IGNORED PATTERNS:
26
+ * - Arrays containing functionResponse (these are function call responses)
27
+ * - System instructions (static, known at dev time)
28
+ *
25
29
  * @see https://ai.google.dev/gemini-api/docs/tokens
26
30
  * @see https://ai.google.dev/gemini-api/docs/pricing
27
31
  */
@@ -42,6 +46,16 @@ const rule = {
42
46
  default: 2000,
43
47
  description: 'Character length threshold to suggest token counting (default: 2000 chars ≈ 500 tokens)',
44
48
  },
49
+ ignoreArraysWithFunctionResponse: {
50
+ type: 'boolean',
51
+ default: true,
52
+ description: 'Ignore arrays that contain functionResponse (these are function call responses, not user prompts)',
53
+ },
54
+ warnOnMultimodalArrays: {
55
+ type: 'boolean',
56
+ default: true,
57
+ description: 'Warn when arrays are passed (may contain images that consume many tokens)',
58
+ },
45
59
  },
46
60
  additionalProperties: false,
47
61
  },
@@ -56,6 +70,8 @@ const rule = {
56
70
  // Default threshold: 2000 chars ≈ 500 tokens
57
71
  // This is a reasonable threshold where token counting becomes useful
58
72
  const promptLengthThreshold = options.promptLengthThreshold ?? 2000;
73
+ const ignoreArraysWithFunctionResponse = options.ignoreArraysWithFunctionResponse !== false;
74
+ const warnOnMultimodalArrays = options.warnOnMultimodalArrays !== false;
59
75
  // Track if countTokens was called in the same scope
60
76
  const scopesWithCountTokens = new Set();
61
77
  function getScopeKey(node) {
@@ -108,11 +124,33 @@ const rule = {
108
124
  // Add estimated expression length (rough estimate)
109
125
  promptLength += promptArg.expressions.length * 50;
110
126
  }
111
- // Array of parts (multimodal)
127
+ // Array of parts (multimodal or function responses)
112
128
  if (promptArg.type === 'ArrayExpression') {
113
- // For arrays, we should definitely suggest counting tokens
114
- // as they might contain images which consume many tokens
115
- promptLength = promptLengthThreshold + 1; // Force suggestion
129
+ // Check if array contains functionResponse
130
+ // Pattern: [{ functionResponse: { ... } }]
131
+ if (ignoreArraysWithFunctionResponse) {
132
+ const hasFunctionResponse = promptArg.elements.some((el) => {
133
+ if (!el || el.type !== 'ObjectExpression')
134
+ return false;
135
+ return el.properties.some((prop) => {
136
+ if (prop.type !== 'Property')
137
+ return false;
138
+ if (prop.key.type === 'Identifier' && prop.key.name === 'functionResponse') {
139
+ return true;
140
+ }
141
+ return false;
142
+ });
143
+ });
144
+ if (hasFunctionResponse) {
145
+ // This is a function call response, not a user prompt
146
+ // Skip - these are controlled responses, not user input
147
+ return;
148
+ }
149
+ }
150
+ // For other arrays (multimodal with images), suggest counting tokens
151
+ if (warnOnMultimodalArrays) {
152
+ promptLength = promptLengthThreshold + 1; // Force suggestion
153
+ }
116
154
  }
117
155
  if (promptLength > promptLengthThreshold) {
118
156
  context.report({
@@ -1 +1 @@
1
- {"version":3,"file":"prefer-count-tokens.js","sourceRoot":"","sources":["../../src/rules/prefer-count-tokens.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"prefer-count-tokens.js","sourceRoot":"","sources":["../../src/rules/prefer-count-tokens.ts"],"names":[],"mappings":"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"}
@@ -16,12 +16,18 @@ import type { Rule } from 'eslint';
16
16
  * - executeWithRetry
17
17
  * 5. Async generators (errors propagate to consumer's try/catch)
18
18
  * 6. Class methods that are async generators
19
+ * 7. Calls prefixed with "void" operator (fire-and-forget pattern)
19
20
  *
20
21
  * The rule checks if the API call is:
21
22
  * - Inside a try/catch block
22
23
  * - Chained with .catch()
23
24
  * - Wrapped in a known error-handling function
24
25
  * - Inside an async generator (errors propagate to consumer)
26
+ * - Called with "void" operator (assumes internal error handling)
27
+ *
28
+ * OPTIONS:
29
+ * - ignoreVoidCalls (boolean, default: true): Ignore calls with "void" operator
30
+ * - ignoreCallers (string[], default: []): Function names to ignore
25
31
  */
26
32
  declare const rule: Rule.RuleModule;
27
33
  export default rule;
@@ -1 +1 @@
1
- {"version":3,"file":"require-error-handling.d.ts","sourceRoot":"","sources":["../../src/rules/require-error-handling.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAGnC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,UA6MhB,CAAC;AAEF,eAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"require-error-handling.d.ts","sourceRoot":"","sources":["../../src/rules/require-error-handling.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAGnC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,UAiUhB,CAAC;AAEF,eAAe,IAAI,CAAC"}
@@ -18,12 +18,18 @@ const ast_helpers_js_1 = require("../utils/ast-helpers.js");
18
18
  * - executeWithRetry
19
19
  * 5. Async generators (errors propagate to consumer's try/catch)
20
20
  * 6. Class methods that are async generators
21
+ * 7. Calls prefixed with "void" operator (fire-and-forget pattern)
21
22
  *
22
23
  * The rule checks if the API call is:
23
24
  * - Inside a try/catch block
24
25
  * - Chained with .catch()
25
26
  * - Wrapped in a known error-handling function
26
27
  * - Inside an async generator (errors propagate to consumer)
28
+ * - Called with "void" operator (assumes internal error handling)
29
+ *
30
+ * OPTIONS:
31
+ * - ignoreVoidCalls (boolean, default: true): Ignore calls with "void" operator
32
+ * - ignoreCallers (string[], default: []): Function names to ignore
27
33
  */
28
34
  const rule = {
29
35
  meta: {
@@ -33,7 +39,25 @@ const rule = {
33
39
  recommended: true,
34
40
  url: 'https://github.com/Just-mpm/eslint-plugin-firebase-ai-logic#require-error-handling',
35
41
  },
36
- schema: [],
42
+ schema: [
43
+ {
44
+ type: 'object',
45
+ properties: {
46
+ ignoreVoidCalls: {
47
+ type: 'boolean',
48
+ default: true,
49
+ description: 'Ignore calls prefixed with "void" operator. These typically call functions that handle errors internally.',
50
+ },
51
+ ignoreCallers: {
52
+ type: 'array',
53
+ items: { type: 'string' },
54
+ default: [],
55
+ description: 'Function names to ignore when they call API methods (e.g., ["sendMessage", "handleSubmit"]). Useful for wrapper functions with internal error handling.',
56
+ },
57
+ },
58
+ additionalProperties: false,
59
+ },
60
+ ],
37
61
  messages: {
38
62
  missingErrorHandling: "Firebase AI Logic API call '{{ method }}' should be wrapped in try/catch to handle errors, especially 429 rate limit errors.",
39
63
  suggest429Handling: 'Implement exponential backoff with jitter for 429 errors: delay = Math.pow(2, attempt) * 1000 + Math.random() * 1000',
@@ -41,6 +65,9 @@ const rule = {
41
65
  },
42
66
  },
43
67
  create(context) {
68
+ const options = context.options[0] ?? {};
69
+ const ignoreVoidCalls = options.ignoreVoidCalls !== false; // Default true
70
+ const ignoreCallers = options.ignoreCallers ?? [];
44
71
  // Methods that make API calls and should have error handling
45
72
  const apiMethods = [
46
73
  'generateContent',
@@ -156,6 +183,77 @@ const rule = {
156
183
  }
157
184
  return false;
158
185
  }
186
+ /**
187
+ * Check if the call is wrapped with the "void" operator.
188
+ * Pattern: void sendMessage(msg)
189
+ *
190
+ * When using "void", developers intentionally fire-and-forget,
191
+ * meaning error handling is expected to be inside the called function.
192
+ */
193
+ function isVoidCall(node) {
194
+ const parent = node.parent;
195
+ if (!parent)
196
+ return false;
197
+ // Direct void: void sendMessage()
198
+ if (parent.type === 'UnaryExpression') {
199
+ const unary = parent;
200
+ if (unary.operator === 'void') {
201
+ return true;
202
+ }
203
+ }
204
+ // void wrapper(): void wrapperFn() where wrapperFn calls sendMessage
205
+ // Check if we're inside a function that's called with void
206
+ let current = parent;
207
+ while (current) {
208
+ if (current.type === 'ArrowFunctionExpression' ||
209
+ current.type === 'FunctionExpression') {
210
+ const funcParent = current.parent;
211
+ if (funcParent?.type === 'CallExpression') {
212
+ const callParent = funcParent.parent;
213
+ if (callParent?.type === 'UnaryExpression') {
214
+ const unary = callParent;
215
+ if (unary.operator === 'void') {
216
+ return true;
217
+ }
218
+ }
219
+ }
220
+ }
221
+ current = current.parent ?? null;
222
+ }
223
+ return false;
224
+ }
225
+ /**
226
+ * Check if the API call is inside a caller function that should be ignored.
227
+ * This handles the pattern where a wrapper function (e.g., sendMessage in a hook)
228
+ * has internal error handling, and is called from elsewhere.
229
+ */
230
+ function isInsideIgnoredCaller(node) {
231
+ if (ignoreCallers.length === 0)
232
+ return false;
233
+ let current = node.parent ?? null;
234
+ while (current) {
235
+ // Check for function declaration with matching name
236
+ if (current.type === 'FunctionDeclaration') {
237
+ const funcDecl = current;
238
+ if (funcDecl.id && ignoreCallers.includes(funcDecl.id.name)) {
239
+ return true;
240
+ }
241
+ }
242
+ // Check for variable declaration: const sendMessage = async () => { ... }
243
+ if (current.type === 'ArrowFunctionExpression' ||
244
+ current.type === 'FunctionExpression') {
245
+ const funcParent = current.parent;
246
+ if (funcParent?.type === 'VariableDeclarator') {
247
+ const varDecl = funcParent;
248
+ if (varDecl.id && ignoreCallers.includes(varDecl.id.name)) {
249
+ return true;
250
+ }
251
+ }
252
+ }
253
+ current = current.parent ?? null;
254
+ }
255
+ return false;
256
+ }
159
257
  return {
160
258
  CallExpression(node) {
161
259
  const calleeName = (0, ast_helpers_js_1.getCalleeName)(node);
@@ -164,6 +262,14 @@ const rule = {
164
262
  }
165
263
  // Check if this is an awaited call
166
264
  const isAwaited = node.parent?.type === 'AwaitExpression';
265
+ // Check for void operator (fire-and-forget pattern)
266
+ if (ignoreVoidCalls && isVoidCall(node)) {
267
+ return;
268
+ }
269
+ // Check if inside an ignored caller function
270
+ if (isInsideIgnoredCaller(node)) {
271
+ return;
272
+ }
167
273
  // Check if inside try/catch, has .catch(), inside error handling wrapper,
168
274
  // or inside an async generator (which propagates errors to consumer)
169
275
  const hasErrorHandling = isInsideTryCatch(node) ||
@@ -1 +1 @@
1
- {"version":3,"file":"require-error-handling.js","sourceRoot":"","sources":["../../src/rules/require-error-handling.ts"],"names":[],"mappings":";;AACA,4DAAwD;AAExD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,IAAI,GAAoB;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,WAAW,EACT,gGAAgG;YAClG,WAAW,EAAE,IAAI;YACjB,GAAG,EAAE,oFAAoF;SAC1F;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,oBAAoB,EAClB,8HAA8H;YAChI,kBAAkB,EAChB,sHAAsH;YACxH,oBAAoB,EAClB,iHAAiH;SACpH;KACF;IAED,MAAM,CAAC,OAAO;QACZ,6DAA6D;QAC7D,MAAM,UAAU,GAAG;YACjB,iBAAiB;YACjB,uBAAuB;YACvB,aAAa;YACb,mBAAmB;YACnB,aAAa;YACb,cAAc;SACf,CAAC;QAEF,uDAAuD;QACvD,MAAM,qBAAqB,GAAG;YAC5B,kBAAkB;YAClB,WAAW;YACX,UAAU;YACV,eAAe;YACf,kBAAkB;YAClB,mBAAmB;YACnB,UAAU;YACV,WAAW;YACX,gBAAgB;SACjB,CAAC;QAEF,SAAS,gBAAgB,CAAC,IAAe;YACvC,IAAI,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC;YAE1B,OAAO,OAAO,EAAE,CAAC;gBACf,IAAI,OAAO,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;oBACpC,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,gCAAgC;gBAChC,IACE,OAAO,CAAC,IAAI,KAAK,gBAAgB;oBACjC,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,kBAAkB;oBAC1C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;oBAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,OAAO,EACxC,CAAC;oBACD,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,OAAO,GAAI,OAAO,CAAC,MAAgC,IAAI,IAAI,CAAC;YAC9D,CAAC;YAED,OAAO,KAAK,CAAC;QACf,CAAC;QAED,SAAS,0BAA0B,CAAC,IAAe;YACjD,IAAI,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC;YAE1B,OAAO,OAAO,EAAE,CAAC;gBACf,0BAA0B;gBAC1B,IACE,OAAO,CAAC,IAAI,KAAK,gBAAgB;oBACjC,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,kBAAkB;oBAC1C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;oBAC7C,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,OAAO;wBACvC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,SAAS,CAAC,EAC7C,CAAC;oBACD,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,0CAA0C;gBAC1C,IACE,OAAO,CAAC,IAAI,KAAK,gBAAgB;oBACjC,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,kBAAkB;oBAC1C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;oBAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,MAAM;oBACvC,OAAO,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAC5B,CAAC;oBACD,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,OAAO,GAAI,OAAO,CAAC,MAAgC,IAAI,IAAI,CAAC;YAC9D,CAAC;YAED,OAAO,KAAK,CAAC;QACf,CAAC;QAED,SAAS,4BAA4B,CAAC,IAAe;YACnD,IAAI,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC;YAE1B,OAAO,OAAO,EAAE,CAAC;gBACf,iEAAiE;gBACjE,IAAI,OAAO,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;oBACtC,MAAM,WAAW,GAAG,IAAA,8BAAa,EAAC,OAAO,CAAC,CAAC;oBAC3C,IAAI,WAAW,IAAI,qBAAqB,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;wBAC/D,OAAO,IAAI,CAAC;oBACd,CAAC;gBACH,CAAC;gBAED,iEAAiE;gBACjE,mDAAmD;gBACnD,IACE,OAAO,CAAC,IAAI,KAAK,yBAAyB;oBAC1C,OAAO,CAAC,IAAI,KAAK,oBAAoB,EACrC,CAAC;oBACD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;oBAC9B,IAAI,MAAM,EAAE,IAAI,KAAK,gBAAgB,EAAE,CAAC;wBACtC,MAAM,WAAW,GAAG,IAAA,8BAAa,EAAC,MAAM,CAAC,CAAC;wBAC1C,IAAI,WAAW,IAAI,qBAAqB,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;4BAC/D,OAAO,IAAI,CAAC;wBACd,CAAC;oBACH,CAAC;gBACH,CAAC;gBAED,OAAO,GAAI,OAAO,CAAC,MAAgC,IAAI,IAAI,CAAC;YAC9D,CAAC;YAED,OAAO,KAAK,CAAC;QACf,CAAC;QAED;;;;;WAKG;QACH,SAAS,sBAAsB,CAAC,IAAe;YAC7C,IAAI,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC;YAE1B,OAAO,OAAO,EAAE,CAAC;gBACf,qEAAqE;gBACrE,IACE,OAAO,CAAC,IAAI,KAAK,qBAAqB;oBACtC,OAAO,CAAC,IAAI,KAAK,oBAAoB,EACrC,CAAC;oBACD,MAAM,QAAQ,GAAG,OAGhB,CAAC;oBACF,IAAI,QAAQ,CAAC,KAAK,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;wBACzC,OAAO,IAAI,CAAC;oBACd,CAAC;gBACH,CAAC;gBAED,0DAA0D;gBAC1D,IAAI,OAAO,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;oBACxC,MAAM,UAAU,GAAG,OAKlB,CAAC;oBACF,IAAI,UAAU,CAAC,KAAK,EAAE,KAAK,IAAI,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC;wBAC3D,OAAO,IAAI,CAAC;oBACd,CAAC;gBACH,CAAC;gBAED,OAAO,GAAI,OAAO,CAAC,MAAgC,IAAI,IAAI,CAAC;YAC9D,CAAC;YAED,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO;YACL,cAAc,CAAC,IAAI;gBACjB,MAAM,UAAU,GAAG,IAAA,8BAAa,EAAC,IAAI,CAAC,CAAC;gBAEvC,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;oBACpD,OAAO;gBACT,CAAC;gBAED,mCAAmC;gBACnC,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,KAAK,iBAAiB,CAAC;gBAE1D,0EAA0E;gBAC1E,qEAAqE;gBACrE,MAAM,gBAAgB,GACpB,gBAAgB,CAAC,IAAiB,CAAC;oBACnC,0BAA0B,CAAC,IAAiB,CAAC;oBAC7C,4BAA4B,CAAC,IAAiB,CAAC;oBAC/C,sBAAsB,CAAC,IAAiB,CAAC,CAAC;gBAE5C,IAAI,CAAC,gBAAgB,EAAE,CAAC;oBACtB,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI;wBACJ,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,sBAAsB;wBACtE,IAAI,EAAE;4BACJ,MAAM,EAAE,UAAU;yBACnB;qBACF,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,kBAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"require-error-handling.js","sourceRoot":"","sources":["../../src/rules/require-error-handling.ts"],"names":[],"mappings":"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"}
@@ -12,11 +12,16 @@ import type { Rule } from 'eslint';
12
12
  * This rule should NOT report errors for using "required" in Schema.object()
13
13
  * because it's a valid and common pattern for function calling parameters.
14
14
  *
15
- * The rule now only suggests (not warns) when using BOTH "required" AND
15
+ * The rule only suggests (not warns) when using BOTH "required" AND
16
16
  * "optionalProperties" in the same schema - which while redundant, is
17
- * technically valid and can improve code clarity.
17
+ * technically valid and can improve code clarity/documentation.
18
18
  *
19
- * CONFIGURABLE: Set 'allowBothRequiredAndOptional' to true to disable this check.
19
+ * DEFAULT BEHAVIOR: Allows both "required" and "optionalProperties" because:
20
+ * 1. It's a valid pattern in Firebase AI SDK
21
+ * 2. It improves readability by being explicit
22
+ * 3. Many codebases use this pattern deliberately
23
+ *
24
+ * CONFIGURABLE: Set 'allowBothRequiredAndOptional' to false to enable warnings.
20
25
  */
21
26
  declare const rule: Rule.RuleModule;
22
27
  export default rule;
@@ -1 +1 @@
1
- {"version":3,"file":"validate-schema-structure.d.ts","sourceRoot":"","sources":["../../src/rules/validate-schema-structure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAGnC;;;;;;;;;;;;;;;;;;GAkBG;AACH,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,UA6DhB,CAAC;AAEF,eAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"validate-schema-structure.d.ts","sourceRoot":"","sources":["../../src/rules/validate-schema-structure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAGnC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,UA8DhB,CAAC;AAEF,eAAe,IAAI,CAAC"}
@@ -14,11 +14,16 @@ const ast_helpers_js_1 = require("../utils/ast-helpers.js");
14
14
  * This rule should NOT report errors for using "required" in Schema.object()
15
15
  * because it's a valid and common pattern for function calling parameters.
16
16
  *
17
- * The rule now only suggests (not warns) when using BOTH "required" AND
17
+ * The rule only suggests (not warns) when using BOTH "required" AND
18
18
  * "optionalProperties" in the same schema - which while redundant, is
19
- * technically valid and can improve code clarity.
19
+ * technically valid and can improve code clarity/documentation.
20
20
  *
21
- * CONFIGURABLE: Set 'allowBothRequiredAndOptional' to true to disable this check.
21
+ * DEFAULT BEHAVIOR: Allows both "required" and "optionalProperties" because:
22
+ * 1. It's a valid pattern in Firebase AI SDK
23
+ * 2. It improves readability by being explicit
24
+ * 3. Many codebases use this pattern deliberately
25
+ *
26
+ * CONFIGURABLE: Set 'allowBothRequiredAndOptional' to false to enable warnings.
22
27
  */
23
28
  const rule = {
24
29
  meta: {
@@ -34,8 +39,8 @@ const rule = {
34
39
  properties: {
35
40
  allowBothRequiredAndOptional: {
36
41
  type: 'boolean',
37
- default: false,
38
- description: 'Allow using both "required" and "optionalProperties" in the same schema',
42
+ default: true,
43
+ description: 'Allow using both "required" and "optionalProperties" in the same schema. Set to false to warn about redundancy.',
39
44
  },
40
45
  },
41
46
  additionalProperties: false,
@@ -47,7 +52,8 @@ const rule = {
47
52
  },
48
53
  create(context) {
49
54
  const options = context.options[0] ?? {};
50
- const allowBothRequiredAndOptional = options.allowBothRequiredAndOptional ?? false;
55
+ // Default is true - allow both patterns since it's valid and improves readability
56
+ const allowBothRequiredAndOptional = options.allowBothRequiredAndOptional !== false;
51
57
  return {
52
58
  // Check for objects that have BOTH required AND optionalProperties
53
59
  ObjectExpression(node) {
@@ -1 +1 @@
1
- {"version":3,"file":"validate-schema-structure.js","sourceRoot":"","sources":["../../src/rules/validate-schema-structure.ts"],"names":[],"mappings":";;AACA,4DAA0E;AAE1E;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,IAAI,GAAoB;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,WAAW,EACT,+DAA+D;YACjE,WAAW,EAAE,IAAI;YACjB,GAAG,EAAE,uFAAuF;SAC7F;QACD,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,4BAA4B,EAAE;wBAC5B,IAAI,EAAE,SAAS;wBACf,OAAO,EAAE,KAAK;wBACd,WAAW,EAAE,yEAAyE;qBACvF;iBACF;gBACD,oBAAoB,EAAE,KAAK;aAC5B;SACF;QACD,QAAQ,EAAE;YACR,gCAAgC,EAC9B,kIAAkI;SACrI;KACF;IAED,MAAM,CAAC,OAAO;QACZ,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACzC,MAAM,4BAA4B,GAAG,OAAO,CAAC,4BAA4B,IAAI,KAAK,CAAC;QAEnF,OAAO;YACL,mEAAmE;YACnE,gBAAgB,CAAC,IAAI;gBACnB,mCAAmC;gBACnC,IAAI,4BAA4B;oBAAE,OAAO;gBAEzC,MAAM,WAAW,GAAG,IAAA,6BAAY,EAAC,IAAI,EAAE,UAAU,CAAC,CAAC;gBACnD,MAAM,qBAAqB,GAAG,IAAA,6BAAY,EAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC;gBACvE,MAAM,aAAa,GAAG,IAAA,6BAAY,EAAC,IAAI,EAAE,YAAY,CAAC,CAAC;gBAEvD,oDAAoD;gBACpD,IAAI,CAAC,aAAa;oBAAE,OAAO;gBAE3B,yDAAyD;gBACzD,uEAAuE;gBACvE,IACE,WAAW;oBACX,qBAAqB;oBACrB,IAAA,kCAAiB,EAAC,WAAW,CAAC,KAAK,CAAC;oBACpC,IAAA,kCAAiB,EAAC,qBAAqB,CAAC,KAAK,CAAC,EAC9C,CAAC;oBACD,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI,EAAE,qBAAqB,CAAC,GAAG;wBAC/B,SAAS,EAAE,kCAAkC;qBAC9C,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,kBAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"validate-schema-structure.js","sourceRoot":"","sources":["../../src/rules/validate-schema-structure.ts"],"names":[],"mappings":";;AACA,4DAA0E;AAE1E;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,IAAI,GAAoB;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,WAAW,EACT,+DAA+D;YACjE,WAAW,EAAE,IAAI;YACjB,GAAG,EAAE,uFAAuF;SAC7F;QACD,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,4BAA4B,EAAE;wBAC5B,IAAI,EAAE,SAAS;wBACf,OAAO,EAAE,IAAI;wBACb,WAAW,EAAE,iHAAiH;qBAC/H;iBACF;gBACD,oBAAoB,EAAE,KAAK;aAC5B;SACF;QACD,QAAQ,EAAE;YACR,gCAAgC,EAC9B,kIAAkI;SACrI;KACF;IAED,MAAM,CAAC,OAAO;QACZ,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACzC,kFAAkF;QAClF,MAAM,4BAA4B,GAAG,OAAO,CAAC,4BAA4B,KAAK,KAAK,CAAC;QAEpF,OAAO;YACL,mEAAmE;YACnE,gBAAgB,CAAC,IAAI;gBACnB,mCAAmC;gBACnC,IAAI,4BAA4B;oBAAE,OAAO;gBAEzC,MAAM,WAAW,GAAG,IAAA,6BAAY,EAAC,IAAI,EAAE,UAAU,CAAC,CAAC;gBACnD,MAAM,qBAAqB,GAAG,IAAA,6BAAY,EAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC;gBACvE,MAAM,aAAa,GAAG,IAAA,6BAAY,EAAC,IAAI,EAAE,YAAY,CAAC,CAAC;gBAEvD,oDAAoD;gBACpD,IAAI,CAAC,aAAa;oBAAE,OAAO;gBAE3B,yDAAyD;gBACzD,uEAAuE;gBACvE,IACE,WAAW;oBACX,qBAAqB;oBACrB,IAAA,kCAAiB,EAAC,WAAW,CAAC,KAAK,CAAC;oBACpC,IAAA,kCAAiB,EAAC,qBAAqB,CAAC,KAAK,CAAC,EAC9C,CAAC;oBACD,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI,EAAE,qBAAqB,CAAC,GAAG;wBAC/B,SAAS,EAAE,kCAAkC;qBAC9C,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,kBAAe,IAAI,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-firebase-ai-logic",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "ESLint plugin for Firebase AI Logic best practices, detecting deprecated imports, models, and common anti-patterns",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",