Report missing and empty required names, duplicate assignment positions and unknown keys under one literal assignment contract. Uses saved stdin text; never reads the real process environment.
Before you start
- Save as audit.js and run with Node.js 22: node audit.js < input.txt. Supply no command-line arguments. The CLI reads only descriptor 0 and requires only node:fs.
- Input consists of selector names, exactly one literal --- separator line, then literal KEY=value assignments. Exactly empty lines and lines starting with # are ignored. Whitespace is never trimmed.
- Keys must match ASCII [A-Za-z_][A-Za-z0-9_]{0,63}. Selectors must be unique. Assignments split at the first equals sign; all remaining characters are literal value content.
- Successful output is exactly one JSON object followed by LF, with missing, empty, duplicates and unknown fields. Key-name arrays and duplicate entries use ASCII key ordering. Duplicate positions are one-based assignment-record ordinals.
- A required key is empty if any of its assignments has an exactly empty value. Unknown names are distinct assigned keys absent from the selectors. Values are never emitted.
- Invalid input, arguments, UTF-8 or stdin reads produce empty stdout, exactly error: invalid input followed by LF on stderr, and exit status 2. Successful execution exits 0 with empty stderr.
- Example stdin: A\nB\n---\nA=\nA=literal\nC=x\n
- Expected example stdout: {"missing":["B"],"empty":["A"],"duplicates":[{"key":"A","positions":[1,2]}],"unknown":["C"]} followed by LF.
Build and check
- Save the example as recipe.cjs.
- Prepare input.txt with selectors, a --- separator and literal assignments; use synthetic values while learning.
- Run the documented command and inspect the JSON output.
- Exit 2 indicates rejected input; no successful JSON result is emitted.
Limits to understand
- Reads at most 65537 bytes total and rejects input longer than 65536 bytes.
- Requires strict UTF-8 without a leading BOM. Rejects ASCII controls other than LF, including CR, NUL and DEL.
- Allows at most 100 selector records and 100 assignment records, counting duplicate assignments separately.
- The combined UTF-8 byte length of every assignment value, including duplicates, must not exceed 1024 bytes.
- This is a literal LF-only protocol, not general dotenv syntax. It performs no interpolation, escaping, quote removal or inline-comment processing.
- No files, environment variables, network resources or subprocesses are accessed by the CLI. Output-write and allocation failures are outside the input-error guarantee.
- Literal assignment subset only; no quoting rules, export syntax, interpolation, multiline values or general dotenv compatibility.
- Key names can themselves be sensitive.
- stdin may block until EOF; input is bounded to 65536 bytes and 100 selector / 100 assignment records. Total assignment-value bytes are limited to 1024.
Run it
node recipe.cjs < input.txtExample input
API_KEY
HOST
PORT
---
HOST=
API_KEY=first
API_KEY=second
EXTRA=x
Expected output
{"missing":["PORT"],"empty":["HOST"],"duplicates":[{"key":"API_KEY","positions":[2,3]}],"unknown":["EXTRA"]}
