eslint-config-agent 1.0.21 → 1.0.23

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/CHANGELOG.md CHANGED
@@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file. See [Conven
4
4
 
5
5
 
6
6
 
7
+ ## [1.0.23](https://github.com/tupe12334/eslint-config/compare/v1.0.22...v1.0.23) (2025-09-05)
8
+
9
+ ### Features
10
+
11
+ * add custom no-env-access rule with tests and update test runner ([b4f4fc5](https://github.com/tupe12334/eslint-config/commit/b4f4fc5fdecfdc8fa6f1524403d2f6df8afb3a40))
12
+
13
+ ## [1.0.22](https://github.com/tupe12334/eslint-config/compare/v1.0.21...v1.0.22) (2025-09-04)
14
+
15
+ ### Features
16
+
17
+ * add max-lines and max-lines-per-function rules with configurations and tests ([218f29c](https://github.com/tupe12334/eslint-config/commit/218f29ca497ca1b49e027f3e33f87cf836e7ff02))
18
+
19
+ ### Bug Fixes
20
+
21
+ * resolve linting issues for release ([3c812cd](https://github.com/tupe12334/eslint-config/commit/3c812cd223f169360cb0d1520e401a17a6a9b960))
22
+
7
23
  ## [1.0.21](https://github.com/tupe12334/eslint-config/compare/v1.0.19...v1.0.21) (2025-09-04)
8
24
 
9
25
  ### Bug Fixes
package/index.js CHANGED
@@ -1,4 +1,3 @@
1
- import { FlatCompat } from "@eslint/eslintrc";
2
1
  import js from "@eslint/js";
3
2
  import tsPlugin from "@typescript-eslint/eslint-plugin";
4
3
  import tsParser from "@typescript-eslint/parser";
@@ -7,6 +6,9 @@ import reactPlugin from "eslint-plugin-react";
7
6
  import importPlugin from "eslint-plugin-import";
8
7
  import globals from "globals";
9
8
  import noTrailingSpacesConfig from "./rules/no-trailing-spaces/index.js";
9
+ import { maxFunctionLinesWarning, maxFunctionLinesError } from "./rules/max-function-lines/index.js";
10
+ import { maxFileLinesWarning, maxFileLinesError } from "./rules/max-file-lines/index.js";
11
+ import noEnvAccessRule from "./rules/no-env-access/index.js";
10
12
 
11
13
  // Conditionally import preact plugin if available
12
14
  let preactPlugin = null;
@@ -16,9 +18,6 @@ try {
16
18
  // eslint-plugin-preact is not available
17
19
  }
18
20
 
19
- const compat = new FlatCompat({
20
- recommendedConfig: js.configs.recommended,
21
- });
22
21
 
23
22
  // Shared rules for both JS and TS files
24
23
  const sharedRules = {
@@ -41,10 +40,8 @@ const sharedRules = {
41
40
  "import/first": "off",
42
41
  "import/prefer-default-export": "off",
43
42
  "react/react-in-jsx-scope": "off",
44
- "max-lines-per-function": [
45
- "warn",
46
- { max: 100, skipBlankLines: true, skipComments: true },
47
- ],
43
+ "max-lines-per-function": maxFunctionLinesWarning,
44
+ "max-lines": maxFileLinesWarning,
48
45
  "react/jsx-filename-extension": ["error", { extensions: [".tsx", ".jsx"] }],
49
46
  semi: "off",
50
47
  "react/function-component-definition": "off",
@@ -64,6 +61,7 @@ const sharedRules = {
64
61
  "react/jsx-no-useless-fragment": "off",
65
62
  "import/group-exports": "off",
66
63
  "import/no-default-export": "off",
64
+ "custom-rules/no-env-access": "error",
67
65
  };
68
66
 
69
67
  // Shared no-restricted-syntax rules for both JS and TS
@@ -73,8 +71,10 @@ const sharedRestrictedSyntax = [
73
71
  message: "Optional chaining is not allowed.",
74
72
  },
75
73
  {
76
- selector: "MemberExpression[object.type='MemberExpression'][object.object.name='process'][object.property.name='env']",
77
- message: "Direct access to process.env properties is not allowed. Use a configuration object or environment validation instead.",
74
+ selector:
75
+ "MemberExpression[object.type='MemberExpression'][object.object.name='process'][object.property.name='env']",
76
+ message:
77
+ "Direct access to process.env properties is not allowed. Use a configuration object or environment validation instead.",
78
78
  },
79
79
  {
80
80
  selector: "CallExpression[optional=true]",
@@ -255,13 +255,22 @@ const tsOnlyRestrictedSyntax = [
255
255
  ];
256
256
 
257
257
  const config = [
258
+ // Global plugin definitions
259
+ {
260
+ plugins: {
261
+ "custom-rules": {
262
+ rules: {
263
+ "no-env-access": noEnvAccessRule,
264
+ }
265
+ },
266
+ },
267
+ },
258
268
  reactHooks.configs["recommended-latest"],
259
269
  {
260
270
  ignores: ["packages/auth-service-sdk/**"],
261
271
  },
262
272
  js.configs.recommended,
263
273
 
264
-
265
274
  // TypeScript and TSX files
266
275
  {
267
276
  files: ["**/*.ts", "**/*.tsx"],
@@ -500,10 +509,7 @@ const config = [
500
509
  },
501
510
  rules: {
502
511
  ...sharedRules,
503
- "no-restricted-syntax": [
504
- "error",
505
- ...sharedRestrictedSyntax,
506
- ],
512
+ "no-restricted-syntax": ["error", ...sharedRestrictedSyntax],
507
513
  },
508
514
  },
509
515
 
@@ -769,8 +775,10 @@ const config = [
769
775
  "error",
770
776
  // Process.env rule (applies to all file types)
771
777
  {
772
- selector: "MemberExpression[object.type='MemberExpression'][object.object.name='process'][object.property.name='env']",
773
- message: "Direct access to process.env properties is not allowed. Use a configuration object or environment validation instead.",
778
+ selector:
779
+ "MemberExpression[object.type='MemberExpression'][object.object.name='process'][object.property.name='env']",
780
+ message:
781
+ "Direct access to process.env properties is not allowed. Use a configuration object or environment validation instead.",
774
782
  },
775
783
  // Switch case rules as errors
776
784
  {
@@ -853,6 +861,30 @@ const config = [
853
861
  },
854
862
  },
855
863
 
864
+ // Function and file length rules - strict error thresholds
865
+ {
866
+ files: ["**/*.{ts,tsx,js,jsx}"],
867
+ rules: {
868
+ // Function length: error at 70+ lines
869
+ "max-lines-per-function": maxFunctionLinesError,
870
+ // File length: error at 100+ lines
871
+ "max-lines": maxFileLinesError,
872
+ },
873
+ },
874
+
875
+ // Disable file length rules for configuration and spec files
876
+ {
877
+ files: [
878
+ "index.js", // Main configuration file
879
+ "**/rules/**/*.spec.js", // Spec files in rules directory
880
+ "**/scripts/**/*.js", // Script files
881
+ ],
882
+ rules: {
883
+ "max-lines": "off",
884
+ "max-lines-per-function": "off",
885
+ },
886
+ },
887
+
856
888
  // Allow default exports in configuration files (must be last to override)
857
889
  {
858
890
  files: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-config-agent",
3
- "version": "1.0.21",
3
+ "version": "1.0.23",
4
4
  "description": "ESLint configuration package with TypeScript support",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -29,7 +29,6 @@
29
29
  "test:performance": "eslint test/performance-test.tsx",
30
30
  "test:comprehensive": "node scripts/test-runner.js",
31
31
  "test:ci": "eslint . --ignore-pattern 'test/**' --ignore-pattern 'scripts/**' --max-warnings 0",
32
- "test:rules": "node rules/no-trailing-spaces/no-trailing-spaces.spec.js",
33
32
  "validate": "node scripts/validate-config.js",
34
33
  "release": "dotenv -e .env -- release-it",
35
34
  "release:patch": "dotenv -e .env -- release-it patch",
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Rule configuration for max-lines
3
+ *
4
+ * This rule enforces a maximum number of lines per file to encourage
5
+ * smaller, more maintainable files and better separation of concerns.
6
+ *
7
+ * Warnings at >70 lines, errors at >100 lines
8
+ *
9
+ * @see https://eslint.org/docs/latest/rules/max-lines
10
+ */
11
+
12
+ // Warning configuration (70 lines)
13
+ export const warningRule = "warn";
14
+ export const warningOptions = {
15
+ max: 70,
16
+ skipBlankLines: true,
17
+ skipComments: true,
18
+ };
19
+
20
+ // Error configuration (100 lines)
21
+ export const errorRule = "error";
22
+ export const errorOptions = {
23
+ max: 100,
24
+ skipBlankLines: true,
25
+ skipComments: true,
26
+ };
27
+
28
+ /**
29
+ * Export the warning rule configuration (applied first)
30
+ * Can be used in ESLint config as:
31
+ * "max-lines": maxFileLinesWarning
32
+ */
33
+ export const maxFileLinesWarning = [warningRule, warningOptions];
34
+
35
+ /**
36
+ * Export the error rule configuration (applied later to override)
37
+ * Can be used in ESLint config as:
38
+ * "max-lines": maxFileLinesError
39
+ */
40
+ export const maxFileLinesError = [errorRule, errorOptions];
41
+
42
+ // Default export is the warning configuration
43
+ export default maxFileLinesWarning;
@@ -0,0 +1,75 @@
1
+ /* global process */
2
+ import {
3
+ warningRule,
4
+ warningOptions,
5
+ errorRule,
6
+ errorOptions,
7
+ maxFileLinesWarning,
8
+ maxFileLinesError
9
+ } from "./index.js";
10
+
11
+ console.log("Testing max-file-lines rule configuration exports...");
12
+
13
+ // Test warning configuration
14
+ console.log("\n📋 Warning Configuration:");
15
+ console.log("Rule level:", warningRule);
16
+ console.log("Options:", warningOptions);
17
+ console.log("Complete config:", maxFileLinesWarning);
18
+
19
+ // Validate warning configuration
20
+ if (warningRule === "warn" &&
21
+ warningOptions.max === 70 &&
22
+ warningOptions.skipBlankLines === true &&
23
+ warningOptions.skipComments === true) {
24
+ console.log("✅ Warning configuration is correct");
25
+ } else {
26
+ console.log("❌ Warning configuration is incorrect");
27
+ process.exit(1);
28
+ }
29
+
30
+ // Test error configuration
31
+ console.log("\n📋 Error Configuration:");
32
+ console.log("Rule level:", errorRule);
33
+ console.log("Options:", errorOptions);
34
+ console.log("Complete config:", maxFileLinesError);
35
+
36
+ // Validate error configuration
37
+ if (errorRule === "error" &&
38
+ errorOptions.max === 100 &&
39
+ errorOptions.skipBlankLines === true &&
40
+ errorOptions.skipComments === true) {
41
+ console.log("✅ Error configuration is correct");
42
+ } else {
43
+ console.log("❌ Error configuration is incorrect");
44
+ process.exit(1);
45
+ }
46
+
47
+ console.log("\n✅ All max-file-lines configuration tests passed!");
48
+
49
+ // Test that the configurations are properly formatted for ESLint
50
+ console.log("\n📋 ESLint Configuration Format:");
51
+ console.log("Warning format:", JSON.stringify(maxFileLinesWarning));
52
+ console.log("Error format:", JSON.stringify(maxFileLinesError));
53
+
54
+ // Validate ESLint format
55
+ if (Array.isArray(maxFileLinesWarning) &&
56
+ maxFileLinesWarning.length === 2 &&
57
+ maxFileLinesWarning[0] === "warn" &&
58
+ typeof maxFileLinesWarning[1] === "object") {
59
+ console.log("✅ Warning ESLint format is correct");
60
+ } else {
61
+ console.log("❌ Warning ESLint format is incorrect");
62
+ process.exit(1);
63
+ }
64
+
65
+ if (Array.isArray(maxFileLinesError) &&
66
+ maxFileLinesError.length === 2 &&
67
+ maxFileLinesError[0] === "error" &&
68
+ typeof maxFileLinesError[1] === "object") {
69
+ console.log("✅ Error ESLint format is correct");
70
+ } else {
71
+ console.log("❌ Error ESLint format is incorrect");
72
+ process.exit(1);
73
+ }
74
+
75
+ console.log("\n🎉 All tests completed successfully!");
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Rule configuration for max-lines-per-function
3
+ *
4
+ * This rule enforces a maximum number of lines per function to encourage
5
+ * smaller, more maintainable functions.
6
+ *
7
+ * Warnings at >50 lines, errors at >70 lines
8
+ *
9
+ * @see https://eslint.org/docs/latest/rules/max-lines-per-function
10
+ */
11
+
12
+ // Warning configuration (50 lines)
13
+ export const warningRule = "warn";
14
+ export const warningOptions = {
15
+ max: 50,
16
+ skipBlankLines: true,
17
+ skipComments: true,
18
+ };
19
+
20
+ // Error configuration (70 lines)
21
+ export const errorRule = "error";
22
+ export const errorOptions = {
23
+ max: 70,
24
+ skipBlankLines: true,
25
+ skipComments: true,
26
+ };
27
+
28
+ /**
29
+ * Export the warning rule configuration (applied first)
30
+ * Can be used in ESLint config as:
31
+ * "max-lines-per-function": maxFunctionLinesWarning
32
+ */
33
+ export const maxFunctionLinesWarning = [warningRule, warningOptions];
34
+
35
+ /**
36
+ * Export the error rule configuration (applied later to override)
37
+ * Can be used in ESLint config as:
38
+ * "max-lines-per-function": maxFunctionLinesError
39
+ */
40
+ export const maxFunctionLinesError = [errorRule, errorOptions];
41
+
42
+ // Default export is the warning configuration
43
+ export default maxFunctionLinesWarning;
@@ -0,0 +1,75 @@
1
+ /* global process */
2
+ import {
3
+ warningRule,
4
+ warningOptions,
5
+ errorRule,
6
+ errorOptions,
7
+ maxFunctionLinesWarning,
8
+ maxFunctionLinesError
9
+ } from "./index.js";
10
+
11
+ console.log("Testing max-function-lines rule configuration exports...");
12
+
13
+ // Test warning configuration
14
+ console.log("\n📋 Warning Configuration:");
15
+ console.log("Rule level:", warningRule);
16
+ console.log("Options:", warningOptions);
17
+ console.log("Complete config:", maxFunctionLinesWarning);
18
+
19
+ // Validate warning configuration
20
+ if (warningRule === "warn" &&
21
+ warningOptions.max === 50 &&
22
+ warningOptions.skipBlankLines === true &&
23
+ warningOptions.skipComments === true) {
24
+ console.log("✅ Warning configuration is correct");
25
+ } else {
26
+ console.log("❌ Warning configuration is incorrect");
27
+ process.exit(1);
28
+ }
29
+
30
+ // Test error configuration
31
+ console.log("\n📋 Error Configuration:");
32
+ console.log("Rule level:", errorRule);
33
+ console.log("Options:", errorOptions);
34
+ console.log("Complete config:", maxFunctionLinesError);
35
+
36
+ // Validate error configuration
37
+ if (errorRule === "error" &&
38
+ errorOptions.max === 70 &&
39
+ errorOptions.skipBlankLines === true &&
40
+ errorOptions.skipComments === true) {
41
+ console.log("✅ Error configuration is correct");
42
+ } else {
43
+ console.log("❌ Error configuration is incorrect");
44
+ process.exit(1);
45
+ }
46
+
47
+ console.log("\n✅ All max-function-lines configuration tests passed!");
48
+
49
+ // Test that the configurations are properly formatted for ESLint
50
+ console.log("\n📋 ESLint Configuration Format:");
51
+ console.log("Warning format:", JSON.stringify(maxFunctionLinesWarning));
52
+ console.log("Error format:", JSON.stringify(maxFunctionLinesError));
53
+
54
+ // Validate ESLint format
55
+ if (Array.isArray(maxFunctionLinesWarning) &&
56
+ maxFunctionLinesWarning.length === 2 &&
57
+ maxFunctionLinesWarning[0] === "warn" &&
58
+ typeof maxFunctionLinesWarning[1] === "object") {
59
+ console.log("✅ Warning ESLint format is correct");
60
+ } else {
61
+ console.log("❌ Warning ESLint format is incorrect");
62
+ process.exit(1);
63
+ }
64
+
65
+ if (Array.isArray(maxFunctionLinesError) &&
66
+ maxFunctionLinesError.length === 2 &&
67
+ maxFunctionLinesError[0] === "error" &&
68
+ typeof maxFunctionLinesError[1] === "object") {
69
+ console.log("✅ Error ESLint format is correct");
70
+ } else {
71
+ console.log("❌ Error ESLint format is incorrect");
72
+ process.exit(1);
73
+ }
74
+
75
+ console.log("\n🎉 All tests completed successfully!");
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Custom ESLint rule: no-env-access
3
+ *
4
+ * Prevents direct access to properties on variables named 'env'.
5
+ * This encourages the use of configuration objects or environment validation
6
+ * instead of directly accessing environment variables.
7
+ *
8
+ * @example
9
+ * // ❌ Bad - direct env access
10
+ * const nodeEnv = env.NODE_ENV;
11
+ * const port = env.PORT;
12
+ *
13
+ * // ✅ Good - configuration object
14
+ * const config = getEnvConfig();
15
+ * const nodeEnv = config.nodeEnv;
16
+ *
17
+ * // ✅ Good - not property access
18
+ * const env = 'production';
19
+ * const envConfig = { env: 'development' };
20
+ */
21
+
22
+ const rule = {
23
+ meta: {
24
+ type: "problem",
25
+ docs: {
26
+ description: "Disallow direct access to properties on 'env' variables",
27
+ category: "Best Practices",
28
+ recommended: true,
29
+ },
30
+ messages: {
31
+ noEnvAccess:
32
+ "Direct access to env properties is not allowed. Use a configuration object or environment validation instead.",
33
+ },
34
+ schema: [], // No options
35
+ },
36
+
37
+ create(context) {
38
+ return {
39
+ MemberExpression(node) {
40
+ // Check if we're accessing a property on a variable named 'env'
41
+ if (
42
+ node.object &&
43
+ node.object.type === "Identifier" &&
44
+ node.object.name === "env" &&
45
+ node.computed === false // Only flag dot notation, not bracket notation
46
+ ) {
47
+ // Don't flag if this member expression itself is being called as a function
48
+ // e.g., env.call(), env.apply(), but do flag env.NODE_ENV.toLowerCase()
49
+ const isDirectMethodCall =
50
+ node.parent &&
51
+ node.parent.type === "CallExpression" &&
52
+ node.parent.callee === node;
53
+
54
+ if (!isDirectMethodCall) {
55
+ context.report({
56
+ node,
57
+ messageId: "noEnvAccess",
58
+ });
59
+ }
60
+ }
61
+ },
62
+ };
63
+ },
64
+ };
65
+
66
+ export default rule;
@@ -0,0 +1,196 @@
1
+ import { RuleTester } from "eslint";
2
+ import noEnvAccessRule from "./index.js";
3
+
4
+ // Create RuleTester instance
5
+ const ruleTester = new RuleTester({
6
+ languageOptions: {
7
+ ecmaVersion: "latest",
8
+ sourceType: "module",
9
+ },
10
+ });
11
+
12
+ // Test the no-env-access custom rule
13
+ ruleTester.run("no-env-access", noEnvAccessRule, {
14
+ valid: [
15
+ // Valid: not accessing properties on 'env'
16
+ "const foo = 'bar';",
17
+ "const config = getEnvConfig();",
18
+ "const nodeEnv = config.NODE_ENV;",
19
+
20
+ // Valid: 'env' as a value, not property access
21
+ "const env = 'production';",
22
+ "const environment = env;",
23
+ "const settings = { env: 'development' };",
24
+ "const mode = settings.env;",
25
+
26
+ // Valid: different variable names
27
+ "const environment = { NODE_ENV: 'test' };",
28
+ "const nodeEnv = environment.NODE_ENV;",
29
+ "const config = { NODE_ENV: 'prod' };",
30
+ "const env_config = { PORT: 3000 };",
31
+ "const port = env_config.PORT;",
32
+
33
+ // Valid: function calls
34
+ "env();",
35
+ "env.call();",
36
+ "env.apply();",
37
+ "getEnv().NODE_ENV;",
38
+
39
+ // Valid: bracket notation (not enforced by this rule)
40
+ "const nodeEnv = env['NODE_ENV'];",
41
+ "const port = env['PORT'];",
42
+
43
+ // Valid: other operations
44
+ "typeof env;",
45
+ "env instanceof Object;",
46
+ "env || 'default';",
47
+ "env ? 'prod' : 'dev';",
48
+
49
+ // Valid: in function parameters, destructuring, etc.
50
+ "function test(env) { return env; }",
51
+ "const { env } = config;",
52
+ "const [env] = environments;",
53
+
54
+ // Valid: class members named env
55
+ "class Config { env = 'prod'; }",
56
+ "const config = new Config(); config.env;",
57
+
58
+ // Valid: accessing properties on process.env (handled by different rule)
59
+ "const nodeEnv = process.env.NODE_ENV;",
60
+ "const port = process.env.PORT;",
61
+ ],
62
+
63
+ invalid: [
64
+ // Invalid: direct property access on 'env' variable
65
+ {
66
+ code: "const nodeEnv = env.NODE_ENV;",
67
+ errors: [
68
+ {
69
+ messageId: "noEnvAccess",
70
+ type: "MemberExpression",
71
+ },
72
+ ],
73
+ },
74
+ {
75
+ code: "const port = env.PORT;",
76
+ errors: [
77
+ {
78
+ messageId: "noEnvAccess",
79
+ type: "MemberExpression",
80
+ },
81
+ ],
82
+ },
83
+ {
84
+ code: "const apiUrl = env.API_URL;",
85
+ errors: [
86
+ {
87
+ messageId: "noEnvAccess",
88
+ type: "MemberExpression",
89
+ },
90
+ ],
91
+ },
92
+ {
93
+ code: "const dbUrl = env.DATABASE_URL;",
94
+ errors: [
95
+ {
96
+ messageId: "noEnvAccess",
97
+ type: "MemberExpression",
98
+ },
99
+ ],
100
+ },
101
+
102
+ // Invalid: multiple accesses in same code
103
+ {
104
+ code: `
105
+ const nodeEnv = env.NODE_ENV;
106
+ const port = env.PORT;
107
+ const dbUrl = env.DATABASE_URL;
108
+ `,
109
+ errors: [
110
+ { messageId: "noEnvAccess", type: "MemberExpression" },
111
+ { messageId: "noEnvAccess", type: "MemberExpression" },
112
+ { messageId: "noEnvAccess", type: "MemberExpression" },
113
+ ],
114
+ },
115
+
116
+ // Invalid: in various contexts
117
+ {
118
+ code: "console.log(env.NODE_ENV);",
119
+ errors: [{ messageId: "noEnvAccess", type: "MemberExpression" }],
120
+ },
121
+ {
122
+ code: "if (env.NODE_ENV === 'production') { }",
123
+ errors: [{ messageId: "noEnvAccess", type: "MemberExpression" }],
124
+ },
125
+ {
126
+ code: "const config = { nodeEnv: env.NODE_ENV };",
127
+ errors: [{ messageId: "noEnvAccess", type: "MemberExpression" }],
128
+ },
129
+ {
130
+ code: "function test() { return env.NODE_ENV || 'development'; }",
131
+ errors: [{ messageId: "noEnvAccess", type: "MemberExpression" }],
132
+ },
133
+ {
134
+ code: "const port = parseInt(env.PORT, 10);",
135
+ errors: [{ messageId: "noEnvAccess", type: "MemberExpression" }],
136
+ },
137
+
138
+ // Invalid: function calls on accessed properties
139
+ {
140
+ code: "const lower = env.NODE_ENV.toLowerCase();",
141
+ errors: [{ messageId: "noEnvAccess", type: "MemberExpression" }],
142
+ },
143
+ {
144
+ code: "const trimmed = env.API_URL.trim();",
145
+ errors: [{ messageId: "noEnvAccess", type: "MemberExpression" }],
146
+ },
147
+
148
+ // Invalid: in function parameters and returns
149
+ {
150
+ code: "function getNodeEnv() { return env.NODE_ENV; }",
151
+ errors: [{ messageId: "noEnvAccess", type: "MemberExpression" }],
152
+ },
153
+ {
154
+ code: "const fn = () => env.NODE_ENV;",
155
+ errors: [{ messageId: "noEnvAccess", type: "MemberExpression" }],
156
+ },
157
+ {
158
+ code: "someFunction(env.NODE_ENV, env.PORT);",
159
+ errors: [
160
+ { messageId: "noEnvAccess", type: "MemberExpression" },
161
+ { messageId: "noEnvAccess", type: "MemberExpression" },
162
+ ],
163
+ },
164
+
165
+ // Invalid: in object/array literals
166
+ {
167
+ code: "const config = [env.NODE_ENV, env.PORT];",
168
+ errors: [
169
+ { messageId: "noEnvAccess", type: "MemberExpression" },
170
+ { messageId: "noEnvAccess", type: "MemberExpression" },
171
+ ],
172
+ },
173
+
174
+ // Invalid: in template literals
175
+ {
176
+ code: "const message = `Environment: ${env.NODE_ENV}`;",
177
+ errors: [{ messageId: "noEnvAccess", type: "MemberExpression" }],
178
+ },
179
+
180
+ // Invalid: in assignments and operations
181
+ {
182
+ code: "let nodeEnv; nodeEnv = env.NODE_ENV;",
183
+ errors: [{ messageId: "noEnvAccess", type: "MemberExpression" }],
184
+ },
185
+ {
186
+ code: "const isDev = env.NODE_ENV === 'development';",
187
+ errors: [{ messageId: "noEnvAccess", type: "MemberExpression" }],
188
+ },
189
+ ],
190
+ });
191
+
192
+ console.log("✅ All no-env-access rule tests passed!");
193
+ console.log(" Rule prevents direct access to properties on 'env' variables");
194
+ console.log(
195
+ " Encourages use of configuration objects for better environment handling"
196
+ );