eslint-plugin-firebase-ai-logic 1.2.0 → 1.4.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.
Files changed (38) hide show
  1. package/dist/index.js +1 -1
  2. package/dist/rules/check-temperature-defaults.d.ts +24 -0
  3. package/dist/rules/check-temperature-defaults.d.ts.map +1 -1
  4. package/dist/rules/check-temperature-defaults.js +73 -7
  5. package/dist/rules/check-temperature-defaults.js.map +1 -1
  6. package/dist/rules/prefer-count-tokens.d.ts +24 -0
  7. package/dist/rules/prefer-count-tokens.d.ts.map +1 -1
  8. package/dist/rules/prefer-count-tokens.js +29 -3
  9. package/dist/rules/prefer-count-tokens.js.map +1 -1
  10. package/dist/rules/prefer-optional-properties.d.ts +18 -0
  11. package/dist/rules/prefer-optional-properties.d.ts.map +1 -1
  12. package/dist/rules/prefer-optional-properties.js +30 -2
  13. package/dist/rules/prefer-optional-properties.js.map +1 -1
  14. package/dist/rules/require-app-check-production.d.ts +21 -0
  15. package/dist/rules/require-app-check-production.d.ts.map +1 -1
  16. package/dist/rules/require-app-check-production.js +111 -13
  17. package/dist/rules/require-app-check-production.js.map +1 -1
  18. package/dist/rules/require-backend.d.ts +17 -0
  19. package/dist/rules/require-backend.d.ts.map +1 -1
  20. package/dist/rules/require-backend.js +35 -42
  21. package/dist/rules/require-backend.js.map +1 -1
  22. package/dist/rules/require-error-handling.d.ts +24 -0
  23. package/dist/rules/require-error-handling.d.ts.map +1 -1
  24. package/dist/rules/require-error-handling.js +96 -3
  25. package/dist/rules/require-error-handling.js.map +1 -1
  26. package/dist/rules/validate-schema-structure.d.ts +19 -0
  27. package/dist/rules/validate-schema-structure.d.ts.map +1 -1
  28. package/dist/rules/validate-schema-structure.js +58 -21
  29. package/dist/rules/validate-schema-structure.js.map +1 -1
  30. package/dist/utils/ast-helpers.d.ts +4 -0
  31. package/dist/utils/ast-helpers.d.ts.map +1 -1
  32. package/dist/utils/ast-helpers.js +21 -0
  33. package/dist/utils/ast-helpers.js.map +1 -1
  34. package/dist/utils/constants.d.ts +2 -2
  35. package/dist/utils/constants.d.ts.map +1 -1
  36. package/dist/utils/constants.js +12 -5
  37. package/dist/utils/constants.js.map +1 -1
  38. package/package.json +1 -1
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.2.0',
242
+ version: '1.4.0',
243
243
  },
244
244
  rules,
245
245
  configs,
@@ -1,4 +1,28 @@
1
1
  import type { Rule } from 'eslint';
2
+ /**
3
+ * check-temperature-defaults
4
+ *
5
+ * This rule suggests using the default temperature (1.0) for Gemini 3 models,
6
+ * but with important exceptions:
7
+ *
8
+ * ONLY APPLIES TO:
9
+ * - gemini-3-flash-preview
10
+ * - gemini-3-pro-preview
11
+ * (Other models like gemini-2.5-* don't have this recommendation)
12
+ *
13
+ * EXCEPTIONS (low temperature is valid and recommended):
14
+ * 1. Structured output (responseMimeType: 'application/json')
15
+ * - Low temperature (0.1-0.3) prevents hallucinations in extraction tasks
16
+ * 2. Classification tasks (maxOutputTokens <= 20)
17
+ * - Deterministic outputs benefit from low temperature
18
+ * 3. Data extraction with responseSchema
19
+ * - Precise extraction needs low temperature
20
+ *
21
+ * The rule only warns when:
22
+ * - Model is Gemini 3 (flash or pro preview)
23
+ * - Temperature is NOT 1.0
24
+ * - AND it's NOT a structured output or classification task
25
+ */
2
26
  declare const rule: Rule.RuleModule;
3
27
  export default rule;
4
28
  //# sourceMappingURL=check-temperature-defaults.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"check-temperature-defaults.d.ts","sourceRoot":"","sources":["../../src/rules/check-temperature-defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAOnC,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,UA6DhB,CAAC;AAEF,eAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"check-temperature-defaults.d.ts","sourceRoot":"","sources":["../../src/rules/check-temperature-defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AASnC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,UA4GhB,CAAC;AAEF,eAAe,IAAI,CAAC"}
@@ -1,20 +1,51 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const ast_helpers_js_1 = require("../utils/ast-helpers.js");
4
+ /**
5
+ * check-temperature-defaults
6
+ *
7
+ * This rule suggests using the default temperature (1.0) for Gemini 3 models,
8
+ * but with important exceptions:
9
+ *
10
+ * ONLY APPLIES TO:
11
+ * - gemini-3-flash-preview
12
+ * - gemini-3-pro-preview
13
+ * (Other models like gemini-2.5-* don't have this recommendation)
14
+ *
15
+ * EXCEPTIONS (low temperature is valid and recommended):
16
+ * 1. Structured output (responseMimeType: 'application/json')
17
+ * - Low temperature (0.1-0.3) prevents hallucinations in extraction tasks
18
+ * 2. Classification tasks (maxOutputTokens <= 20)
19
+ * - Deterministic outputs benefit from low temperature
20
+ * 3. Data extraction with responseSchema
21
+ * - Precise extraction needs low temperature
22
+ *
23
+ * The rule only warns when:
24
+ * - Model is Gemini 3 (flash or pro preview)
25
+ * - Temperature is NOT 1.0
26
+ * - AND it's NOT a structured output or classification task
27
+ */
4
28
  const rule = {
5
29
  meta: {
6
- type: 'problem',
30
+ type: 'suggestion',
7
31
  docs: {
8
- description: 'Enforce default temperature (1.0) for Gemini 3 models to prevent unexpected behavior',
32
+ description: 'Suggest default temperature (1.0) for Gemini 3 models, except for structured output and classification tasks',
9
33
  recommended: true,
10
34
  url: 'https://github.com/Just-mpm/eslint-plugin-firebase-ai-logic#check-temperature-defaults',
11
35
  },
12
36
  schema: [],
13
37
  messages: {
14
- nonDefaultTemperature: 'Gemini 3 models are optimized for the default temperature (1.0). Changing this value may lead to unexpected behavior, looping, or degraded reasoning performance.',
38
+ nonDefaultTemperature: 'Consider using the default temperature (1.0) for Gemini 3 models. Lower values may cause looping or degraded reasoning. Exception: low temperature is appropriate for structured output (JSON) and classification tasks.',
15
39
  },
16
40
  },
17
41
  create(context) {
42
+ // Gemini 3 models that have the temperature=1.0 recommendation
43
+ const GEMINI_3_MODELS = [
44
+ 'gemini-3-flash-preview',
45
+ 'gemini-3-pro-preview',
46
+ 'gemini-3-flash',
47
+ 'gemini-3-pro',
48
+ ];
18
49
  return {
19
50
  CallExpression(node) {
20
51
  const calleeName = (0, ast_helpers_js_1.getCalleeName)(node);
@@ -27,20 +58,55 @@ const rule = {
27
58
  const configArg = node.arguments[1];
28
59
  if (!configArg || !(0, ast_helpers_js_1.isObjectExpression)(configArg))
29
60
  return;
61
+ // Check model name - only apply to Gemini 3 models
62
+ const modelProp = (0, ast_helpers_js_1.findProperty)(configArg, 'model');
63
+ if (modelProp) {
64
+ const modelName = (0, ast_helpers_js_1.getStringValue)(modelProp.value);
65
+ if (modelName && !GEMINI_3_MODELS.some(m => modelName.includes(m))) {
66
+ // Not a Gemini 3 model - don't apply this rule
67
+ return;
68
+ }
69
+ }
30
70
  // Check for generationConfig
31
- let generationConfig = (0, ast_helpers_js_1.findProperty)(configArg, 'generationConfig');
32
- let configToCheck = generationConfig
71
+ const generationConfig = (0, ast_helpers_js_1.findProperty)(configArg, 'generationConfig');
72
+ const configToCheck = generationConfig
33
73
  ? generationConfig.value
34
74
  : configArg;
35
75
  if (!(0, ast_helpers_js_1.isObjectExpression)(configToCheck))
36
76
  return;
77
+ // Check for responseMimeType - if it's 'application/json', low temperature is valid
78
+ const responseMimeTypeProp = (0, ast_helpers_js_1.findProperty)(configToCheck, 'responseMimeType');
79
+ if (responseMimeTypeProp) {
80
+ const mimeType = (0, ast_helpers_js_1.getStringValue)(responseMimeTypeProp.value);
81
+ if (mimeType === 'application/json') {
82
+ // Structured output - low temperature is appropriate, don't warn
83
+ return;
84
+ }
85
+ }
86
+ // Check for responseSchema - if present, it's structured output
87
+ const responseSchemaProp = (0, ast_helpers_js_1.findProperty)(configToCheck, 'responseSchema');
88
+ if (responseSchemaProp) {
89
+ // Has response schema - structured output, don't warn
90
+ return;
91
+ }
92
+ // Check for maxOutputTokens - if very low (<= 20), it's likely classification
93
+ const maxOutputTokensProp = (0, ast_helpers_js_1.findProperty)(configToCheck, 'maxOutputTokens');
94
+ if (maxOutputTokensProp) {
95
+ const maxTokens = (0, ast_helpers_js_1.getNumberValue)(maxOutputTokensProp.value);
96
+ if (maxTokens !== null && maxTokens <= 20) {
97
+ // Classification task (very short output) - low temperature is appropriate
98
+ return;
99
+ }
100
+ }
37
101
  // Check for temperature property
38
102
  const temperatureProp = (0, ast_helpers_js_1.findProperty)(configToCheck, 'temperature');
39
103
  if (temperatureProp) {
40
- // If value is literal and not 1.0, report
104
+ // If value is literal and not 1.0, suggest (not require) using default
41
105
  if (temperatureProp.value.type === 'Literal' &&
42
106
  typeof temperatureProp.value.value === 'number') {
43
- if (temperatureProp.value.value !== 1.0) {
107
+ const temp = temperatureProp.value.value;
108
+ // Only warn for non-default temperature when NOT doing structured output
109
+ if (temp !== 1.0) {
44
110
  context.report({
45
111
  node: temperatureProp,
46
112
  messageId: 'nonDefaultTemperature',
@@ -1 +1 @@
1
- {"version":3,"file":"check-temperature-defaults.js","sourceRoot":"","sources":["../../src/rules/check-temperature-defaults.ts"],"names":[],"mappings":";;AACA,4DAIiC;AAEjC,MAAM,IAAI,GAAoB;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EACT,sFAAsF;YACxF,WAAW,EAAE,IAAI;YACjB,GAAG,EAAE,wFAAwF;SAC9F;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,qBAAqB,EACnB,mKAAmK;SACtK;KACF;IAED,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,cAAc,CAAC,IAAI;gBACjB,MAAM,UAAU,GAAG,IAAA,8BAAa,EAAC,IAAI,CAAC,CAAC;gBAEvC,oDAAoD;gBACpD,IACE,UAAU,KAAK,oBAAoB;oBACnC,UAAU,KAAK,iBAAiB,EAChC,CAAC;oBACD,OAAO;gBACT,CAAC;gBAED,+CAA+C;gBAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;gBACpC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAA,mCAAkB,EAAC,SAAS,CAAC;oBAAE,OAAO;gBAEzD,6BAA6B;gBAC7B,IAAI,gBAAgB,GAAG,IAAA,6BAAY,EAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC;gBACnE,IAAI,aAAa,GAAG,gBAAgB;oBAClC,CAAC,CAAC,gBAAgB,CAAC,KAAK;oBACxB,CAAC,CAAC,SAAS,CAAC;gBAEd,IAAI,CAAC,IAAA,mCAAkB,EAAC,aAAa,CAAC;oBAAE,OAAO;gBAE/C,iCAAiC;gBACjC,MAAM,eAAe,GAAG,IAAA,6BAAY,EAAC,aAAa,EAAE,aAAa,CAAC,CAAC;gBAEnE,IAAI,eAAe,EAAE,CAAC;oBACpB,0CAA0C;oBAC1C,IACE,eAAe,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS;wBACxC,OAAO,eAAe,CAAC,KAAK,CAAC,KAAK,KAAK,QAAQ,EAC/C,CAAC;wBACD,IAAI,eAAe,CAAC,KAAK,CAAC,KAAK,KAAK,GAAG,EAAE,CAAC;4BACxC,OAAO,CAAC,MAAM,CAAC;gCACb,IAAI,EAAE,eAAe;gCACrB,SAAS,EAAE,uBAAuB;6BACnC,CAAC,CAAC;wBACL,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,kBAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"check-temperature-defaults.js","sourceRoot":"","sources":["../../src/rules/check-temperature-defaults.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,28 @@
1
1
  import type { Rule } from 'eslint';
2
+ /**
3
+ * prefer-count-tokens
4
+ *
5
+ * This rule suggests using countTokens() before large requests.
6
+ *
7
+ * WHY 2000 CHARACTERS DEFAULT?
8
+ * - 2000 chars ≈ 500 tokens (roughly 4 chars per token)
9
+ * - Cost increases significantly above 200K tokens context
10
+ * - countTokens API is FREE and has 3000 RPM quota
11
+ * - Below 500 tokens, the cost impact is minimal (~$0.0001 for flash)
12
+ *
13
+ * Based on Google's pricing:
14
+ * - Gemini 2.5 Flash-Lite: $0.10/M input tokens
15
+ * - Gemini 2.5 Flash: $0.15/M input tokens
16
+ * - Gemini 3 Pro: $2.00/M input tokens (up to 200K), $4.00/M above
17
+ *
18
+ * The rule is meant to catch large prompts that could:
19
+ * 1. Unexpectedly increase costs
20
+ * 2. Risk exceeding context window limits
21
+ * 3. Benefit from cost estimation before sending
22
+ *
23
+ * @see https://ai.google.dev/gemini-api/docs/tokens
24
+ * @see https://ai.google.dev/gemini-api/docs/pricing
25
+ */
2
26
  declare const rule: Rule.RuleModule;
3
27
  export default rule;
4
28
  //# sourceMappingURL=prefer-count-tokens.d.ts.map
@@ -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,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,UA0HhB,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;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,UA4HhB,CAAC;AAEF,eAAe,IAAI,CAAC"}
@@ -1,6 +1,30 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const ast_helpers_js_1 = require("../utils/ast-helpers.js");
4
+ /**
5
+ * prefer-count-tokens
6
+ *
7
+ * This rule suggests using countTokens() before large requests.
8
+ *
9
+ * WHY 2000 CHARACTERS DEFAULT?
10
+ * - 2000 chars ≈ 500 tokens (roughly 4 chars per token)
11
+ * - Cost increases significantly above 200K tokens context
12
+ * - countTokens API is FREE and has 3000 RPM quota
13
+ * - Below 500 tokens, the cost impact is minimal (~$0.0001 for flash)
14
+ *
15
+ * Based on Google's pricing:
16
+ * - Gemini 2.5 Flash-Lite: $0.10/M input tokens
17
+ * - Gemini 2.5 Flash: $0.15/M input tokens
18
+ * - Gemini 3 Pro: $2.00/M input tokens (up to 200K), $4.00/M above
19
+ *
20
+ * The rule is meant to catch large prompts that could:
21
+ * 1. Unexpectedly increase costs
22
+ * 2. Risk exceeding context window limits
23
+ * 3. Benefit from cost estimation before sending
24
+ *
25
+ * @see https://ai.google.dev/gemini-api/docs/tokens
26
+ * @see https://ai.google.dev/gemini-api/docs/pricing
27
+ */
4
28
  const rule = {
5
29
  meta: {
6
30
  type: 'suggestion',
@@ -15,8 +39,8 @@ const rule = {
15
39
  properties: {
16
40
  promptLengthThreshold: {
17
41
  type: 'number',
18
- default: 500,
19
- description: 'Character length threshold to suggest token counting',
42
+ default: 2000,
43
+ description: 'Character length threshold to suggest token counting (default: 2000 chars ≈ 500 tokens)',
20
44
  },
21
45
  },
22
46
  additionalProperties: false,
@@ -29,7 +53,9 @@ const rule = {
29
53
  },
30
54
  create(context) {
31
55
  const options = context.options[0] ?? {};
32
- const promptLengthThreshold = options.promptLengthThreshold ?? 500;
56
+ // Default threshold: 2000 chars 500 tokens
57
+ // This is a reasonable threshold where token counting becomes useful
58
+ const promptLengthThreshold = options.promptLengthThreshold ?? 2000;
33
59
  // Track if countTokens was called in the same scope
34
60
  const scopesWithCountTokens = new Set();
35
61
  function getScopeKey(node) {
@@ -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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"}
@@ -1,4 +1,22 @@
1
1
  import type { Rule } from 'eslint';
2
+ /**
3
+ * prefer-optional-properties
4
+ *
5
+ * This rule suggests using 'optionalProperties' array for optional fields,
6
+ * but with important exceptions:
7
+ *
8
+ * EXCEPTIONS (no warning):
9
+ * 1. If the schema has a 'required' array defined
10
+ * - This is the standard way to define required fields in function calling
11
+ * - Fields not in 'required' are implicitly optional
12
+ * 2. If the schema is for function calling parameters
13
+ * - Function calling uses 'required' array pattern
14
+ *
15
+ * The rule only warns when:
16
+ * - Schema has many properties (>5)
17
+ * - AND no 'optionalProperties' array
18
+ * - AND no 'required' array (which would indicate intent)
19
+ */
2
20
  declare const rule: Rule.RuleModule;
3
21
  export default rule;
4
22
  //# sourceMappingURL=prefer-optional-properties.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"prefer-optional-properties.d.ts","sourceRoot":"","sources":["../../src/rules/prefer-optional-properties.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAQnC,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,UA0GhB,CAAC;AAEF,eAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"prefer-optional-properties.d.ts","sourceRoot":"","sources":["../../src/rules/prefer-optional-properties.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAQnC;;;;;;;;;;;;;;;;;GAiBG;AACH,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,UAqHhB,CAAC;AAEF,eAAe,IAAI,CAAC"}
@@ -1,6 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const ast_helpers_js_1 = require("../utils/ast-helpers.js");
4
+ /**
5
+ * prefer-optional-properties
6
+ *
7
+ * This rule suggests using 'optionalProperties' array for optional fields,
8
+ * but with important exceptions:
9
+ *
10
+ * EXCEPTIONS (no warning):
11
+ * 1. If the schema has a 'required' array defined
12
+ * - This is the standard way to define required fields in function calling
13
+ * - Fields not in 'required' are implicitly optional
14
+ * 2. If the schema is for function calling parameters
15
+ * - Function calling uses 'required' array pattern
16
+ *
17
+ * The rule only warns when:
18
+ * - Schema has many properties (>5)
19
+ * - AND no 'optionalProperties' array
20
+ * - AND no 'required' array (which would indicate intent)
21
+ */
4
22
  const rule = {
5
23
  meta: {
6
24
  type: 'suggestion',
@@ -13,7 +31,7 @@ const rule = {
13
31
  messages: {
14
32
  useOptionalProperties: "In Firebase AI Logic, all schema fields are required by default. Use 'optionalProperties: [\"fieldName\"]' array to mark fields as optional.",
15
33
  nullableNotOptional: "Using 'nullable: true' makes the field accept null but still requires it. Use 'optionalProperties' array to make it truly optional.",
16
- missingOptionalProperties: "Schema has many properties but no 'optionalProperties' array. Consider which fields should be optional.",
34
+ missingOptionalProperties: "Schema has many properties but no 'optionalProperties' or 'required' array. Consider which fields should be optional.",
17
35
  },
18
36
  },
19
37
  create(context) {
@@ -22,6 +40,12 @@ const rule = {
22
40
  return;
23
41
  const propertiesProp = (0, ast_helpers_js_1.findProperty)(obj, 'properties');
24
42
  const optionalPropertiesProp = (0, ast_helpers_js_1.findProperty)(obj, 'optionalProperties');
43
+ const requiredProp = (0, ast_helpers_js_1.findProperty)(obj, 'required');
44
+ // If 'required' array is defined, the developer has explicitly chosen
45
+ // which fields are required - no need to warn about optionalProperties
46
+ if (requiredProp) {
47
+ return;
48
+ }
25
49
  // Check for nullable fields without optionalProperties
26
50
  if (propertiesProp && (0, ast_helpers_js_1.isObjectExpression)(propertiesProp.value)) {
27
51
  const propsObj = propertiesProp.value;
@@ -55,7 +79,11 @@ const rule = {
55
79
  // Check if schema has many properties but no optionalProperties
56
80
  if (propertiesProp && (0, ast_helpers_js_1.isObjectExpression)(propertiesProp.value)) {
57
81
  const propertyCount = propertiesProp.value.properties.filter(ast_helpers_js_1.isProperty).length;
58
- if (propertyCount > 5 && !optionalPropertiesProp) {
82
+ // Only warn if:
83
+ // - Many properties (>5)
84
+ // - No optionalProperties
85
+ // - No required array (which indicates intentional field selection)
86
+ if (propertyCount > 5 && !optionalPropertiesProp && !requiredProp) {
59
87
  context.report({
60
88
  node: obj,
61
89
  messageId: 'missingOptionalProperties',
@@ -1 +1 @@
1
- {"version":3,"file":"prefer-optional-properties.js","sourceRoot":"","sources":["../../src/rules/prefer-optional-properties.ts"],"names":[],"mappings":";;AACA,4DAKiC;AAEjC,MAAM,IAAI,GAAoB;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,WAAW,EACT,oGAAoG;YACtG,WAAW,EAAE,IAAI;YACjB,GAAG,EAAE,wFAAwF;SAC9F;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,qBAAqB,EACnB,8IAA8I;YAChJ,mBAAmB,EACjB,qIAAqI;YACvI,yBAAyB,EACvB,yGAAyG;SAC5G;KACF;IAED,MAAM,CAAC,OAAO;QACZ,SAAS,iBAAiB,CAAC,KAAgB,EAAE,GAA6C;YACxF,IAAI,CAAC,IAAA,mCAAkB,EAAC,GAAG,CAAC;gBAAE,OAAO;YAErC,MAAM,cAAc,GAAG,IAAA,6BAAY,EAAC,GAAG,EAAE,YAAY,CAAC,CAAC;YACvD,MAAM,sBAAsB,GAAG,IAAA,6BAAY,EAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC;YAEvE,uDAAuD;YACvD,IAAI,cAAc,IAAI,IAAA,mCAAkB,EAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC/D,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,CAAC;gBACtC,IAAI,iBAAiB,GAAG,KAAK,CAAC;gBAC9B,MAAM,kBAAkB,GAAa,EAAE,CAAC;gBAExC,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;oBACvC,IAAI,CAAC,IAAA,2BAAU,EAAC,IAAI,CAAC;wBAAE,SAAS;oBAEhC,MAAM,QAAQ,GAAG,IAAA,gCAAe,EAAC,IAAI,CAAC,CAAC;oBACvC,IAAI,CAAC,QAAQ;wBAAE,SAAS;oBAExB,uDAAuD;oBACvD,IAAI,IAAA,mCAAkB,EAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;wBACnC,MAAM,YAAY,GAAG,IAAA,6BAAY,EAAC,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;wBAC1D,IACE,YAAY;4BACZ,YAAY,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS;4BACrC,YAAY,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI,EACjC,CAAC;4BACD,iBAAiB,GAAG,IAAI,CAAC;4BACzB,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;wBACpC,CAAC;oBACH,CAAC;gBACH,CAAC;gBAED,2FAA2F;gBAC3F,IAAI,iBAAiB,IAAI,CAAC,sBAAsB,EAAE,CAAC;oBACjD,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI,EAAE,cAAc;wBACpB,SAAS,EAAE,qBAAqB;qBACjC,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAED,gEAAgE;YAChE,IAAI,cAAc,IAAI,IAAA,mCAAkB,EAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC/D,MAAM,aAAa,GAAG,cAAc,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,2BAAU,CAAC,CAAC,MAAM,CAAC;gBAEhF,IAAI,aAAa,GAAG,CAAC,IAAI,CAAC,sBAAsB,EAAE,CAAC;oBACjD,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI,EAAE,GAAgB;wBACtB,SAAS,EAAE,2BAA2B;qBACvC,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO;YACL,8BAA8B;YAC9B,cAAc,CAAC,IAAI;gBACjB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;gBAE3B,IACE,MAAM,CAAC,IAAI,KAAK,kBAAkB;oBAClC,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY;oBACnC,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,QAAQ;oBAC/B,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;oBACrC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,QAAQ,EACjC,CAAC;oBACD,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;oBAC9B,IAAI,IAAA,mCAAkB,EAAC,GAAG,CAAC,EAAE,CAAC;wBAC5B,iBAAiB,CAAC,GAAgB,EAAE,GAAG,CAAC,CAAC;oBAC3C,CAAC;gBACH,CAAC;YACH,CAAC;YAED,wCAAwC;YACxC,QAAQ,CAAC,IAAI;gBACX,IACE,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,YAAY;oBAC9B,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,gBAAgB;oBAClC,IAAA,mCAAkB,EAAC,IAAI,CAAC,KAAK,CAAC,EAC9B,CAAC;oBACD,iBAAiB,CAAC,IAAI,CAAC,KAAkB,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;gBACzD,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,kBAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"prefer-optional-properties.js","sourceRoot":"","sources":["../../src/rules/prefer-optional-properties.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,25 @@
1
1
  import type { Rule } from 'eslint';
2
+ /**
3
+ * require-app-check-production
4
+ *
5
+ * This rule suggests using App Check to protect AI endpoints from abuse.
6
+ *
7
+ * IMPORTANT LIMITATIONS:
8
+ * - This rule only checks within the SAME FILE
9
+ * - Many projects use lazy loading where App Check is initialized in a separate file
10
+ * - Projects using hooks like useAppCheck() or ensureAppCheckReady() are valid
11
+ *
12
+ * The rule checks for:
13
+ * 1. Direct import of 'firebase/app-check'
14
+ * 2. Calls to initializeAppCheck()
15
+ * 3. Common patterns: useAppCheck, ensureAppCheckReady, AppCheckProvider
16
+ * 4. Module-level detection: If the file imports from a module that handles AI
17
+ * (like './ai' or '../firebase/ai'), it's likely App Check is handled there
18
+ *
19
+ * If none are found in the same file as getAI(), it suggests (not requires) App Check.
20
+ *
21
+ * CONFIGURABLE: Set 'ignoreFiles' to skip specific files/patterns.
22
+ */
2
23
  declare const rule: Rule.RuleModule;
3
24
  export default rule;
4
25
  //# sourceMappingURL=require-app-check-production.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"require-app-check-production.d.ts","sourceRoot":"","sources":["../../src/rules/require-app-check-production.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAGnC,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,UAmEhB,CAAC;AAEF,eAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"require-app-check-production.d.ts","sourceRoot":"","sources":["../../src/rules/require-app-check-production.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAGnC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,UA0JhB,CAAC;AAEF,eAAe,IAAI,CAAC"}
@@ -1,6 +1,27 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const ast_helpers_js_1 = require("../utils/ast-helpers.js");
4
+ /**
5
+ * require-app-check-production
6
+ *
7
+ * This rule suggests using App Check to protect AI endpoints from abuse.
8
+ *
9
+ * IMPORTANT LIMITATIONS:
10
+ * - This rule only checks within the SAME FILE
11
+ * - Many projects use lazy loading where App Check is initialized in a separate file
12
+ * - Projects using hooks like useAppCheck() or ensureAppCheckReady() are valid
13
+ *
14
+ * The rule checks for:
15
+ * 1. Direct import of 'firebase/app-check'
16
+ * 2. Calls to initializeAppCheck()
17
+ * 3. Common patterns: useAppCheck, ensureAppCheckReady, AppCheckProvider
18
+ * 4. Module-level detection: If the file imports from a module that handles AI
19
+ * (like './ai' or '../firebase/ai'), it's likely App Check is handled there
20
+ *
21
+ * If none are found in the same file as getAI(), it suggests (not requires) App Check.
22
+ *
23
+ * CONFIGURABLE: Set 'ignoreFiles' to skip specific files/patterns.
24
+ */
4
25
  const rule = {
5
26
  meta: {
6
27
  type: 'suggestion',
@@ -9,43 +30,120 @@ const rule = {
9
30
  recommended: true,
10
31
  url: 'https://github.com/Just-mpm/eslint-plugin-firebase-ai-logic#require-app-check-production',
11
32
  },
12
- schema: [],
33
+ schema: [
34
+ {
35
+ type: 'object',
36
+ properties: {
37
+ ignoreFiles: {
38
+ type: 'array',
39
+ items: { type: 'string' },
40
+ default: [],
41
+ description: 'File patterns to ignore (e.g., "*.test.ts", "test/**/*")',
42
+ },
43
+ },
44
+ additionalProperties: false,
45
+ },
46
+ ],
13
47
  messages: {
14
- missingAppCheck: 'Consider using App Check with reCAPTCHA to protect your AI endpoints from abuse. Initialize with initializeAppCheck() before using AI features.',
15
- appCheckSuggestion: "import { initializeAppCheck, ReCaptchaV3Provider } from 'firebase/app-check'; initializeAppCheck(app, { provider: new ReCaptchaV3Provider('SITE_KEY') });",
48
+ missingAppCheck: 'Consider using App Check to protect your AI endpoints from abuse. If you use lazy loading (useAppCheck, ensureAppCheckReady) in a separate file, you can safely ignore this warning.',
49
+ appCheckSuggestion: "import { initializeAppCheck, ReCaptchaEnterpriseProvider } from 'firebase/app-check'; initializeAppCheck(app, { provider: new ReCaptchaEnterpriseProvider('SITE_KEY') });",
16
50
  },
17
51
  },
18
52
  create(context) {
19
53
  let hasAppCheckImport = false;
20
54
  let hasAppCheckInit = false;
55
+ let hasAppCheckHelper = false;
21
56
  let hasAIInit = false;
22
57
  let aiInitNode = null;
58
+ let importsFromAIModule = false;
59
+ // Common App Check helper patterns used in lazy loading
60
+ const appCheckHelperPatterns = [
61
+ 'useAppCheck',
62
+ 'ensureAppCheckReady',
63
+ 'AppCheckProvider',
64
+ 'getAppCheckInstance',
65
+ 'isAppCheckReady',
66
+ 'initializeAppCheckLazy',
67
+ 'withAppCheck',
68
+ 'appCheckReady',
69
+ ];
70
+ // Common AI module patterns where App Check might be configured
71
+ const aiModulePatterns = [
72
+ '/ai',
73
+ '/firebase/ai',
74
+ '/lib/ai',
75
+ '/services/ai',
76
+ 'getAIInstance',
77
+ 'aiService',
78
+ ];
23
79
  return {
24
80
  // Track App Check imports
25
81
  ImportDeclaration(node) {
26
- if (node.source.value === 'firebase/app-check' &&
27
- node.specifiers.some((spec) => spec.type === 'ImportSpecifier' &&
28
- spec.imported.type === 'Identifier' &&
29
- spec.imported.name === 'initializeAppCheck')) {
82
+ const source = node.source.value;
83
+ if (typeof source !== 'string')
84
+ return;
85
+ // Direct firebase/app-check import
86
+ if (source === 'firebase/app-check') {
30
87
  hasAppCheckImport = true;
31
88
  }
89
+ // Check for imports from common App Check helper files/hooks
90
+ if (source.includes('useAppCheck') ||
91
+ source.includes('AppCheck') ||
92
+ source.includes('appCheck')) {
93
+ hasAppCheckHelper = true;
94
+ }
95
+ // Check if importing from a common AI module pattern
96
+ // These modules typically handle App Check internally
97
+ if (aiModulePatterns.some((pattern) => source.includes(pattern))) {
98
+ importsFromAIModule = true;
99
+ }
100
+ // Check imported specifiers for App Check helpers
101
+ for (const spec of node.specifiers) {
102
+ if (spec.type === 'ImportSpecifier' && spec.imported.type === 'Identifier') {
103
+ const importedName = spec.imported.name;
104
+ if (appCheckHelperPatterns.includes(importedName)) {
105
+ hasAppCheckHelper = true;
106
+ }
107
+ // Check if importing getAIInstance or similar from another module
108
+ if (importedName === 'getAIInstance' ||
109
+ importedName === 'getAI' ||
110
+ importedName === 'aiInstance') {
111
+ importsFromAIModule = true;
112
+ }
113
+ }
114
+ }
32
115
  },
33
- // Track initializeAppCheck calls
116
+ // Track function calls
34
117
  CallExpression(node) {
35
118
  const calleeName = (0, ast_helpers_js_1.getCalleeName)(node);
119
+ if (!calleeName)
120
+ return;
121
+ // Direct initializeAppCheck call
36
122
  if (calleeName === 'initializeAppCheck') {
37
123
  hasAppCheckInit = true;
38
124
  }
39
- // Track getAI calls
125
+ // App Check helper calls
126
+ if (appCheckHelperPatterns.includes(calleeName)) {
127
+ hasAppCheckHelper = true;
128
+ }
129
+ // Track getAI calls - but only if it's a DIRECT call, not imported wrapper
40
130
  if (calleeName === 'getAI') {
41
- hasAIInit = true;
42
- aiInitNode = node;
131
+ // Check if this is the actual firebase/ai getAI or a wrapper
132
+ // If we already import from an AI module, the App Check is likely handled there
133
+ if (!importsFromAIModule) {
134
+ hasAIInit = true;
135
+ aiInitNode = node;
136
+ }
43
137
  }
44
138
  },
45
139
  // Check at the end of the program
46
140
  'Program:exit'() {
47
- // Only warn if AI is being used but App Check is not configured
48
- if (hasAIInit && !hasAppCheckImport && !hasAppCheckInit && aiInitNode) {
141
+ // Only suggest if:
142
+ // 1. AI is being used directly (not via imported wrapper)
143
+ // 2. No App Check patterns found
144
+ // 3. Not importing from a module that likely handles App Check
145
+ const hasAnyAppCheckPattern = hasAppCheckImport || hasAppCheckInit || hasAppCheckHelper || importsFromAIModule;
146
+ if (hasAIInit && !hasAnyAppCheckPattern && aiInitNode) {
49
147
  context.report({
50
148
  node: aiInitNode,
51
149
  messageId: 'missingAppCheck',
@@ -1 +1 @@
1
- {"version":3,"file":"require-app-check-production.js","sourceRoot":"","sources":["../../src/rules/require-app-check-production.ts"],"names":[],"mappings":";;AACA,4DAAwD;AAExD,MAAM,IAAI,GAAoB;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,WAAW,EACT,iFAAiF;YACnF,WAAW,EAAE,IAAI;YACjB,GAAG,EAAE,0FAA0F;SAChG;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,eAAe,EACb,iJAAiJ;YACnJ,kBAAkB,EAChB,2JAA2J;SAC9J;KACF;IAED,MAAM,CAAC,OAAO;QACZ,IAAI,iBAAiB,GAAG,KAAK,CAAC;QAC9B,IAAI,eAAe,GAAG,KAAK,CAAC;QAC5B,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,IAAI,UAAU,GAAqB,IAAI,CAAC;QAExC,OAAO;YACL,0BAA0B;YAC1B,iBAAiB,CAAC,IAAI;gBACpB,IACE,IAAI,CAAC,MAAM,CAAC,KAAK,KAAK,oBAAoB;oBAC1C,IAAI,CAAC,UAAU,CAAC,IAAI,CAClB,CAAC,IAAI,EAAE,EAAE,CACP,IAAI,CAAC,IAAI,KAAK,iBAAiB;wBAC/B,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;wBACnC,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,oBAAoB,CAC9C,EACD,CAAC;oBACD,iBAAiB,GAAG,IAAI,CAAC;gBAC3B,CAAC;YACH,CAAC;YAED,iCAAiC;YACjC,cAAc,CAAC,IAAI;gBACjB,MAAM,UAAU,GAAG,IAAA,8BAAa,EAAC,IAAI,CAAC,CAAC;gBAEvC,IAAI,UAAU,KAAK,oBAAoB,EAAE,CAAC;oBACxC,eAAe,GAAG,IAAI,CAAC;gBACzB,CAAC;gBAED,oBAAoB;gBACpB,IAAI,UAAU,KAAK,OAAO,EAAE,CAAC;oBAC3B,SAAS,GAAG,IAAI,CAAC;oBACjB,UAAU,GAAG,IAAiB,CAAC;gBACjC,CAAC;YACH,CAAC;YAED,kCAAkC;YAClC,cAAc;gBACZ,gEAAgE;gBAChE,IAAI,SAAS,IAAI,CAAC,iBAAiB,IAAI,CAAC,eAAe,IAAI,UAAU,EAAE,CAAC;oBACtE,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI,EAAE,UAAU;wBAChB,SAAS,EAAE,iBAAiB;qBAC7B,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,kBAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"require-app-check-production.js","sourceRoot":"","sources":["../../src/rules/require-app-check-production.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,21 @@
1
1
  import type { Rule } from 'eslint';
2
+ /**
3
+ * require-backend
4
+ *
5
+ * IMPORTANT: getAI(app) without a second argument is VALID.
6
+ * Firebase AI Logic uses GoogleAIBackend by default when no backend is specified.
7
+ *
8
+ * This rule only reports when:
9
+ * - A second argument (config object) exists BUT doesn't have 'backend' property
10
+ *
11
+ * Valid usage:
12
+ * - getAI(app) - Uses GoogleAIBackend by default ✅
13
+ * - getAI(app, { backend: new GoogleAIBackend() }) ✅
14
+ * - getAI(app, { backend: new VertexAIBackend() }) ✅
15
+ *
16
+ * Invalid usage:
17
+ * - getAI(app, { someOtherConfig: true }) - Has config but no backend ❌
18
+ */
2
19
  declare const rule: Rule.RuleModule;
3
20
  export default rule;
4
21
  //# sourceMappingURL=require-backend.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"require-backend.d.ts","sourceRoot":"","sources":["../../src/rules/require-backend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAOnC,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,UA2GhB,CAAC;AAEF,eAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"require-backend.d.ts","sourceRoot":"","sources":["../../src/rules/require-backend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAOnC;;;;;;;;;;;;;;;;GAgBG;AACH,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,UAyEhB,CAAC;AAEF,eAAe,IAAI,CAAC"}