eslint-plugin-operability 3.0.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/README.md ADDED
@@ -0,0 +1,141 @@
1
+ <p align="center">
2
+ <a href="https://eslint.interlace.tools" target="blank"><img src="https://eslint.interlace.tools/eslint-interlace-logo-light.svg" alt="ESLint Interlace Logo" width="120" /></a>
3
+ </p>
4
+
5
+ <p align="center">
6
+ Production readiness rules for debug code, logging, and operational hygiene.
7
+ </p>
8
+
9
+ <p align="center">
10
+ <a href="https://www.npmjs.com/package/eslint-plugin-operability" target="_blank"><img src="https://img.shields.io/npm/v/eslint-plugin-operability.svg" alt="NPM Version" /></a>
11
+ <a href="https://www.npmjs.com/package/eslint-plugin-operability" target="_blank"><img src="https://img.shields.io/npm/dm/eslint-plugin-operability.svg" alt="NPM Downloads" /></a>
12
+ <a href="https://opensource.org/licenses/MIT" target="_blank"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="Package License" /></a>
13
+ </p>
14
+
15
+ ## Description
16
+
17
+ This plugin enforces production-ready code practices by detecting debug statements, verbose error messages, and other patterns that should not ship to production. It helps teams maintain operational hygiene and prevent accidental exposure of sensitive information.
18
+
19
+ ## Philosophy
20
+
21
+ **Interlace** fosters **strength through integration**. Code that works in development isn't always production-ready. These rules catch common operability issues before they reach production, protecting both your users and your infrastructure.
22
+
23
+ ## Getting Started
24
+
25
+ - To check out the [guide](https://eslint.interlace.tools/docs/operability), visit [eslint.interlace.tools](https://eslint.interlace.tools). 📚
26
+
27
+ ```bash
28
+ npm install eslint-plugin-operability --save-dev
29
+ ```
30
+
31
+ ## ⚙️ Configuration Presets
32
+
33
+ | Preset | Description |
34
+ | :------------ | :---------------------------------------------- |
35
+ | `recommended` | Balanced operability checks for production code |
36
+
37
+ ---
38
+
39
+ ## 🏢 Usage Example
40
+
41
+ ```js
42
+ // eslint.config.js
43
+ import operability from 'eslint-plugin-operability';
44
+
45
+ export default [
46
+ operability.configs.recommended,
47
+
48
+ // Be extra strict in production code
49
+ {
50
+ files: ['src/**/*.ts'],
51
+ ignores: ['**/*.test.ts', '**/*.spec.ts'],
52
+ rules: {
53
+ '@interlace/operability/operability/no-console-log': 'error',
54
+ },
55
+ },
56
+ ];
57
+ ```
58
+
59
+ ---
60
+
61
+ ## Rules
62
+
63
+ | Rule | Description | 💼 | ⚠️ |
64
+ | :------------------------------------------------------------------------- | :-------------------------------------------- | :-: | :-: |
65
+ | [no-console-log](./docs/rules/no-console-log.md) | Disallow `console.log` in production code | 💼 | ⚠️ |
66
+ | [no-process-exit](./docs/rules/no-process-exit.md) | Disallow `process.exit()` in library code | | |
67
+ | [no-debug-code-in-production](./docs/rules/no-debug-code-in-production.md) | Detect debug statements and debugger keywords | 💼 | |
68
+ | [no-verbose-error-messages](./docs/rules/no-verbose-error-messages.md) | Prevent overly detailed error messages | 💼 | ⚠️ |
69
+ | [require-code-minification](./docs/rules/require-code-minification.md) | Detect patterns that prevent minification | | |
70
+ | [require-data-minimization](./docs/rules/require-data-minimization.md) | Detect excessive data exposure in responses | | |
71
+
72
+ **Legend**: 💼 Recommended | ⚠️ Warns (not error)
73
+
74
+ ---
75
+
76
+ ## Why These Rules?
77
+
78
+ ### `no-console-log`
79
+
80
+ `console.log` statements are for debugging and shouldn't ship to production.
81
+
82
+ ```ts
83
+ // ❌ Bad: Debug logging in production
84
+ function processPayment(card: Card) {
85
+ console.log('Processing payment:', card); // Exposes sensitive data!
86
+ return paymentService.charge(card);
87
+ }
88
+
89
+ // ✅ Good: Use proper logging
90
+ function processPayment(card: Card) {
91
+ logger.info('Processing payment', { cardLast4: card.last4 });
92
+ return paymentService.charge(card);
93
+ }
94
+ ```
95
+
96
+ ### `no-debug-code-in-production`
97
+
98
+ Catches `debugger` statements and debug-only code paths.
99
+
100
+ ```ts
101
+ // ❌ Bad: Debugger statement left in code
102
+ function calculateTotal(items: Item[]) {
103
+ debugger; // Will pause execution in production!
104
+ return items.reduce((sum, item) => sum + item.price, 0);
105
+ }
106
+
107
+ // ✅ Good: No debug statements
108
+ function calculateTotal(items: Item[]) {
109
+ return items.reduce((sum, item) => sum + item.price, 0);
110
+ }
111
+ ```
112
+
113
+ ### `no-verbose-error-messages`
114
+
115
+ Prevents detailed error messages that could expose system internals.
116
+
117
+ ```ts
118
+ // ❌ Bad: Verbose error exposes internals (CWE-209)
119
+ throw new Error(
120
+ `Database connection failed at ${host}:${port} with user ${dbUser}`,
121
+ );
122
+
123
+ // ✅ Good: Generic error with internal logging
124
+ logger.error('Database connection failed', { host, port, user: dbUser });
125
+ throw new Error('Service temporarily unavailable');
126
+ ```
127
+
128
+ ---
129
+
130
+ ## 🔗 Related ESLint Plugins
131
+
132
+ Part of the **Interlace ESLint Ecosystem** — AI-native quality plugins with LLM-optimized error messages:
133
+
134
+ | Plugin | Description |
135
+ | :----------------------------------------------------------------------------------------- | :------------------------------ |
136
+ | [`eslint-plugin-reliability`](https://www.npmjs.com/package/eslint-plugin-reliability) | Error handling & null safety |
137
+ | [`eslint-plugin-secure-coding`](https://www.npmjs.com/package/eslint-plugin-secure-coding) | Security best practices & OWASP |
138
+
139
+ ## 📄 License
140
+
141
+ MIT © [Ofri Peretz](https://github.com/ofri-peretz)
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "eslint-plugin-operability",
3
+ "version": "3.0.0",
4
+ "description": "ESLint rules for production behavior, resource hygiene, and log quality.",
5
+ "type": "commonjs",
6
+ "main": "./src/index.js",
7
+ "types": "./src/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./src/index.d.ts",
11
+ "default": "./src/index.js"
12
+ }
13
+ },
14
+ "author": "Ofri Peretz <ofriperetzdev@gmail.com>",
15
+ "license": "MIT",
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "files": [
20
+ "src/",
21
+ "dist/",
22
+ "README.md",
23
+ "LICENSE",
24
+ "CHANGELOG.md"
25
+ ],
26
+ "keywords": [
27
+ "eslint",
28
+ "eslint-plugin",
29
+ "interlace-quality",
30
+ "operability",
31
+ "observability",
32
+ "production-ready",
33
+ "llm-optimized"
34
+ ],
35
+ "engines": {
36
+ "node": ">=18.0.0"
37
+ },
38
+ "dependencies": {
39
+ "tslib": "^2.3.0",
40
+ "@interlace/eslint-devkit": "*"
41
+ },
42
+ "devDependencies": {
43
+ "@typescript-eslint/parser": "^8.46.2",
44
+ "@typescript-eslint/rule-tester": "^8.46.2"
45
+ },
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "https://github.com/ofri-peretz/eslint",
49
+ "directory": "packages/eslint-plugin-operability"
50
+ },
51
+ "homepage": "https://github.com/ofri-peretz/eslint/tree/main/packages/eslint-plugin-operability#readme",
52
+ "bugs": {
53
+ "url": "https://github.com/ofri-peretz/eslint/issues"
54
+ }
55
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Copyright (c) 2025 Ofri Peretz
3
+ * Licensed under the MIT License. Use of this source code is governed by the
4
+ * MIT license that can be found in the LICENSE file.
5
+ */
6
+ import type { TSESLint } from '@interlace/eslint-devkit';
7
+ export declare const rules: {
8
+ 'no-console-log': TSESLint.RuleModule<"consoleLogFound" | "strategyRemove" | "strategyConvert" | "strategyComment" | "strategyWarn", [(import("./rules/operability/no-console-log").Options | undefined)?], unknown, TSESLint.RuleListener> & {
9
+ name: string;
10
+ };
11
+ 'no-process-exit': TSESLint.RuleModule<"noProcessExit", [(import("./rules/operability/no-process-exit").Options | undefined)?], unknown, TSESLint.RuleListener> & {
12
+ name: string;
13
+ };
14
+ 'no-debug-code-in-production': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/no-debug-code-in-production").Options | undefined)?], unknown, TSESLint.RuleListener> & {
15
+ name: string;
16
+ };
17
+ 'no-verbose-error-messages': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/no-verbose-error-messages").Options | undefined)?], unknown, TSESLint.RuleListener> & {
18
+ name: string;
19
+ };
20
+ 'require-code-minification': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/require-code-minification").Options | undefined)?], unknown, TSESLint.RuleListener> & {
21
+ name: string;
22
+ };
23
+ 'require-data-minimization': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/require-data-minimization").Options | undefined)?], unknown, TSESLint.RuleListener> & {
24
+ name: string;
25
+ };
26
+ 'operability/no-console-log': TSESLint.RuleModule<"consoleLogFound" | "strategyRemove" | "strategyConvert" | "strategyComment" | "strategyWarn", [(import("./rules/operability/no-console-log").Options | undefined)?], unknown, TSESLint.RuleListener> & {
27
+ name: string;
28
+ };
29
+ 'operability/no-process-exit': TSESLint.RuleModule<"noProcessExit", [(import("./rules/operability/no-process-exit").Options | undefined)?], unknown, TSESLint.RuleListener> & {
30
+ name: string;
31
+ };
32
+ 'operability/no-debug-code-in-production': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/no-debug-code-in-production").Options | undefined)?], unknown, TSESLint.RuleListener> & {
33
+ name: string;
34
+ };
35
+ 'operability/no-verbose-error-messages': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/no-verbose-error-messages").Options | undefined)?], unknown, TSESLint.RuleListener> & {
36
+ name: string;
37
+ };
38
+ 'operability/require-code-minification': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/require-code-minification").Options | undefined)?], unknown, TSESLint.RuleListener> & {
39
+ name: string;
40
+ };
41
+ 'operability/require-data-minimization': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/require-data-minimization").Options | undefined)?], unknown, TSESLint.RuleListener> & {
42
+ name: string;
43
+ };
44
+ };
45
+ export declare const plugin: {
46
+ meta: {
47
+ name: string;
48
+ version: string;
49
+ };
50
+ rules: {
51
+ 'no-console-log': TSESLint.RuleModule<"consoleLogFound" | "strategyRemove" | "strategyConvert" | "strategyComment" | "strategyWarn", [(import("./rules/operability/no-console-log").Options | undefined)?], unknown, TSESLint.RuleListener> & {
52
+ name: string;
53
+ };
54
+ 'no-process-exit': TSESLint.RuleModule<"noProcessExit", [(import("./rules/operability/no-process-exit").Options | undefined)?], unknown, TSESLint.RuleListener> & {
55
+ name: string;
56
+ };
57
+ 'no-debug-code-in-production': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/no-debug-code-in-production").Options | undefined)?], unknown, TSESLint.RuleListener> & {
58
+ name: string;
59
+ };
60
+ 'no-verbose-error-messages': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/no-verbose-error-messages").Options | undefined)?], unknown, TSESLint.RuleListener> & {
61
+ name: string;
62
+ };
63
+ 'require-code-minification': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/require-code-minification").Options | undefined)?], unknown, TSESLint.RuleListener> & {
64
+ name: string;
65
+ };
66
+ 'require-data-minimization': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/require-data-minimization").Options | undefined)?], unknown, TSESLint.RuleListener> & {
67
+ name: string;
68
+ };
69
+ 'operability/no-console-log': TSESLint.RuleModule<"consoleLogFound" | "strategyRemove" | "strategyConvert" | "strategyComment" | "strategyWarn", [(import("./rules/operability/no-console-log").Options | undefined)?], unknown, TSESLint.RuleListener> & {
70
+ name: string;
71
+ };
72
+ 'operability/no-process-exit': TSESLint.RuleModule<"noProcessExit", [(import("./rules/operability/no-process-exit").Options | undefined)?], unknown, TSESLint.RuleListener> & {
73
+ name: string;
74
+ };
75
+ 'operability/no-debug-code-in-production': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/no-debug-code-in-production").Options | undefined)?], unknown, TSESLint.RuleListener> & {
76
+ name: string;
77
+ };
78
+ 'operability/no-verbose-error-messages': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/no-verbose-error-messages").Options | undefined)?], unknown, TSESLint.RuleListener> & {
79
+ name: string;
80
+ };
81
+ 'operability/require-code-minification': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/require-code-minification").Options | undefined)?], unknown, TSESLint.RuleListener> & {
82
+ name: string;
83
+ };
84
+ 'operability/require-data-minimization': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/require-data-minimization").Options | undefined)?], unknown, TSESLint.RuleListener> & {
85
+ name: string;
86
+ };
87
+ };
88
+ };
89
+ export declare const configs: {
90
+ recommended: {
91
+ plugins: {
92
+ '@interlace/operability': {
93
+ meta: {
94
+ name: string;
95
+ version: string;
96
+ };
97
+ rules: {
98
+ 'no-console-log': TSESLint.RuleModule<"consoleLogFound" | "strategyRemove" | "strategyConvert" | "strategyComment" | "strategyWarn", [(import("./rules/operability/no-console-log").Options | undefined)?], unknown, TSESLint.RuleListener> & {
99
+ name: string;
100
+ };
101
+ 'no-process-exit': TSESLint.RuleModule<"noProcessExit", [(import("./rules/operability/no-process-exit").Options | undefined)?], unknown, TSESLint.RuleListener> & {
102
+ name: string;
103
+ };
104
+ 'no-debug-code-in-production': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/no-debug-code-in-production").Options | undefined)?], unknown, TSESLint.RuleListener> & {
105
+ name: string;
106
+ };
107
+ 'no-verbose-error-messages': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/no-verbose-error-messages").Options | undefined)?], unknown, TSESLint.RuleListener> & {
108
+ name: string;
109
+ };
110
+ 'require-code-minification': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/require-code-minification").Options | undefined)?], unknown, TSESLint.RuleListener> & {
111
+ name: string;
112
+ };
113
+ 'require-data-minimization': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/require-data-minimization").Options | undefined)?], unknown, TSESLint.RuleListener> & {
114
+ name: string;
115
+ };
116
+ 'operability/no-console-log': TSESLint.RuleModule<"consoleLogFound" | "strategyRemove" | "strategyConvert" | "strategyComment" | "strategyWarn", [(import("./rules/operability/no-console-log").Options | undefined)?], unknown, TSESLint.RuleListener> & {
117
+ name: string;
118
+ };
119
+ 'operability/no-process-exit': TSESLint.RuleModule<"noProcessExit", [(import("./rules/operability/no-process-exit").Options | undefined)?], unknown, TSESLint.RuleListener> & {
120
+ name: string;
121
+ };
122
+ 'operability/no-debug-code-in-production': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/no-debug-code-in-production").Options | undefined)?], unknown, TSESLint.RuleListener> & {
123
+ name: string;
124
+ };
125
+ 'operability/no-verbose-error-messages': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/no-verbose-error-messages").Options | undefined)?], unknown, TSESLint.RuleListener> & {
126
+ name: string;
127
+ };
128
+ 'operability/require-code-minification': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/require-code-minification").Options | undefined)?], unknown, TSESLint.RuleListener> & {
129
+ name: string;
130
+ };
131
+ 'operability/require-data-minimization': TSESLint.RuleModule<"violationDetected", [(import("./rules/operability/require-data-minimization").Options | undefined)?], unknown, TSESLint.RuleListener> & {
132
+ name: string;
133
+ };
134
+ };
135
+ };
136
+ };
137
+ rules: {
138
+ '@interlace/operability/operability/no-console-log': "warn";
139
+ '@interlace/operability/operability/no-debug-code-in-production': "error";
140
+ '@interlace/operability/operability/no-verbose-error-messages': "warn";
141
+ };
142
+ };
143
+ };
144
+ export default plugin;
package/src/index.js ADDED
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2025 Ofri Peretz
4
+ * Licensed under the MIT License. Use of this source code is governed by the
5
+ * MIT license that can be found in the LICENSE file.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.configs = exports.plugin = exports.rules = void 0;
9
+ // Operability rules
10
+ const no_console_log_1 = require("./rules/operability/no-console-log");
11
+ const no_process_exit_1 = require("./rules/operability/no-process-exit");
12
+ const no_debug_code_in_production_1 = require("./rules/operability/no-debug-code-in-production");
13
+ const no_verbose_error_messages_1 = require("./rules/operability/no-verbose-error-messages");
14
+ const require_code_minification_1 = require("./rules/operability/require-code-minification");
15
+ const require_data_minimization_1 = require("./rules/operability/require-data-minimization");
16
+ exports.rules = {
17
+ 'no-console-log': no_console_log_1.noConsoleLog,
18
+ 'no-process-exit': no_process_exit_1.noProcessExit,
19
+ 'no-debug-code-in-production': no_debug_code_in_production_1.noDebugCodeInProduction,
20
+ 'no-verbose-error-messages': no_verbose_error_messages_1.noVerboseErrorMessages,
21
+ 'require-code-minification': require_code_minification_1.requireCodeMinification,
22
+ 'require-data-minimization': require_data_minimization_1.requireDataMinimization,
23
+ // Categorized names
24
+ 'operability/no-console-log': no_console_log_1.noConsoleLog,
25
+ 'operability/no-process-exit': no_process_exit_1.noProcessExit,
26
+ 'operability/no-debug-code-in-production': no_debug_code_in_production_1.noDebugCodeInProduction,
27
+ 'operability/no-verbose-error-messages': no_verbose_error_messages_1.noVerboseErrorMessages,
28
+ 'operability/require-code-minification': require_code_minification_1.requireCodeMinification,
29
+ 'operability/require-data-minimization': require_data_minimization_1.requireDataMinimization,
30
+ };
31
+ exports.plugin = {
32
+ meta: {
33
+ name: 'eslint-plugin-operability',
34
+ version: '1.0.0',
35
+ },
36
+ rules: exports.rules,
37
+ };
38
+ exports.configs = {
39
+ recommended: {
40
+ plugins: {
41
+ '@interlace/operability': exports.plugin,
42
+ },
43
+ rules: {
44
+ '@interlace/operability/operability/no-console-log': 'warn',
45
+ '@interlace/operability/operability/no-debug-code-in-production': 'error',
46
+ '@interlace/operability/operability/no-verbose-error-messages': 'warn',
47
+ },
48
+ },
49
+ };
50
+ exports.default = exports.plugin;
51
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/eslint-plugin-operability/src/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAIH,oBAAoB;AACpB,uEAAkE;AAClE,yEAAoE;AACpE,iGAA0F;AAC1F,6FAAuF;AACvF,6FAAwF;AACxF,6FAAwF;AAE3E,QAAA,KAAK,GAAG;IACnB,gBAAgB,EAAE,6BAAY;IAC9B,iBAAiB,EAAE,+BAAa;IAChC,6BAA6B,EAAE,qDAAuB;IACtD,2BAA2B,EAAE,kDAAsB;IACnD,2BAA2B,EAAE,mDAAuB;IACpD,2BAA2B,EAAE,mDAAuB;IAEpD,oBAAoB;IACpB,4BAA4B,EAAE,6BAAY;IAC1C,6BAA6B,EAAE,+BAAa;IAC5C,yCAAyC,EAAE,qDAAuB;IAClE,uCAAuC,EAAE,kDAAsB;IAC/D,uCAAuC,EAAE,mDAAuB;IAChE,uCAAuC,EAAE,mDAAuB;CACS,CAAC;AAE/D,QAAA,MAAM,GAAG;IACpB,IAAI,EAAE;QACJ,IAAI,EAAE,2BAA2B;QACjC,OAAO,EAAE,OAAO;KACjB;IACD,KAAK,EAAL,aAAK;CAC+B,CAAC;AAE1B,QAAA,OAAO,GAAG;IACrB,WAAW,EAAE;QACX,OAAO,EAAE;YACP,wBAAwB,EAAE,cAAM;SACjC;QACD,KAAK,EAAE;YACL,mDAAmD,EAAE,MAAM;YAC3D,gEAAgE,EAAE,OAAO;YACzE,8DAA8D,EAAE,MAAM;SACvE;KACmC;CACc,CAAC;AAEvD,kBAAe,cAAM,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function eslintPluginOperability(): string;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.eslintPluginOperability = eslintPluginOperability;
4
+ function eslintPluginOperability() {
5
+ return 'eslint-plugin-operability';
6
+ }
7
+ //# sourceMappingURL=eslint-plugin-operability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eslint-plugin-operability.js","sourceRoot":"","sources":["../../../../../packages/eslint-plugin-operability/src/lib/eslint-plugin-operability.ts"],"names":[],"mappings":";;AAAA,0DAEC;AAFD,SAAgB,uBAAuB;IACrC,OAAO,2BAA2B,CAAC;AACrC,CAAC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Copyright (c) 2025 Ofri Peretz
3
+ * Licensed under the MIT License. Use of this source code is governed by the
4
+ * MIT license that can be found in the LICENSE file.
5
+ */
6
+ /**
7
+ * Enhanced ESLint rule: no-console-log
8
+ * Disallows console.log with configurable strategies and LLM-optimized output
9
+ */
10
+ import type { TSESLint } from '@interlace/eslint-devkit';
11
+ /**
12
+ * Strategy for handling console.log
13
+ * @enum {string}
14
+ * @description The strategy to use when handling console.log
15
+ * @example
16
+ * - 'remove': Remove the console.log statement
17
+ * - 'convert': Convert the console.log statement to a logger method
18
+ */
19
+ type Strategy = 'remove' | 'convert' | 'comment' | 'warn';
20
+ /**
21
+ * Message IDs for the rule
22
+ * @enum {string}
23
+ * @description The message IDs for the rule
24
+ * @example
25
+ * - 'consoleLogFound': The message ID for the console.log statement found
26
+ * - 'strategyRemove': The message ID for the strategy to remove the console.log statement
27
+ * - 'strategyConvert': The message ID for the strategy to convert the console.log statement to a logger method
28
+ */
29
+ type MessageIds = 'consoleLogFound' | 'strategyRemove' | 'strategyConvert' | 'strategyComment' | 'strategyWarn';
30
+ interface SeverityMapping {
31
+ [consoleMethod: string]: string;
32
+ }
33
+ export interface Options {
34
+ /** How to handle console.log: 'remove', 'convert', 'comment', or 'warn' */
35
+ strategy?: Strategy;
36
+ /** File path patterns to ignore */
37
+ ignorePaths?: string[];
38
+ /** Name of the logger to use (e.g., 'logger', 'winston'). Default: 'logger' */
39
+ loggerName?: string;
40
+ /** Maximum occurrences to report: number (e.g., 5), 'all' (report all instances), or undefined (no limit). Default: undefined */
41
+ maxOccurrences?: number | 'all';
42
+ /** Map console methods to logger methods */
43
+ severityMap?: SeverityMapping;
44
+ /** Auto-detect logger import in file. Default: true */
45
+ autoDetectLogger?: boolean;
46
+ /** Object names to match (e.g., ['console', 'winston', 'oldLogger']). Default: ['console'] */
47
+ sourcePatterns?: string[];
48
+ }
49
+ type RuleOptions = [Options?];
50
+ export declare const noConsoleLog: TSESLint.RuleModule<MessageIds, RuleOptions, unknown, TSESLint.RuleListener> & {
51
+ name: string;
52
+ };
53
+ export {};
@@ -0,0 +1,328 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2025 Ofri Peretz
4
+ * Licensed under the MIT License. Use of this source code is governed by the
5
+ * MIT license that can be found in the LICENSE file.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.noConsoleLog = void 0;
9
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
10
+ const eslint_devkit_2 = require("@interlace/eslint-devkit");
11
+ const eslint_devkit_3 = require("@interlace/eslint-devkit");
12
+ // Default severity map: only flags console.log by default for minimal disruption
13
+ // Can be extended via severityMap option to include other console methods
14
+ const DEFAULT_SEVERITY_MAP = {
15
+ log: 'debug',
16
+ };
17
+ exports.noConsoleLog = (0, eslint_devkit_2.createRule)({
18
+ name: 'no-console-log',
19
+ meta: {
20
+ type: 'problem',
21
+ docs: {
22
+ description: 'Disallow console.log with configurable remediation strategies',
23
+ },
24
+ fixable: 'code',
25
+ hasSuggestions: false,
26
+ messages: {
27
+ // 🎯 Token optimization: 43% reduction (51→29 tokens) - compact format for logger context
28
+ consoleLogFound: (0, eslint_devkit_1.formatLLMMessage)({
29
+ icon: eslint_devkit_1.MessageIcons.WARNING,
30
+ issueName: 'console.log in production',
31
+ cwe: 'CWE-532',
32
+ description: 'console.log found in production code',
33
+ severity: 'MEDIUM',
34
+ fix: 'Use logger.debug() or remove statement',
35
+ documentationLink: 'https://owasp.org/www-project-log-review-guide/',
36
+ }),
37
+ strategyRemove: (0, eslint_devkit_1.formatLLMMessage)({
38
+ icon: eslint_devkit_1.MessageIcons.STRATEGY,
39
+ issueName: 'Remove Strategy',
40
+ description: 'Remove console.log statement',
41
+ severity: 'LOW',
42
+ fix: 'Delete the console.log statement',
43
+ documentationLink: 'https://owasp.org/www-project-log-review-guide/',
44
+ }),
45
+ strategyConvert: (0, eslint_devkit_1.formatLLMMessage)({
46
+ icon: eslint_devkit_1.MessageIcons.STRATEGY,
47
+ issueName: 'Convert Strategy',
48
+ description: 'Convert to logger method',
49
+ severity: 'LOW',
50
+ fix: 'logger.debug() or logger.info()',
51
+ documentationLink: 'https://github.com/winstonjs/winston',
52
+ }),
53
+ strategyComment: (0, eslint_devkit_1.formatLLMMessage)({
54
+ icon: eslint_devkit_1.MessageIcons.STRATEGY,
55
+ issueName: 'Comment Strategy',
56
+ description: 'Comment out console.log',
57
+ severity: 'LOW',
58
+ fix: '// console.log(...)',
59
+ documentationLink: 'https://owasp.org/www-project-log-review-guide/',
60
+ }),
61
+ strategyWarn: (0, eslint_devkit_1.formatLLMMessage)({
62
+ icon: eslint_devkit_1.MessageIcons.STRATEGY,
63
+ issueName: 'Warn Strategy',
64
+ description: 'Replace with console.warn()',
65
+ severity: 'LOW',
66
+ fix: 'console.warn()',
67
+ documentationLink: 'https://developer.mozilla.org/en-US/docs/Web/API/console/warn',
68
+ }),
69
+ },
70
+ schema: [
71
+ {
72
+ type: 'object',
73
+ properties: {
74
+ strategy: {
75
+ type: 'string',
76
+ enum: ['remove', 'convert', 'comment', 'warn'],
77
+ default: 'remove',
78
+ description: 'Strategy for handling console.log',
79
+ },
80
+ ignorePaths: {
81
+ type: 'array',
82
+ items: { type: 'string' },
83
+ default: [],
84
+ description: 'File path patterns to ignore',
85
+ },
86
+ loggerName: {
87
+ type: 'string',
88
+ default: 'logger',
89
+ description: 'Name of the logger to use for convert strategy (e.g., "logger", "winston")',
90
+ },
91
+ maxOccurrences: {
92
+ oneOf: [
93
+ {
94
+ type: 'number',
95
+ minimum: 1,
96
+ description: 'Maximum number of occurrences to report',
97
+ },
98
+ {
99
+ type: 'string',
100
+ enum: ['all'],
101
+ description: 'Report all violations',
102
+ },
103
+ ],
104
+ description: 'Maximum occurrences to report: number (e.g., 5), "all" (report all), or undefined (no limit)',
105
+ },
106
+ severityMap: {
107
+ type: 'object',
108
+ additionalProperties: { type: 'string' },
109
+ default: {
110
+ log: 'debug',
111
+ },
112
+ description: 'Advanced: Map console methods to logger methods, e.g., {"log": "info", "debug": "verbose"}',
113
+ },
114
+ autoDetectLogger: {
115
+ type: 'boolean',
116
+ default: true,
117
+ description: 'Auto-detect logger import in file',
118
+ },
119
+ sourcePatterns: {
120
+ type: 'array',
121
+ items: { type: 'string' },
122
+ default: ['console'],
123
+ description: 'Object names to match and replace (e.g., ["console", "winston", "oldLogger"]). Uses exact string matching for safety.',
124
+ },
125
+ },
126
+ additionalProperties: false,
127
+ },
128
+ ],
129
+ },
130
+ defaultOptions: [
131
+ {
132
+ strategy: 'remove',
133
+ ignorePaths: [],
134
+ loggerName: 'logger',
135
+ severityMap: { log: 'log' }, // Only flag console.log by default
136
+ autoDetectLogger: true,
137
+ sourcePatterns: ['console'],
138
+ },
139
+ ],
140
+ create(context) {
141
+ const options = context.options[0] || {};
142
+ const { strategy = 'remove', ignorePaths = [], loggerName, maxOccurrences, severityMap = {}, autoDetectLogger = true, sourcePatterns = ['console'], } = options;
143
+ /** Merge user's severityMap with defaults to determine method mappings */
144
+ const effectiveSeverityMap = { ...DEFAULT_SEVERITY_MAP, ...severityMap };
145
+ const filename = context.filename || context.getFilename();
146
+ const sourceCode = context.sourceCode || context.sourceCode;
147
+ const occurrences = [];
148
+ /**
149
+ * Auto-detect logger in file by scanning imports.
150
+ * Uses strict pattern matching to avoid false positives (e.g., 'reactLogo').
151
+ */
152
+ let detectedLogger = null;
153
+ if (autoDetectLogger) {
154
+ const ast = sourceCode.ast;
155
+ const loggerPatterns = /^(logger|log|winston|bunyan|pino|console)$/i;
156
+ for (const statement of ast.body) {
157
+ if (statement.type === 'ImportDeclaration') {
158
+ for (const specifier of statement.specifiers) {
159
+ if (specifier.type === 'ImportDefaultSpecifier' ||
160
+ specifier.type === 'ImportSpecifier') {
161
+ const name = specifier.local.name;
162
+ if (loggerPatterns.test(name)) {
163
+ detectedLogger = name;
164
+ break;
165
+ }
166
+ }
167
+ }
168
+ }
169
+ // Look for require() calls
170
+ if (statement.type === 'VariableDeclaration') {
171
+ for (const declarator of statement.declarations) {
172
+ if (declarator.init?.type === 'CallExpression' &&
173
+ declarator.init.callee.type === 'Identifier' &&
174
+ declarator.init.callee.name === 'require' &&
175
+ declarator.id.type === 'Identifier') {
176
+ const name = declarator.id.name;
177
+ if (loggerPatterns.test(name)) {
178
+ detectedLogger = name;
179
+ break;
180
+ }
181
+ }
182
+ }
183
+ }
184
+ if (detectedLogger)
185
+ break;
186
+ }
187
+ }
188
+ /**
189
+ * Determine the effective logger to use.
190
+ * Priority: explicit loggerName from config > auto-detected logger > default 'logger'
191
+ */
192
+ const effectiveLogger = loggerName || detectedLogger || 'logger';
193
+ /**
194
+ * Check if the current file should be ignored based on ignorePaths patterns.
195
+ * Supports exact matches, directory prefixes, and glob-like patterns.
196
+ */
197
+ const shouldIgnoreFile = () => {
198
+ if (ignorePaths.length === 0)
199
+ return false;
200
+ const normalizedPath = (0, eslint_devkit_3.normalizePath)(filename);
201
+ return ignorePaths.some((pattern) => {
202
+ const normalizedPattern = pattern.replace(/\\/g, '/');
203
+ /** Exact match */
204
+ if (normalizedPath === normalizedPattern)
205
+ return true;
206
+ /** Directory match */
207
+ if (normalizedPath.startsWith(normalizedPattern + '/'))
208
+ return true;
209
+ /** Glob-like pattern support */
210
+ const regexPattern = normalizedPattern
211
+ .replace(/\./g, '\\.')
212
+ .replace(/\*/g, '.*')
213
+ .replace(/\?/g, '.');
214
+ return new RegExp(regexPattern).test(normalizedPath);
215
+ });
216
+ };
217
+ if (shouldIgnoreFile()) {
218
+ return {};
219
+ }
220
+ return {
221
+ /**
222
+ * CallExpression visitor that checks for member expressions matching source patterns.
223
+ * Handles calls like console.log(), winston.info(), oldLogger.debug(), etc.
224
+ */
225
+ CallExpression(node) {
226
+ if (node.callee.type !== 'MemberExpression' ||
227
+ node.callee.object.type !== 'Identifier' ||
228
+ node.callee.property.type !== 'Identifier') {
229
+ return;
230
+ }
231
+ const sourceObject = node.callee.object.name;
232
+ const methodName = node.callee.property.name;
233
+ /** Check if this source object is in our patterns to match */
234
+ if (!sourcePatterns.includes(sourceObject)) {
235
+ return;
236
+ }
237
+ /** Only handle methods that are in the effectiveSeverityMap */
238
+ if (!effectiveSeverityMap[methodName]) {
239
+ return;
240
+ }
241
+ const line = node.loc?.start.line ?? 0;
242
+ occurrences.push(line);
243
+ // ✅ Calculate skip condition (don't return early)
244
+ // 'all' means report all instances
245
+ // undefined means no limit
246
+ // number > 0 means limit to that count
247
+ const shouldSkipReport = maxOccurrences !== undefined &&
248
+ maxOccurrences !== 'all' &&
249
+ typeof maxOccurrences === 'number' &&
250
+ maxOccurrences > 0 &&
251
+ occurrences.length > maxOccurrences;
252
+ const sourceCode = context.sourceCode || context.sourceCode;
253
+ const relativePath = (0, eslint_devkit_3.getRelativePath)(process.cwd(), filename);
254
+ /**
255
+ * Determine the target logger method to use based on severityMap.
256
+ *
257
+ * @example
258
+ * Default: console.log → logger.log, console.debug → logger.debug
259
+ *
260
+ * @example
261
+ * With severityMap: { log: 'info' } → console.log → logger.info, console.debug → logger.debug
262
+ */
263
+ const targetLoggerMethod = effectiveSeverityMap[methodName] || methodName;
264
+ /**
265
+ * Generate fix based on the configured strategy.
266
+ * Handles remove, convert, comment, and warn strategies.
267
+ */
268
+ const fix = (fixer) => {
269
+ const statement = findParentStatement(node);
270
+ if (!statement)
271
+ return null;
272
+ switch (strategy) {
273
+ case 'remove':
274
+ return fixer.remove(statement);
275
+ case 'convert':
276
+ return fixer.replaceText(node.callee, `${effectiveLogger}.${targetLoggerMethod}`);
277
+ case 'comment': {
278
+ const text = sourceCode.getText(statement);
279
+ return fixer.replaceText(statement, `// ${text}`);
280
+ }
281
+ case 'warn':
282
+ return fixer.replaceText(node.callee, 'console.warn');
283
+ default:
284
+ return null;
285
+ }
286
+ };
287
+ /** Build conversion info for the error message */
288
+ let conversionInfo = '';
289
+ if (strategy === 'convert') {
290
+ conversionInfo = ` → ${effectiveLogger}.${targetLoggerMethod}()`;
291
+ }
292
+ // ✅ Only report if not exceeding limit
293
+ if (!shouldSkipReport) {
294
+ context.report({
295
+ node,
296
+ messageId: 'consoleLogFound',
297
+ data: {
298
+ consoleMethod: `${sourceObject}.${methodName}`,
299
+ filePath: relativePath,
300
+ line: String(line),
301
+ strategy,
302
+ conversionInfo,
303
+ logger: effectiveLogger,
304
+ method: targetLoggerMethod,
305
+ },
306
+ fix,
307
+ });
308
+ }
309
+ },
310
+ };
311
+ },
312
+ });
313
+ /**
314
+ * Find the parent statement node for proper removal
315
+ */
316
+ function findParentStatement(node) {
317
+ let current = node;
318
+ while (current) {
319
+ if (current.type === 'ExpressionStatement' ||
320
+ current.type === 'ReturnStatement' ||
321
+ current.type === 'VariableDeclaration') {
322
+ return current;
323
+ }
324
+ current = current.parent;
325
+ }
326
+ return null;
327
+ }
328
+ //# sourceMappingURL=no-console-log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-console-log.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-operability/src/rules/operability/no-console-log.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Copyright (c) 2025 Ofri Peretz
3
+ * Licensed under the MIT License. Use of this source code is governed by the
4
+ * MIT license that can be found in the LICENSE file.
5
+ */
6
+ export interface Options {
7
+ }
8
+ type RuleOptions = [Options?];
9
+ export declare const noDebugCodeInProduction: import("@typescript-eslint/utils/ts-eslint").RuleModule<"violationDetected", RuleOptions, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
10
+ name: string;
11
+ };
12
+ export {};
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2025 Ofri Peretz
4
+ * Licensed under the MIT License. Use of this source code is governed by the
5
+ * MIT license that can be found in the LICENSE file.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.noDebugCodeInProduction = void 0;
9
+ /**
10
+ * @fileoverview Detect debug code in production
11
+ * @see https://owasp.org/www-project-mobile-top-10/
12
+ * @see https://cwe.mitre.org/data/definitions/489.html
13
+ */
14
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
15
+ exports.noDebugCodeInProduction = (0, eslint_devkit_1.createRule)({
16
+ name: 'no-debug-code-in-production',
17
+ meta: {
18
+ type: 'problem',
19
+ docs: {
20
+ description: 'Detect debug code in production',
21
+ },
22
+ messages: {
23
+ violationDetected: (0, eslint_devkit_1.formatLLMMessage)({
24
+ icon: eslint_devkit_1.MessageIcons.SECURITY,
25
+ issueName: 'violation Detected',
26
+ cwe: 'CWE-489',
27
+ description: 'Detect debug code in production detected - DEBUG, __DEV__, console',
28
+ severity: 'HIGH',
29
+ fix: 'Review and apply secure practices',
30
+ documentationLink: 'https://cwe.mitre.org/data/definitions/489.html',
31
+ }),
32
+ },
33
+ schema: [],
34
+ },
35
+ defaultOptions: [],
36
+ create(context) {
37
+ return {
38
+ Identifier(node) {
39
+ if (['DEBUG', '__DEV__'].includes(node.name)) {
40
+ context.report({ node, messageId: 'violationDetected' });
41
+ }
42
+ },
43
+ CallExpression(node) {
44
+ if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
45
+ node.callee.object.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
46
+ node.callee.object.name === 'console' &&
47
+ node.callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
48
+ node.callee.property.name === 'log') {
49
+ context.report({ node, messageId: 'violationDetected' });
50
+ }
51
+ },
52
+ };
53
+ },
54
+ });
55
+ //# sourceMappingURL=no-debug-code-in-production.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-debug-code-in-production.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-operability/src/rules/operability/no-debug-code-in-production.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH;;;;GAIG;AAEH,4DAKkC;AAUrB,QAAA,uBAAuB,GAAG,IAAA,0BAAU,EAA0B;IACzE,IAAI,EAAE,6BAA6B;IACnC,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,iCAAiC;SAC/C;QACD,QAAQ,EAAE;YACR,iBAAiB,EAAE,IAAA,gCAAgB,EAAC;gBAClC,IAAI,EAAE,4BAAY,CAAC,QAAQ;gBAC3B,SAAS,EAAE,oBAAoB;gBAC/B,GAAG,EAAE,SAAS;gBACd,WAAW,EACT,oEAAoE;gBACtE,QAAQ,EAAE,MAAM;gBAChB,GAAG,EAAE,mCAAmC;gBACxC,iBAAiB,EAAE,iDAAiD;aACrE,CAAC;SACH;QACD,MAAM,EAAE,EAAE;KACX;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,UAAU,CAAC,IAAyB;gBAClC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC7C,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,mBAAmB,EAAE,CAAC,CAAC;gBAC3D,CAAC;YACH,CAAC;YACD,cAAc,CAAC,IAA6B;gBAC1C,IACE,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,8BAAc,CAAC,gBAAgB;oBACpD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,8BAAc,CAAC,UAAU;oBACrD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS;oBACrC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,8BAAc,CAAC,UAAU;oBACvD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,KAAK,EACnC,CAAC;oBACD,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,mBAAmB,EAAE,CAAC,CAAC;gBAC3D,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Copyright (c) 2025 Ofri Peretz
3
+ * Licensed under the MIT License. Use of this source code is governed by the
4
+ * MIT license that can be found in the LICENSE file.
5
+ */
6
+ /**
7
+ * ESLint Rule: no-process-exit
8
+ * Prevent usage of process.exit()
9
+ */
10
+ import type { TSESLint } from '@interlace/eslint-devkit';
11
+ export interface Options {
12
+ /** Allow process.exit in specific contexts */
13
+ allow?: string[];
14
+ }
15
+ type RuleOptions = [Options?];
16
+ export declare const noProcessExit: TSESLint.RuleModule<"noProcessExit", RuleOptions, unknown, TSESLint.RuleListener> & {
17
+ name: string;
18
+ };
19
+ export {};
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2025 Ofri Peretz
4
+ * Licensed under the MIT License. Use of this source code is governed by the
5
+ * MIT license that can be found in the LICENSE file.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.noProcessExit = void 0;
9
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
10
+ const eslint_devkit_2 = require("@interlace/eslint-devkit");
11
+ exports.noProcessExit = (0, eslint_devkit_1.createRule)({
12
+ name: 'no-process-exit',
13
+ meta: {
14
+ type: 'problem',
15
+ docs: {
16
+ description: 'Prevent usage of process.exit() which can terminate the process unexpectedly',
17
+ },
18
+ hasSuggestions: false,
19
+ messages: {
20
+ noProcessExit: (0, eslint_devkit_2.formatLLMMessage)({
21
+ icon: eslint_devkit_2.MessageIcons.WARNING,
22
+ issueName: 'Process Exit',
23
+ description: 'Avoid using process.exit()',
24
+ severity: 'HIGH',
25
+ fix: 'Use throw error or return exit code instead',
26
+ documentationLink: 'https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-process-exit.md',
27
+ }),
28
+ },
29
+ schema: [
30
+ {
31
+ type: 'object',
32
+ properties: {
33
+ allow: {
34
+ type: 'array',
35
+ items: { type: 'string' },
36
+ default: [],
37
+ },
38
+ },
39
+ additionalProperties: false,
40
+ },
41
+ ],
42
+ },
43
+ defaultOptions: [{ allow: [] }],
44
+ create(context) {
45
+ function isInAllowedContext() {
46
+ // For simplicity, we'll skip the allow option for now
47
+ return false;
48
+ }
49
+ function isProcessExitCall(node) {
50
+ // Check if this is a call to process.exit
51
+ function isProcessExitMember(callee) {
52
+ if (callee.type === 'MemberExpression' &&
53
+ callee.object.type === 'Identifier' &&
54
+ callee.object.name === 'process' &&
55
+ callee.property.type === 'Identifier' &&
56
+ callee.property.name === 'exit') {
57
+ return true;
58
+ }
59
+ return false;
60
+ }
61
+ return isProcessExitMember(node.callee);
62
+ }
63
+ return {
64
+ CallExpression(node) {
65
+ if (isProcessExitCall(node) && !isInAllowedContext()) {
66
+ context.report({
67
+ node,
68
+ messageId: 'noProcessExit',
69
+ data: {
70
+ current: 'process.exit()',
71
+ fix: 'throw error or return',
72
+ },
73
+ });
74
+ }
75
+ },
76
+ };
77
+ },
78
+ });
79
+ //# sourceMappingURL=no-process-exit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-process-exit.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-operability/src/rules/operability/no-process-exit.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAOH,4DAAsD;AACtD,4DAA0E;AAW7D,QAAA,aAAa,GAAG,IAAA,0BAAU,EAA0B;IAC/D,IAAI,EAAE,iBAAiB;IACvB,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EACT,8EAA8E;SACjF;QACD,cAAc,EAAE,KAAK;QACrB,QAAQ,EAAE;YACR,aAAa,EAAE,IAAA,gCAAgB,EAAC;gBAC9B,IAAI,EAAE,4BAAY,CAAC,OAAO;gBAC1B,SAAS,EAAE,cAAc;gBACzB,WAAW,EAAE,4BAA4B;gBACzC,QAAQ,EAAE,MAAM;gBAChB,GAAG,EAAE,6CAA6C;gBAClD,iBAAiB,EACf,+FAA+F;aAClG,CAAC;SACH;QACD,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,KAAK,EAAE;wBACL,IAAI,EAAE,OAAO;wBACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;wBACzB,OAAO,EAAE,EAAE;qBACZ;iBACF;gBACD,oBAAoB,EAAE,KAAK;aAC5B;SACF;KACF;IACD,cAAc,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IAE/B,MAAM,CAAC,OAAsD;QAC3D,SAAS,kBAAkB;YACzB,sDAAsD;YACtD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,SAAS,iBAAiB,CAAC,IAA6B;YACtD,0CAA0C;YAC1C,SAAS,mBAAmB,CAAC,MAA2B;gBACtD,IACE,MAAM,CAAC,IAAI,KAAK,kBAAkB;oBAClC,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY;oBACnC,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS;oBAChC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;oBACrC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,MAAM,EAC/B,CAAC;oBACD,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,OAAO,KAAK,CAAC;YACf,CAAC;YAED,OAAO,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1C,CAAC;QAED,OAAO;YACL,cAAc,CAAC,IAA6B;gBAC1C,IAAI,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,CAAC;oBACrD,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI;wBACJ,SAAS,EAAE,eAAe;wBAC1B,IAAI,EAAE;4BACJ,OAAO,EAAE,gBAAgB;4BACzB,GAAG,EAAE,uBAAuB;yBAC7B;qBACF,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Copyright (c) 2025 Ofri Peretz
3
+ * Licensed under the MIT License. Use of this source code is governed by the
4
+ * MIT license that can be found in the LICENSE file.
5
+ */
6
+ export interface Options {
7
+ }
8
+ type RuleOptions = [Options?];
9
+ export declare const noVerboseErrorMessages: import("@typescript-eslint/utils/ts-eslint").RuleModule<"violationDetected", RuleOptions, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
10
+ name: string;
11
+ };
12
+ export {};
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2025 Ofri Peretz
4
+ * Licensed under the MIT License. Use of this source code is governed by the
5
+ * MIT license that can be found in the LICENSE file.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.noVerboseErrorMessages = void 0;
9
+ /**
10
+ * @fileoverview Prevent exposing stack traces to users
11
+ * @see https://owasp.org/www-project-mobile-top-10/
12
+ * @see https://cwe.mitre.org/data/definitions/209.html
13
+ */
14
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
15
+ exports.noVerboseErrorMessages = (0, eslint_devkit_1.createRule)({
16
+ name: 'no-verbose-error-messages',
17
+ meta: {
18
+ type: 'problem',
19
+ docs: {
20
+ description: 'Prevent exposing stack traces to users',
21
+ },
22
+ messages: {
23
+ violationDetected: (0, eslint_devkit_1.formatLLMMessage)({
24
+ icon: eslint_devkit_1.MessageIcons.SECURITY,
25
+ issueName: 'violation Detected',
26
+ cwe: 'CWE-209',
27
+ description: 'Prevent exposing stack traces to users detected - this is a security risk',
28
+ severity: 'MEDIUM',
29
+ fix: 'Review and apply secure practices',
30
+ documentationLink: 'https://cwe.mitre.org/data/definitions/209.html',
31
+ }),
32
+ },
33
+ schema: [],
34
+ },
35
+ defaultOptions: [],
36
+ create(context) {
37
+ function report(node) {
38
+ context.report({
39
+ node,
40
+ messageId: 'violationDetected',
41
+ });
42
+ }
43
+ return {
44
+ CallExpression(node) {
45
+ // Check res.send/res.json with error.stack
46
+ if (node.type === eslint_devkit_1.AST_NODE_TYPES.CallExpression &&
47
+ node.callee.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
48
+ node.callee.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
49
+ ['send', 'json'].includes(node.callee.property.name)) {
50
+ const arg = node.arguments[0];
51
+ // Check for error.stack or err.stack
52
+ if (arg?.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
53
+ arg.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
54
+ arg.property.name === 'stack') {
55
+ report(node);
56
+ }
57
+ // Check for { stack: error.stack } in object
58
+ if (arg?.type === eslint_devkit_1.AST_NODE_TYPES.ObjectExpression) {
59
+ const stackProp = arg.properties.find((p) => p.type === eslint_devkit_1.AST_NODE_TYPES.Property &&
60
+ p.key.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
61
+ (p.key.name === 'stack' ||
62
+ (p.value.type === eslint_devkit_1.AST_NODE_TYPES.MemberExpression &&
63
+ p.value.property.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
64
+ p.value.property.name === 'stack')));
65
+ if (stackProp) {
66
+ report(node);
67
+ }
68
+ }
69
+ }
70
+ },
71
+ };
72
+ },
73
+ });
74
+ //# sourceMappingURL=no-verbose-error-messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-verbose-error-messages.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-operability/src/rules/operability/no-verbose-error-messages.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH;;;;GAIG;AAEH,4DAKkC;AAUrB,QAAA,sBAAsB,GAAG,IAAA,0BAAU,EAA0B;IACxE,IAAI,EAAE,2BAA2B;IACjC,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,wCAAwC;SACtD;QACD,QAAQ,EAAE;YACR,iBAAiB,EAAE,IAAA,gCAAgB,EAAC;gBAClC,IAAI,EAAE,4BAAY,CAAC,QAAQ;gBAC3B,SAAS,EAAE,oBAAoB;gBAC/B,GAAG,EAAE,SAAS;gBACd,WAAW,EACT,2EAA2E;gBAC7E,QAAQ,EAAE,QAAQ;gBAClB,GAAG,EAAE,mCAAmC;gBACxC,iBAAiB,EAAE,iDAAiD;aACrE,CAAC;SACH;QACD,MAAM,EAAE,EAAE;KACX;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,SAAS,MAAM,CAAC,IAAmB;YACjC,OAAO,CAAC,MAAM,CAAC;gBACb,IAAI;gBACJ,SAAS,EAAE,mBAAmB;aAC/B,CAAC,CAAC;QACL,CAAC;QAED,OAAO;YACL,cAAc,CAAC,IAA6B;gBAC1C,2CAA2C;gBAC3C,IACE,IAAI,CAAC,IAAI,KAAK,8BAAc,CAAC,cAAc;oBAC3C,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,8BAAc,CAAC,gBAAgB;oBACpD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,8BAAc,CAAC,UAAU;oBACvD,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EACpD,CAAC;oBACD,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;oBAE9B,qCAAqC;oBACrC,IACE,GAAG,EAAE,IAAI,KAAK,8BAAc,CAAC,gBAAgB;wBAC7C,GAAG,CAAC,QAAQ,CAAC,IAAI,KAAK,8BAAc,CAAC,UAAU;wBAC/C,GAAG,CAAC,QAAQ,CAAC,IAAI,KAAK,OAAO,EAC7B,CAAC;wBACD,MAAM,CAAC,IAAI,CAAC,CAAC;oBACf,CAAC;oBAED,6CAA6C;oBAC7C,IAAI,GAAG,EAAE,IAAI,KAAK,8BAAc,CAAC,gBAAgB,EAAE,CAAC;wBAClD,MAAM,SAAS,GAAG,GAAG,CAAC,UAAU,CAAC,IAAI,CACnC,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,IAAI,KAAK,8BAAc,CAAC,QAAQ;4BAClC,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,8BAAc,CAAC,UAAU;4BACxC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,OAAO;gCACrB,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,8BAAc,CAAC,gBAAgB;oCAC/C,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,8BAAc,CAAC,UAAU;oCACnD,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAC1C,CAAC;wBACF,IAAI,SAAS,EAAE,CAAC;4BACd,MAAM,CAAC,IAAI,CAAC,CAAC;wBACf,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Copyright (c) 2025 Ofri Peretz
3
+ * Licensed under the MIT License. Use of this source code is governed by the
4
+ * MIT license that can be found in the LICENSE file.
5
+ */
6
+ export interface Options {
7
+ }
8
+ type RuleOptions = [Options?];
9
+ export declare const requireCodeMinification: import("@typescript-eslint/utils/ts-eslint").RuleModule<"violationDetected", RuleOptions, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
10
+ name: string;
11
+ };
12
+ export {};
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2025 Ofri Peretz
4
+ * Licensed under the MIT License. Use of this source code is governed by the
5
+ * MIT license that can be found in the LICENSE file.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.requireCodeMinification = void 0;
9
+ /**
10
+ * @fileoverview Require minification configuration
11
+ * @see https://owasp.org/www-project-mobile-top-10/
12
+ * @see https://cwe.mitre.org/data/definitions/656.html
13
+ */
14
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
15
+ exports.requireCodeMinification = (0, eslint_devkit_1.createRule)({
16
+ name: 'require-code-minification',
17
+ meta: {
18
+ type: 'problem',
19
+ docs: {
20
+ description: 'Require minification configuration',
21
+ },
22
+ messages: {
23
+ violationDetected: (0, eslint_devkit_1.formatLLMMessage)({
24
+ icon: eslint_devkit_1.MessageIcons.SECURITY,
25
+ issueName: 'violation Detected',
26
+ cwe: 'CWE-656',
27
+ description: 'Require minification configuration detected - Build config without minification',
28
+ severity: 'LOW',
29
+ fix: 'Review and apply secure practices',
30
+ documentationLink: 'https://cwe.mitre.org/data/definitions/656.html',
31
+ }),
32
+ },
33
+ schema: [],
34
+ },
35
+ defaultOptions: [],
36
+ create(context) {
37
+ return {
38
+ Property(node) {
39
+ if (node.key.type === 'Identifier' &&
40
+ node.key.name === 'minimize' &&
41
+ node.value.type === 'Literal' &&
42
+ node.value.value === false) {
43
+ context.report({ node, messageId: 'violationDetected' });
44
+ }
45
+ },
46
+ };
47
+ },
48
+ });
49
+ //# sourceMappingURL=require-code-minification.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"require-code-minification.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-operability/src/rules/operability/require-code-minification.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH;;;;GAIG;AAEH,4DAIkC;AAUrB,QAAA,uBAAuB,GAAG,IAAA,0BAAU,EAA0B;IACzE,IAAI,EAAE,2BAA2B;IACjC,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,oCAAoC;SAClD;QACD,QAAQ,EAAE;YACR,iBAAiB,EAAE,IAAA,gCAAgB,EAAC;gBAClC,IAAI,EAAE,4BAAY,CAAC,QAAQ;gBAC3B,SAAS,EAAE,oBAAoB;gBAC/B,GAAG,EAAE,SAAS;gBACd,WAAW,EACT,iFAAiF;gBACnF,QAAQ,EAAE,KAAK;gBACf,GAAG,EAAE,mCAAmC;gBACxC,iBAAiB,EAAE,iDAAiD;aACrE,CAAC;SACH;QACD,MAAM,EAAE,EAAE;KACX;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,QAAQ,CAAC,IAAuB;gBAC9B,IACE,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,YAAY;oBAC9B,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,UAAU;oBAC5B,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS;oBAC7B,IAAI,CAAC,KAAK,CAAC,KAAK,KAAK,KAAK,EAC1B,CAAC;oBACD,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,mBAAmB,EAAE,CAAC,CAAC;gBAC3D,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Copyright (c) 2025 Ofri Peretz
3
+ * Licensed under the MIT License. Use of this source code is governed by the
4
+ * MIT license that can be found in the LICENSE file.
5
+ */
6
+ export interface Options {
7
+ }
8
+ type RuleOptions = [Options?];
9
+ export declare const requireDataMinimization: import("@typescript-eslint/utils/ts-eslint").RuleModule<"violationDetected", RuleOptions, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
10
+ name: string;
11
+ };
12
+ export {};
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) 2025 Ofri Peretz
4
+ * Licensed under the MIT License. Use of this source code is governed by the
5
+ * MIT license that can be found in the LICENSE file.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.requireDataMinimization = void 0;
9
+ /**
10
+ * @fileoverview Identify excessive data collection
11
+ * @see https://owasp.org/www-project-mobile-top-10/
12
+ * @see https://cwe.mitre.org/data/definitions/213.html
13
+ */
14
+ const eslint_devkit_1 = require("@interlace/eslint-devkit");
15
+ exports.requireDataMinimization = (0, eslint_devkit_1.createRule)({
16
+ name: 'require-data-minimization',
17
+ meta: {
18
+ type: 'suggestion',
19
+ docs: {
20
+ description: 'Identify excessive data collection patterns',
21
+ },
22
+ messages: {
23
+ violationDetected: (0, eslint_devkit_1.formatLLMMessage)({
24
+ icon: eslint_devkit_1.MessageIcons.SECURITY,
25
+ issueName: 'violation Detected',
26
+ cwe: 'CWE-213',
27
+ description: 'Excessive data collection detected - only collect data that is necessary',
28
+ severity: 'MEDIUM',
29
+ fix: 'Review and apply secure practices',
30
+ documentationLink: 'https://cwe.mitre.org/data/definitions/213.html',
31
+ }),
32
+ },
33
+ schema: [],
34
+ },
35
+ defaultOptions: [],
36
+ create(context) {
37
+ function report(node) {
38
+ context.report({ node, messageId: 'violationDetected' });
39
+ }
40
+ return {
41
+ ObjectExpression(node) {
42
+ // Flag objects with >10 properties being collected
43
+ if (node.properties.length > 10) {
44
+ // Check if this looks like user data collection
45
+ const hasUserData = node.properties.some((p) => p.type === eslint_devkit_1.AST_NODE_TYPES.Property &&
46
+ p.key.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
47
+ ['email', 'name', 'phone', 'address'].includes(p.key.name));
48
+ if (hasUserData) {
49
+ report(node);
50
+ }
51
+ }
52
+ },
53
+ };
54
+ },
55
+ });
56
+ //# sourceMappingURL=require-data-minimization.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"require-data-minimization.js","sourceRoot":"","sources":["../../../../../../packages/eslint-plugin-operability/src/rules/operability/require-data-minimization.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH;;;;GAIG;AAEH,4DAKkC;AAUrB,QAAA,uBAAuB,GAAG,IAAA,0BAAU,EAA0B;IACzE,IAAI,EAAE,2BAA2B;IACjC,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,WAAW,EAAE,6CAA6C;SAC3D;QACD,QAAQ,EAAE;YACR,iBAAiB,EAAE,IAAA,gCAAgB,EAAC;gBAClC,IAAI,EAAE,4BAAY,CAAC,QAAQ;gBAC3B,SAAS,EAAE,oBAAoB;gBAC/B,GAAG,EAAE,SAAS;gBACd,WAAW,EACT,0EAA0E;gBAC5E,QAAQ,EAAE,QAAQ;gBAClB,GAAG,EAAE,mCAAmC;gBACxC,iBAAiB,EAAE,iDAAiD;aACrE,CAAC;SACH;QACD,MAAM,EAAE,EAAE;KACX;IACD,cAAc,EAAE,EAAE;IAClB,MAAM,CAAC,OAAO;QACZ,SAAS,MAAM,CAAC,IAAmB;YACjC,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,mBAAmB,EAAE,CAAC,CAAC;QAC3D,CAAC;QAED,OAAO;YACL,gBAAgB,CAAC,IAA+B;gBAC9C,mDAAmD;gBACnD,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;oBAChC,gDAAgD;oBAChD,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CACtC,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,IAAI,KAAK,8BAAc,CAAC,QAAQ;wBAClC,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,8BAAc,CAAC,UAAU;wBACxC,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAC7D,CAAC;oBAEF,IAAI,WAAW,EAAE,CAAC;wBAChB,MAAM,CAAC,IAAI,CAAC,CAAC;oBACf,CAAC;gBACH,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}