envprobe 1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) [2026] [Bitreon]
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,316 @@
1
+ # envcheck-cli
2
+
3
+ ## The Origin Story (Or: How Coffee Led to Code)
4
+
5
+ So there I was, sitting on my sofa, sipping my coffee on a perfectly ordinary Saturday morning. You know that moment when the caffeine hits just right and your brain suddenly decides to replay every production incident from the past year? Yeah, that happened.
6
+
7
+ I was thinking about *that one time* when the staging environment exploded because someone added `DATABASE_URL` to the code but forgot to document it in `.env.example`. The new dev spent three hours debugging why their local setup wouldn't work. Three. Hours. For a missing environment variable.
8
+
9
+ My coffee was getting cold as I stared at the ceiling, and I thought: "Why isn't there a tool that just... checks this stuff?" You know, something that scans your code, looks at what env vars you're actually using, and yells at you if they're not documented. Something simple. Something that doesn't require installing half of npm to work.
10
+
11
+ So I did what any reasonable developer does when caffeinated and slightly annoyed: I built it.
12
+
13
+ And thus, envcheck-cli was born. From a sofa. With lukewarm coffee. Living its best life as a zero-dependency CLI tool that saves developers from the ancient curse of undocumented environment variables.
14
+
15
+ ## What This Thing Actually Does
16
+
17
+ envcheck scans your codebase and compares environment variable usage against your `.env.example` file. It's like a spell-checker, but for env vars. It catches three types of problems:
18
+
19
+ - **MISSING** - You're using `process.env.SECRET_API_KEY` in your code, but `.env.example` has never heard of it. Rookie mistake.
20
+ - **UNUSED** - You documented `LEGACY_FEATURE_FLAG` in `.env.example`, but it's not referenced anywhere. Time to clean house.
21
+ - **UNDOCUMENTED** - The variable exists and is used, but there's no comment explaining what it does. Future you will hate present you for this.
22
+
23
+ ## Why You Might Actually Want This
24
+
25
+ - **Zero dependencies** - Seriously. None. Just Node.js built-ins. Your `node_modules` folder thanks me.
26
+ - **Multi-language support** - JavaScript, TypeScript, Python, Go, Ruby, Rust, Shell scripts. I got you.
27
+ - **Multiple output formats** - Human-readable text, JSON for your scripts, GitHub Actions annotations for your CI/CD pipeline.
28
+ - **Actually fast** - No AI, no blockchain, no unnecessary complexity. Just good old-fashioned file scanning.
29
+ - **CI/CD ready** - Configurable failure conditions so you can enforce env var hygiene in your pipeline.
30
+ - **Interactive REPL** - Explore and fix issues in an interactive shell with tab completion and command history.
31
+ - **Watch mode** - Automatically rerun validation when files change during development.
32
+ - **Auto-fix** - Automatically add missing variables to .env.example with smart defaults.
33
+ - **Intelligent suggestions** - Get actionable hints including typo detection and smart example values.
34
+ - **Configuration files** - Save your settings in `.envcheckrc.json` for consistent team workflows.
35
+
36
+ ## Supported Languages
37
+
38
+ Because not everyone writes JavaScript (shocking, I know):
39
+
40
+ - JavaScript/TypeScript (`.js`, `.jsx`, `.ts`, `.tsx`, `.mjs`, `.cjs`)
41
+ - Python (`.py`)
42
+ - Go (`.go`)
43
+ - Ruby (`.rb`)
44
+ - Rust (`.rs`)
45
+ - Shell/Bash (`.sh`, `.bash`, `.zsh`)
46
+
47
+ ## Requirements
48
+
49
+ - Node.js 18.0.0 or higher (because we're living in the future)
50
+
51
+ ## Installation
52
+
53
+ ```bash
54
+ npm install -g envcheck-cli
55
+ ```
56
+
57
+ Or run it directly without installing:
58
+
59
+ ```bash
60
+ npx envcheck-cli
61
+ ```
62
+
63
+ ## Quick Start
64
+
65
+ The simplest way to use envcheck:
66
+
67
+ ```bash
68
+ envcheck
69
+ ```
70
+
71
+ That's it. It scans your current directory, checks your `.env.example`, and tells you what's wrong. But there's more if you need it.
72
+
73
+ ## The Evolution: From Simple to Powerful
74
+
75
+ ### Act I: The Basic Scan
76
+
77
+ You run `envcheck` and it does its thing. Finds missing vars, unused vars, undocumented vars. Clean output. Done.
78
+
79
+ ```bash
80
+ envcheck
81
+ ```
82
+
83
+ But then you think: "What if I could just... stay in here? Like a conversation?"
84
+
85
+ ### Act II: The Interactive Mode
86
+
87
+ So we built a REPL. Because sometimes you want to poke around, try different settings, see what happens.
88
+
89
+ ```bash
90
+ envcheck --repl
91
+ ```
92
+
93
+ Now you're in an interactive shell. Type `:help` and discover you can:
94
+ - Change settings on the fly (`:set format json`)
95
+ - View your command history (`:history`)
96
+ - Get smart suggestions (`:suggest`)
97
+ - Save your config for later (`:save`)
98
+
99
+ It's like having a conversation with your environment variables. Weird, but useful.
100
+
101
+ ### Act III: The "I'm Coding Right Now" Mode
102
+
103
+ You're deep in the zone. Writing code. Adding env vars. You don't want to keep running commands manually.
104
+
105
+ ```bash
106
+ envcheck --watch
107
+ ```
108
+
109
+ Now it watches your files. Every time you save, it checks again. Instant feedback. No context switching. Just code and know.
110
+
111
+ ### Act IV: The "Just Fix It Already" Button
112
+
113
+ You've got 15 missing variables. You know they need to be in `.env.example`. You don't want to type them all out.
114
+
115
+ ```bash
116
+ envcheck --fix
117
+ ```
118
+
119
+ Done. It adds them for you. With smart defaults:
120
+ - Sees `API_KEY`? Suggests `your_api_key_here`
121
+ - Sees `DATABASE_URL`? Suggests `postgres://localhost:5432/dbname`
122
+ - Sees `PORT`? Suggests `3000`
123
+
124
+ It's not magic. It's just pattern matching. But it feels like magic at 11 PM.
125
+
126
+ ### Act V: The "Did You Mean...?" Feature
127
+
128
+ You typed `DATABSE_URL` instead of `DATABASE_URL`. We've all been there.
129
+
130
+ ```bash
131
+ envcheck
132
+ ```
133
+
134
+ Output:
135
+ ```
136
+ 💡 Did you mean 'DATABASE_URL' instead of 'DATABSE_URL'? (91% similar)
137
+ ```
138
+
139
+ It's like autocorrect, but for environment variables. And it doesn't change "duck" to something embarrassing.
140
+
141
+ ### Act VI: The Team Player
142
+
143
+ Your team needs consistency. Everyone should use the same settings. So you create a config file:
144
+
145
+ ```json
146
+ {
147
+ "path": ".",
148
+ "envFile": ".env.example",
149
+ "failOn": "missing",
150
+ "ignore": ["node_modules/**", "**/*.test.js"]
151
+ }
152
+ ```
153
+
154
+ Save it as `.envcheckrc.json`. Commit it. Now everyone's on the same page. No more "but it works on my machine" because of env var issues.
155
+
156
+ ## Real-World Scenarios (Or: How People Actually Use This)
157
+
158
+ ### Scenario 1: The New Developer
159
+
160
+ Sarah joins your team. She clones the repo, runs `npm install`, starts the app. It crashes. "What env vars do I need?"
161
+
162
+ With envcheck:
163
+ ```bash
164
+ envcheck
165
+ ```
166
+
167
+ She sees exactly what's missing. Copies them to her `.env`. App starts. She's productive in 5 minutes instead of 50.
168
+
169
+ ### Scenario 2: The Refactoring Session
170
+
171
+ You're removing an old feature. Delete a bunch of code. But did you remove the env vars from `.env.example`?
172
+
173
+ ```bash
174
+ envcheck
175
+ ```
176
+
177
+ "Found 3 unused variables." Clean them up. Keep your config lean.
178
+
179
+ ### Scenario 3: The CI/CD Pipeline
180
+
181
+ Your staging environment broke because someone forgot to document a new env var. Again.
182
+
183
+ Add to your GitHub Actions:
184
+ ```yaml
185
+ - run: envcheck --format github --fail-on missing
186
+ ```
187
+
188
+ Now the PR won't merge until all env vars are documented. Problem solved.
189
+
190
+ ### Scenario 4: The Late Night Coding Session
191
+
192
+ It's 2 AM. You're in the zone. Adding features. Adding env vars. You don't want to break your flow.
193
+
194
+ ```bash
195
+ envcheck --watch
196
+ ```
197
+
198
+ Terminal in the corner. Updates automatically. You see issues as they happen. Fix them before you forget.
199
+
200
+ ### Scenario 5: The "I'll Do It Later" Moment
201
+
202
+ You added 10 new env vars. You know you need to document them. But typing them all out? Ugh.
203
+
204
+ ```bash
205
+ envcheck --fix
206
+ ```
207
+
208
+ It adds them all with smart defaults. You just need to update the descriptions. 2 minutes instead of 20.
209
+
210
+ ## All The Flags (For When You Need Control)
211
+
212
+ ```bash
213
+ envcheck [path] [options]
214
+ ```
215
+
216
+ **The Essentials:**
217
+ - `--env-file <path>` - Check against a different env file (like `.env.production.example`)
218
+ - `--format json` - Output as JSON (for scripts and tools)
219
+ - `--format github` - GitHub Actions annotations (for CI/CD)
220
+ - `--fail-on missing` - Exit with code 1 if issues found (for CI/CD)
221
+
222
+ **The Power User Stuff:**
223
+ - `--watch` - Auto-rerun on file changes (for development)
224
+ - `--fix` - Auto-add missing vars to .env.example (for lazy days)
225
+ - `--repl` - Interactive mode (for exploration)
226
+ - `--config <path>` - Load settings from file (for teams)
227
+ - `--ignore "**/*.test.js"` - Skip certain files (repeatable)
228
+
229
+ **The "Make It Quiet" Options:**
230
+ - `--quiet` - Only show output if there are issues
231
+ - `--no-color` - Plain text (for logs and scripts)
232
+ - `--no-suggestions` - Skip the helpful hints
233
+ - `--no-progress` - No spinners or progress bars
234
+
235
+ **The Obvious Ones:**
236
+ - `--help` - Show help message
237
+ - `--version` - Show version number
238
+
239
+ ## Making It Part of Your Workflow
240
+
241
+ ### The Pre-commit Hook (Catch Issues Before They're Committed)
242
+
243
+ Create `.git/hooks/pre-commit`:
244
+ ```bash
245
+ #!/bin/sh
246
+ envcheck . --fail-on missing --quiet
247
+ ```
248
+
249
+ Now you can't commit code that uses undocumented env vars. Your future self says thanks.
250
+
251
+ ### The GitHub Action (Catch Issues Before They're Merged)
252
+
253
+ Add to `.github/workflows/ci.yml`:
254
+ ```yaml
255
+ - name: Check environment variables
256
+ run: envcheck . --format github --fail-on all
257
+ ```
258
+
259
+ PRs with missing env vars won't pass CI. No more "works on my machine" surprises in production.
260
+
261
+ ### The npm Script (For Your Team)
262
+
263
+ Add to `package.json`:
264
+ ```json
265
+ {
266
+ "scripts": {
267
+ "env:check": "envcheck .",
268
+ "env:watch": "envcheck . --watch",
269
+ "env:fix": "envcheck . --fix",
270
+ "pretest": "envcheck . --fail-on missing"
271
+ }
272
+ }
273
+ ```
274
+
275
+ Now everyone knows how to check env vars. `npm run env:check`. Simple.
276
+
277
+ ### The Docker Build (Fail Fast in Containers)
278
+
279
+ Add to your `Dockerfile`:
280
+ ```dockerfile
281
+ RUN npm install -g envcheck
282
+ RUN envcheck . --fail-on all
283
+ ```
284
+
285
+ If env vars are misconfigured, the build fails. Better to know during build than during deploy.
286
+
287
+ ## Want More?
288
+
289
+ The docs have the deep stuff:
290
+ - [CLI Reference](docs/CLI_REFERENCE.md) - Complete command-line flag documentation
291
+ - [Configuration Guide](docs/CONFIGURATION.md) - All the settings, explained
292
+ - [Examples](docs/EXAMPLES.md) - Real-world use cases and patterns
293
+ - [Integrations](docs/INTEGRATIONS.md) - CI/CD platform setup guides
294
+ - [REPL Guide](docs/REPL.md) - Interactive mode deep dive
295
+ - [Advanced Features](docs/ADVANCED.md) - Plugins, caching, performance tuning
296
+ - [Architecture](docs/ARCHITECTURE.md) - How it works under the hood
297
+
298
+ ## The Bottom Line
299
+
300
+ envcheck started as a simple tool to solve a simple problem: keeping `.env.example` in sync with your code.
301
+
302
+ Then we added a REPL because sometimes you want to explore.
303
+ Then watch mode because developers hate context switching.
304
+ Then auto-fix because typing is tedious.
305
+ Then smart suggestions because typos happen.
306
+ Then config files because teams need consistency.
307
+
308
+ It's still zero dependencies. It's still fast. It's still simple at its core.
309
+
310
+ But now it's also powerful when you need it to be.
311
+
312
+ ---
313
+
314
+ **Pro tip:** Start with just `envcheck`. When you need more, the features are there. When you don't, they stay out of your way.
315
+
316
+ Built with ☕, mild frustration, and the belief that developer tools should be both simple and powerful.
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * envcheck CLI entry point
5
+ *
6
+ * Orchestrates the entire workflow:
7
+ * 1. Parse command-line arguments
8
+ * 2. Load ignore patterns
9
+ * 3. Scan codebase for files
10
+ * 4. Scan files for environment variable references
11
+ * 5. Parse .env.example file
12
+ * 6. Analyze and categorize issues
13
+ * 7. Format and display output
14
+ * 8. Exit with appropriate code
15
+ *
16
+ * REPL Mode:
17
+ * - Run without arguments or with --repl/-r flag to start interactive mode
18
+ */
19
+
20
+ import { run } from '../src/cli.js';
21
+ import { startREPL } from '../src/repl.js';
22
+
23
+ process.on('unhandledRejection', (reason) => {
24
+ const message = reason && reason.message ? reason.message : String(reason);
25
+ console.error(`Unhandled rejection: ${message}`);
26
+ process.exit(2);
27
+ });
28
+
29
+ process.on('uncaughtException', (error) => {
30
+ console.error(`Unhandled exception: ${error.message}`);
31
+ process.exit(2);
32
+ });
33
+
34
+ const args = process.argv.slice(2);
35
+
36
+ // Check for REPL mode
37
+ if (args.length === 0 || args.includes('--repl') || args.includes('-r')) {
38
+ // Remove --repl flag if present
39
+ const replArgs = args.filter(arg => arg !== '--repl' && arg !== '-r');
40
+
41
+ // If no other args, start REPL
42
+ if (replArgs.length === 0) {
43
+ startREPL().catch(error => {
44
+ console.error(`REPL error: ${error.message}`);
45
+ process.exit(2);
46
+ });
47
+ } else {
48
+ // Run command normally
49
+ run(replArgs)
50
+ .then(exitCode => {
51
+ process.exit(exitCode);
52
+ })
53
+ .catch(error => {
54
+ console.error(`Fatal error: ${error.message}`);
55
+ process.exit(2);
56
+ });
57
+ }
58
+ } else {
59
+ // Normal CLI mode
60
+ run(args)
61
+ .then(exitCode => {
62
+ process.exit(exitCode);
63
+ })
64
+ .catch(error => {
65
+ console.error(`Fatal error: ${error.message}`);
66
+ process.exit(2);
67
+ });
68
+ }
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "envprobe",
3
+ "version": "1.0.0",
4
+ "description": "Zero-dependency CLI tool for validating environment variables across codebases",
5
+ "type": "module",
6
+ "bin": {
7
+ "envprobe": "bin/envcheck.js"
8
+ },
9
+ "scripts": {
10
+ "test": "node --test",
11
+ "test:coverage": "node --test --experimental-test-coverage",
12
+ "benchmark": "node benchmarks/benchmark.js"
13
+ },
14
+ "engines": {
15
+ "node": ">=18.0.0"
16
+ },
17
+ "keywords": [
18
+ "cli",
19
+ "environment-variables",
20
+ "env",
21
+ "validation",
22
+ "dotenv",
23
+ "linter",
24
+ "env-check",
25
+ "environment",
26
+ "config",
27
+ "devops",
28
+ "ci-cd"
29
+ ],
30
+ "author": "Bitreon",
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/RealBitreon/envprobe.git"
35
+ },
36
+ "bugs": {
37
+ "url": "https://github.com/RealBitreon/envprobe/issues"
38
+ },
39
+ "homepage": "https://github.com/RealBitreon/envprobe#readme",
40
+ "files": [
41
+ "bin/",
42
+ "src/",
43
+ "LICENSE",
44
+ "README.md"
45
+ ],
46
+ "devDependencies": {
47
+ "fast-check": "^4.6.0"
48
+ }
49
+ }
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Issue Analyzer Module
3
+ *
4
+ * Compares environment variable references from code against definitions
5
+ * in .env.example and categorizes issues into three types:
6
+ * - MISSING: Used in code but absent from .env.example
7
+ * - UNUSED: Defined in .env.example but never referenced
8
+ * - UNDOCUMENTED: Used and defined but lacking inline comments
9
+ */
10
+
11
+ /**
12
+ * Analyzes environment variable usage and categorizes issues
13
+ *
14
+ * @param {Array<{varName: string, filePath: string, lineNumber: number, pattern: string}>} references - Env var references from code
15
+ * @param {Array<{varName: string, hasComment: boolean, comment: string|null, lineNumber: number}>} definitions - Env var definitions from .env.example
16
+ * @returns {{missing: Array, unused: Array, undocumented: Array, summary: Object}} Analysis result
17
+ */
18
+ export function analyzeIssues(references, definitions) {
19
+ // Group references by variable name for efficient lookup
20
+ const refsByVar = groupReferencesByVariable(references);
21
+
22
+ // Create definition lookup map
23
+ const defByVar = createDefinitionMap(definitions);
24
+
25
+ // Get unique variable names from both sources
26
+ const referencedVars = new Set(references.map(ref => ref.varName));
27
+ const definedVars = new Set(definitions.map(def => def.varName));
28
+
29
+ // Detect MISSING variables (used in code but not in .env.example)
30
+ const missing = findMissing(referencedVars, definedVars, refsByVar);
31
+
32
+ // Detect UNUSED variables (in .env.example but never used)
33
+ const unused = findUnused(definedVars, referencedVars, defByVar);
34
+
35
+ // Detect UNDOCUMENTED variables (used and defined but no comment)
36
+ const undocumented = findUndocumented(referencedVars, definedVars, refsByVar, defByVar);
37
+
38
+ // Calculate summary statistics
39
+ const summary = calculateSummary(missing, unused, undocumented, referencedVars, definedVars);
40
+
41
+ return {
42
+ missing,
43
+ unused,
44
+ undocumented,
45
+ summary
46
+ };
47
+ }
48
+
49
+ /**
50
+ * Groups environment variable references by variable name
51
+ *
52
+ * @param {Array<{varName: string, filePath: string, lineNumber: number, pattern: string}>} references
53
+ * @returns {Map<string, Array>} Map of variable name to array of references
54
+ */
55
+ export function groupReferencesByVariable(references) {
56
+ const refsByVar = new Map();
57
+
58
+ for (const ref of references) {
59
+ if (!refsByVar.has(ref.varName)) {
60
+ refsByVar.set(ref.varName, []);
61
+ }
62
+ refsByVar.get(ref.varName).push(ref);
63
+ }
64
+
65
+ return refsByVar;
66
+ }
67
+
68
+ /**
69
+ * Creates a lookup map of definitions by variable name
70
+ *
71
+ * @param {Array<{varName: string, hasComment: boolean, comment: string|null, lineNumber: number}>} definitions
72
+ * @returns {Map<string, Object>} Map of variable name to definition object
73
+ */
74
+ export function createDefinitionMap(definitions) {
75
+ const defByVar = new Map();
76
+
77
+ for (const def of definitions) {
78
+ defByVar.set(def.varName, def);
79
+ }
80
+
81
+ return defByVar;
82
+ }
83
+
84
+ /**
85
+ * Finds MISSING variables (used in code but not in .env.example)
86
+ *
87
+ * @param {Set<string>} referencedVars - Set of variable names used in code
88
+ * @param {Set<string>} definedVars - Set of variable names defined in .env.example
89
+ * @param {Map<string, Array>} refsByVar - Map of variable name to references
90
+ * @returns {Array<{varName: string, references: Array}>} Array of missing variable issues
91
+ */
92
+ export function findMissing(referencedVars, definedVars, refsByVar) {
93
+ const missing = [];
94
+
95
+ for (const varName of referencedVars) {
96
+ if (!definedVars.has(varName)) {
97
+ missing.push({
98
+ varName,
99
+ references: refsByVar.get(varName)
100
+ });
101
+ }
102
+ }
103
+
104
+ // Sort by variable name for consistent output
105
+ return missing.sort((a, b) => a.varName.localeCompare(b.varName));
106
+ }
107
+
108
+ /**
109
+ * Finds UNUSED variables (defined in .env.example but never used)
110
+ *
111
+ * @param {Set<string>} definedVars - Set of variable names defined in .env.example
112
+ * @param {Set<string>} referencedVars - Set of variable names used in code
113
+ * @param {Map<string, Object>} defByVar - Map of variable name to definition
114
+ * @returns {Array<{varName: string, definition: Object}>} Array of unused variable issues
115
+ */
116
+ export function findUnused(definedVars, referencedVars, defByVar) {
117
+ const unused = [];
118
+
119
+ for (const varName of definedVars) {
120
+ if (!referencedVars.has(varName)) {
121
+ unused.push({
122
+ varName,
123
+ definition: defByVar.get(varName)
124
+ });
125
+ }
126
+ }
127
+
128
+ // Sort by variable name for consistent output
129
+ return unused.sort((a, b) => a.varName.localeCompare(b.varName));
130
+ }
131
+
132
+ /**
133
+ * Finds UNDOCUMENTED variables (used and defined but no inline comment)
134
+ *
135
+ * @param {Set<string>} referencedVars - Set of variable names used in code
136
+ * @param {Set<string>} definedVars - Set of variable names defined in .env.example
137
+ * @param {Map<string, Array>} refsByVar - Map of variable name to references
138
+ * @param {Map<string, Object>} defByVar - Map of variable name to definition
139
+ * @returns {Array<{varName: string, references: Array, definition: Object}>} Array of undocumented variable issues
140
+ */
141
+ export function findUndocumented(referencedVars, definedVars, refsByVar, defByVar) {
142
+ const undocumented = [];
143
+
144
+ for (const varName of referencedVars) {
145
+ if (definedVars.has(varName)) {
146
+ const def = defByVar.get(varName);
147
+ if (!def.hasComment) {
148
+ undocumented.push({
149
+ varName,
150
+ references: refsByVar.get(varName),
151
+ definition: def
152
+ });
153
+ }
154
+ }
155
+ }
156
+
157
+ // Sort by variable name for consistent output
158
+ return undocumented.sort((a, b) => a.varName.localeCompare(b.varName));
159
+ }
160
+
161
+ /**
162
+ * Calculates summary statistics for the analysis
163
+ *
164
+ * @param {Array} missing - Array of missing variable issues
165
+ * @param {Array} unused - Array of unused variable issues
166
+ * @param {Array} undocumented - Array of undocumented variable issues
167
+ * @param {Set<string>} referencedVars - Set of variable names used in code
168
+ * @param {Set<string>} definedVars - Set of variable names defined in .env.example
169
+ * @returns {{totalMissing: number, totalUnused: number, totalUndocumented: number, totalReferences: number, totalDefinitions: number}}
170
+ */
171
+ export function calculateSummary(missing, unused, undocumented, referencedVars, definedVars) {
172
+ return {
173
+ totalMissing: missing.length,
174
+ totalUnused: unused.length,
175
+ totalUndocumented: undocumented.length,
176
+ totalReferences: referencedVars.size,
177
+ totalDefinitions: definedVars.size
178
+ };
179
+ }