env-typed-checker 0.2.1 → 0.2.4
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 +224 -195
- package/bin/env-typed-checker.cjs +3 -2
- package/dist/{chunk-L5DK6LRX.mjs → chunk-CCJEPMPN.mjs} +55 -5
- package/dist/chunk-CCJEPMPN.mjs.map +1 -0
- package/dist/cli/index.js +187 -23
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +134 -20
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.d.mts +11 -3
- package/dist/index.d.ts +11 -3
- package/dist/index.js +54 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +2 -2
- package/dist/chunk-L5DK6LRX.mjs.map +0 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -2,14 +2,24 @@ import {
|
|
|
2
2
|
EnvDoctorError,
|
|
3
3
|
envDoctor,
|
|
4
4
|
normalizeSpec
|
|
5
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-CCJEPMPN.mjs";
|
|
6
6
|
|
|
7
7
|
// src/cli/cli.ts
|
|
8
8
|
import fs from "fs";
|
|
9
9
|
import path from "path";
|
|
10
10
|
import * as dotenv from "dotenv";
|
|
11
|
+
function isCheckOutputFormat(value) {
|
|
12
|
+
return value === "pretty" || value === "json" || value === "github";
|
|
13
|
+
}
|
|
11
14
|
function parseArgs(argv) {
|
|
12
|
-
const out = {
|
|
15
|
+
const out = {
|
|
16
|
+
checkFormat: "pretty",
|
|
17
|
+
useDotenv: true,
|
|
18
|
+
useDefaults: true,
|
|
19
|
+
commentTypes: false,
|
|
20
|
+
commentDocs: false,
|
|
21
|
+
exampleValues: false
|
|
22
|
+
};
|
|
13
23
|
const [cmd, ...rest] = argv;
|
|
14
24
|
out.cmd = cmd;
|
|
15
25
|
for (let i = 0; i < rest.length; i++) {
|
|
@@ -18,7 +28,15 @@ function parseArgs(argv) {
|
|
|
18
28
|
else if (a.startsWith("--schema=")) out.schemaPath = a.split("=", 2)[1];
|
|
19
29
|
else if (a === "--env-file") out.envFile = rest[++i];
|
|
20
30
|
else if (a.startsWith("--env-file=")) out.envFile = a.split("=", 2)[1];
|
|
21
|
-
else if (a === "--
|
|
31
|
+
else if (a === "--format") {
|
|
32
|
+
const f = rest[++i];
|
|
33
|
+
if (isCheckOutputFormat(f)) out.checkFormat = f;
|
|
34
|
+
else out.invalidCheckFormat = String(f);
|
|
35
|
+
} else if (a.startsWith("--format=")) {
|
|
36
|
+
const f = a.slice("--format=".length);
|
|
37
|
+
if (isCheckOutputFormat(f)) out.checkFormat = f;
|
|
38
|
+
else out.invalidCheckFormat = f;
|
|
39
|
+
} else if (a === "--no-dotenv") out.useDotenv = false;
|
|
22
40
|
else if (a === "--out") out.outFile = rest[++i];
|
|
23
41
|
else if (a.startsWith("--out=")) out.outFile = a.split("=", 2)[1];
|
|
24
42
|
else if (a === "--mode") {
|
|
@@ -29,6 +47,8 @@ function parseArgs(argv) {
|
|
|
29
47
|
if (m === "update" || m === "create") out.mode = m;
|
|
30
48
|
} else if (a === "--no-defaults") out.useDefaults = false;
|
|
31
49
|
else if (a === "--comment-types") out.commentTypes = true;
|
|
50
|
+
else if (a === "--comment-docs") out.commentDocs = true;
|
|
51
|
+
else if (a === "--example-values") out.exampleValues = true;
|
|
32
52
|
}
|
|
33
53
|
return out;
|
|
34
54
|
}
|
|
@@ -83,7 +103,22 @@ function formatEnvLine(key, value, comment) {
|
|
|
83
103
|
const safe = needsQuoting(value) ? JSON.stringify(value) : value;
|
|
84
104
|
return comment ? `${key}=${safe} # ${comment}` : `${key}=${safe}`;
|
|
85
105
|
}
|
|
86
|
-
function
|
|
106
|
+
function normalizeCommentText(s) {
|
|
107
|
+
return s.replace(/\r?\n+/g, " ").replace(/\s+/g, " ").trim();
|
|
108
|
+
}
|
|
109
|
+
function getDocCommentLines(description, example) {
|
|
110
|
+
const lines = [];
|
|
111
|
+
if (typeof description === "string") {
|
|
112
|
+
const d = normalizeCommentText(description);
|
|
113
|
+
if (d) lines.push(`# ${d}`);
|
|
114
|
+
}
|
|
115
|
+
if (typeof example === "string") {
|
|
116
|
+
const ex = normalizeCommentText(example);
|
|
117
|
+
if (ex) lines.push(`# example: ${ex}`);
|
|
118
|
+
}
|
|
119
|
+
return lines;
|
|
120
|
+
}
|
|
121
|
+
function runGenerate(schema, outPath, mode, useDefaults, commentTypes, commentDocs, exampleValues, io) {
|
|
87
122
|
const absOut = path.resolve(process.cwd(), outPath);
|
|
88
123
|
if (mode === "create" && fs.existsSync(absOut)) {
|
|
89
124
|
io.error(`Refusing to overwrite existing file: ${outPath}`);
|
|
@@ -92,45 +127,100 @@ function runGenerate(schema, outPath, mode, useDefaults, commentTypes, io) {
|
|
|
92
127
|
const existing = mode === "update" ? readEnvFile(absOut) : {};
|
|
93
128
|
const keys = Object.keys(schema).sort();
|
|
94
129
|
const linesToAdd = [];
|
|
130
|
+
let addedVars = 0;
|
|
95
131
|
for (const key of keys) {
|
|
96
132
|
if (existing[key] !== void 0) continue;
|
|
97
133
|
const spec = schema[key];
|
|
134
|
+
const ns = normalizeSpec(spec);
|
|
98
135
|
const typeLabel = commentTypes ? getTypeLabel(spec) : void 0;
|
|
99
136
|
let val = "";
|
|
100
|
-
if (
|
|
101
|
-
|
|
137
|
+
if (exampleValues && ns.example !== void 0) {
|
|
138
|
+
val = ns.example;
|
|
139
|
+
} else if (useDefaults) {
|
|
102
140
|
if (ns.defaultValue !== void 0) {
|
|
103
141
|
val = defaultToEnvString(ns.defaultValue);
|
|
104
142
|
}
|
|
105
143
|
}
|
|
144
|
+
if (commentDocs) {
|
|
145
|
+
linesToAdd.push(...getDocCommentLines(ns.description, ns.example));
|
|
146
|
+
}
|
|
106
147
|
linesToAdd.push(formatEnvLine(key, val, typeLabel));
|
|
148
|
+
addedVars++;
|
|
107
149
|
}
|
|
108
|
-
if (
|
|
150
|
+
if (addedVars === 0) {
|
|
109
151
|
io.log("\u2705 No missing variables. Nothing to generate.");
|
|
110
152
|
return 0;
|
|
111
153
|
}
|
|
112
154
|
if (mode === "create") {
|
|
113
155
|
fs.writeFileSync(absOut, linesToAdd.join("\n") + "\n", "utf8");
|
|
114
|
-
io.log(`\u2705 Created ${outPath} with ${
|
|
156
|
+
io.log(`\u2705 Created ${outPath} with ${addedVars} variables.`);
|
|
115
157
|
return 0;
|
|
116
158
|
}
|
|
117
159
|
const prefix = fs.existsSync(absOut) ? "\n" : "";
|
|
118
160
|
fs.appendFileSync(absOut, prefix + linesToAdd.join("\n") + "\n", "utf8");
|
|
119
|
-
io.log(
|
|
120
|
-
`\u2705 Updated ${outPath}. Added ${linesToAdd.length} missing variables.`
|
|
121
|
-
);
|
|
161
|
+
io.log(`\u2705 Updated ${outPath}. Added ${addedVars} missing variables.`);
|
|
122
162
|
return 0;
|
|
123
163
|
}
|
|
164
|
+
function redactIssueMessage(message) {
|
|
165
|
+
const sep = ", got ";
|
|
166
|
+
const i = message.indexOf(sep);
|
|
167
|
+
if (i >= 0) {
|
|
168
|
+
return `${message.slice(0, i)}, got "<redacted>"`;
|
|
169
|
+
}
|
|
170
|
+
return `invalid value, got "<redacted>"`;
|
|
171
|
+
}
|
|
172
|
+
function isSecretKey(schema, key) {
|
|
173
|
+
const spec = schema[key];
|
|
174
|
+
if (spec === void 0) return false;
|
|
175
|
+
try {
|
|
176
|
+
const ns = normalizeSpec(spec);
|
|
177
|
+
return ns.secret === true;
|
|
178
|
+
} catch {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function getIssueMessage(issue, schema) {
|
|
183
|
+
const redact = issue.kind === "invalid" && isSecretKey(schema, issue.key);
|
|
184
|
+
return redact ? redactIssueMessage(issue.message) : issue.message;
|
|
185
|
+
}
|
|
186
|
+
function escapeGithubCommandData(value) {
|
|
187
|
+
return value.replace(/%/g, "%25").replace(/\r/g, "%0D").replace(/\n/g, "%0A");
|
|
188
|
+
}
|
|
189
|
+
function escapeGithubCommandProperty(value) {
|
|
190
|
+
return escapeGithubCommandData(value).replace(/:/g, "%3A").replace(/,/g, "%2C");
|
|
191
|
+
}
|
|
192
|
+
function formatValidationErrorForCli(err, schema, format) {
|
|
193
|
+
const issues = err.issues.map((issue) => {
|
|
194
|
+
const message = getIssueMessage(issue, schema);
|
|
195
|
+
return { key: issue.key, kind: issue.kind, message };
|
|
196
|
+
});
|
|
197
|
+
if (format === "github") {
|
|
198
|
+
const title = escapeGithubCommandProperty("ENV validation");
|
|
199
|
+
return issues.map(
|
|
200
|
+
(issue) => `::error title=${title}::${escapeGithubCommandData(`${issue.key}: ${issue.message}`)}`
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
if (format === "json") {
|
|
204
|
+
return [JSON.stringify({ error: "ENV validation failed", issues })];
|
|
205
|
+
}
|
|
206
|
+
const header = "ENV validation failed";
|
|
207
|
+
const lines = issues.map((issue) => `- ${issue.key}: ${issue.message}`);
|
|
208
|
+
return [[header, ...lines].join("\n")];
|
|
209
|
+
}
|
|
124
210
|
function runCli(argv, io = console) {
|
|
125
211
|
const {
|
|
126
212
|
cmd,
|
|
127
213
|
schemaPath,
|
|
128
214
|
envFile,
|
|
215
|
+
checkFormat,
|
|
216
|
+
invalidCheckFormat,
|
|
129
217
|
useDotenv,
|
|
130
218
|
outFile,
|
|
131
219
|
mode,
|
|
132
220
|
useDefaults,
|
|
133
|
-
commentTypes
|
|
221
|
+
commentTypes,
|
|
222
|
+
commentDocs,
|
|
223
|
+
exampleValues
|
|
134
224
|
} = parseArgs(argv);
|
|
135
225
|
if (!cmd || cmd === "help" || cmd === "--help" || cmd === "-h") {
|
|
136
226
|
io.log(
|
|
@@ -138,17 +228,20 @@ function runCli(argv, io = console) {
|
|
|
138
228
|
"env-typed-checker",
|
|
139
229
|
"",
|
|
140
230
|
"Usage:",
|
|
141
|
-
" env-typed-checker check --schema <file> [--env-file <file>] [--no-dotenv]",
|
|
142
|
-
" env-typed-checker generate --schema <file> [--out <file>] [--mode update|create] [--no-defaults] [--comment-types]",
|
|
231
|
+
" env-typed-checker check --schema <file> [--env-file <file>] [--no-dotenv] [--format pretty|json|github]",
|
|
232
|
+
" env-typed-checker generate --schema <file> [--out <file>] [--mode update|create] [--no-defaults] [--comment-types] [--comment-docs] [--example-values]",
|
|
143
233
|
"",
|
|
144
234
|
"Options:",
|
|
145
235
|
" --schema <file> Path to schema JSON (required)",
|
|
146
236
|
" --env-file <file> Env file path (default: .env) [check]",
|
|
147
237
|
" --no-dotenv Do not load env file; use process.env only [check]",
|
|
238
|
+
" --format <name> check output format: pretty|json|github (default: pretty) [check]",
|
|
148
239
|
" --out <file> Output env file (default: .env) [generate]",
|
|
149
240
|
" --mode update|create update appends missing keys; create fails if file exists (default: update)",
|
|
150
241
|
" --no-defaults do not write schema defaults; write empty placeholders [generate]",
|
|
151
242
|
" --comment-types add inline comments with type info [generate]",
|
|
243
|
+
" --comment-docs add description/example comments above each key [generate]",
|
|
244
|
+
" --example-values use schema example values when generating missing keys [generate]",
|
|
152
245
|
"",
|
|
153
246
|
"Exit codes:",
|
|
154
247
|
" 0 = OK, 1 = validation failed, 2 = CLI error"
|
|
@@ -160,26 +253,47 @@ function runCli(argv, io = console) {
|
|
|
160
253
|
io.error("Missing required option: --schema <file>");
|
|
161
254
|
return 2;
|
|
162
255
|
}
|
|
256
|
+
if (cmd === "check" && invalidCheckFormat !== void 0) {
|
|
257
|
+
io.error(
|
|
258
|
+
`Invalid value for --format: "${invalidCheckFormat}". Expected: pretty, json, github`
|
|
259
|
+
);
|
|
260
|
+
return 2;
|
|
261
|
+
}
|
|
163
262
|
try {
|
|
164
263
|
const schema = loadSchema(schemaPath);
|
|
165
264
|
if (cmd === "check") {
|
|
166
265
|
const env = buildEnv(useDotenv, envFile);
|
|
167
|
-
|
|
266
|
+
try {
|
|
267
|
+
envDoctor(schema, { loadDotEnv: false, env });
|
|
268
|
+
} catch (e) {
|
|
269
|
+
if (e instanceof EnvDoctorError) {
|
|
270
|
+
for (const line of formatValidationErrorForCli(e, schema, checkFormat)) {
|
|
271
|
+
io.error(line);
|
|
272
|
+
}
|
|
273
|
+
return 1;
|
|
274
|
+
}
|
|
275
|
+
throw e;
|
|
276
|
+
}
|
|
168
277
|
io.log("\u2705 Environment is valid.");
|
|
169
278
|
return 0;
|
|
170
279
|
}
|
|
171
280
|
if (cmd === "generate") {
|
|
172
281
|
const out = outFile ?? ".env";
|
|
173
282
|
const m = mode ?? "update";
|
|
174
|
-
return runGenerate(
|
|
283
|
+
return runGenerate(
|
|
284
|
+
schema,
|
|
285
|
+
out,
|
|
286
|
+
m,
|
|
287
|
+
useDefaults,
|
|
288
|
+
commentTypes,
|
|
289
|
+
commentDocs,
|
|
290
|
+
exampleValues,
|
|
291
|
+
io
|
|
292
|
+
);
|
|
175
293
|
}
|
|
176
294
|
io.error(`Unknown command: ${cmd}`);
|
|
177
295
|
return 2;
|
|
178
296
|
} catch (e) {
|
|
179
|
-
if (e instanceof EnvDoctorError) {
|
|
180
|
-
io.error(e.message);
|
|
181
|
-
return 1;
|
|
182
|
-
}
|
|
183
297
|
io.error(e instanceof Error ? e.message : String(e));
|
|
184
298
|
return 2;
|
|
185
299
|
}
|
package/dist/cli/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/cli.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport * as dotenv from \"dotenv\";\nimport { envDoctor, EnvDoctorError } from \"../index\";\nimport { normalizeSpec } from \"../validators/primitives\";\nimport type { EnvDoctorSchema, EnvSchemaValue } from \"../types\";\n\ntype Io = {\n log: (msg: string) => void;\n error: (msg: string) => void;\n};\n\nfunction parseArgs(argv: string[]) {\n const out: {\n cmd?: string;\n schemaPath?: string;\n envFile?: string;\n useDotenv: boolean;\n\n // generate options\n outFile?: string;\n mode?: \"update\" | \"create\";\n useDefaults: boolean;\n commentTypes: boolean;\n } = { useDotenv: true, useDefaults: true, commentTypes: false };\n\n const [cmd, ...rest] = argv;\n out.cmd = cmd;\n\n for (let i = 0; i < rest.length; i++) {\n const a = rest[i];\n\n if (a === \"--schema\") out.schemaPath = rest[++i];\n else if (a.startsWith(\"--schema=\")) out.schemaPath = a.split(\"=\", 2)[1];\n else if (a === \"--env-file\") out.envFile = rest[++i];\n else if (a.startsWith(\"--env-file=\")) out.envFile = a.split(\"=\", 2)[1];\n else if (a === \"--no-dotenv\") out.useDotenv = false;\n // generate flags\n else if (a === \"--out\") out.outFile = rest[++i];\n else if (a.startsWith(\"--out=\")) out.outFile = a.split(\"=\", 2)[1];\n else if (a === \"--mode\") {\n const m = rest[++i];\n if (m === \"update\" || m === \"create\") out.mode = m;\n } else if (a.startsWith(\"--mode=\")) {\n const m = a.split(\"=\", 2)[1];\n if (m === \"update\" || m === \"create\") out.mode = m;\n } else if (a === \"--no-defaults\") out.useDefaults = false;\n else if (a === \"--comment-types\") out.commentTypes = true;\n }\n\n return out;\n}\n\nfunction loadSchema(schemaPath: string): EnvDoctorSchema {\n const abs = path.resolve(process.cwd(), schemaPath);\n const raw = fs.readFileSync(abs, \"utf8\");\n\n // Let JSON.parse throw with its native message; CLI catches and prints it\n const json = JSON.parse(raw);\n\n if (!json || typeof json !== \"object\" || Array.isArray(json)) {\n throw new Error(\"Schema must be a JSON object of key -> spec.\");\n }\n\n // Validate using the same core logic (reduces CLI branch complexity a lot)\n for (const [k, v] of Object.entries(json)) {\n try {\n normalizeSpec(v as EnvSchemaValue);\n } catch (e) {\n throw new Error(`Invalid schema value for \"${k}\": ${String(e)}`);\n }\n }\n\n return json as EnvDoctorSchema;\n}\n\nfunction buildEnv(\n useDotenv: boolean,\n envFile?: string,\n): Record<string, string | undefined> {\n const env: Record<string, string | undefined> = { ...process.env };\n\n if (!useDotenv) return env;\n\n const p = envFile ?? \".env\";\n const envAbsPath = path.resolve(process.cwd(), p);\n\n if (fs.existsSync(envAbsPath)) {\n const fileRaw = fs.readFileSync(envAbsPath, \"utf8\");\n const parsed = dotenv.parse(fileRaw);\n Object.assign(env, parsed); // env-file overrides shell env\n }\n\n return env;\n}\n\n// -------- generate helpers --------\n\nfunction readEnvFile(filePath: string): Record<string, string> {\n if (!fs.existsSync(filePath)) return {};\n // allow \"export KEY=...\" lines too\n const raw = fs.readFileSync(filePath, \"utf8\").replace(/^export\\s+/gm, \"\");\n return dotenv.parse(raw);\n}\n\nfunction getTypeLabel(spec: EnvSchemaValue): string {\n // loadSchema() already validates specs are string or object\n if (typeof spec === \"string\") return spec;\n return (spec as any).type as string;\n}\n\nfunction defaultToEnvString(x: unknown): string {\n if (x === undefined || x === null) return \"\";\n if (typeof x === \"string\") return x;\n if (typeof x === \"number\" || typeof x === \"boolean\") return String(x);\n\n // Schema defaults come from JSON => JSON.stringify won't throw and won't return undefined\n return JSON.stringify(x) as string;\n}\n\nfunction needsQuoting(v: string): boolean {\n if (v === \"\") return true;\n return /[\\s#\\n\"']/.test(v);\n}\n\nfunction formatEnvLine(key: string, value: string, comment?: string): string {\n const safe = needsQuoting(value) ? JSON.stringify(value) : value;\n return comment ? `${key}=${safe} # ${comment}` : `${key}=${safe}`;\n}\n\nfunction runGenerate(\n schema: EnvDoctorSchema,\n outPath: string,\n mode: \"update\" | \"create\",\n useDefaults: boolean,\n commentTypes: boolean,\n io: Io,\n): number {\n const absOut = path.resolve(process.cwd(), outPath);\n\n if (mode === \"create\" && fs.existsSync(absOut)) {\n io.error(`Refusing to overwrite existing file: ${outPath}`);\n return 2;\n }\n\n const existing = mode === \"update\" ? readEnvFile(absOut) : {};\n const keys = Object.keys(schema).sort();\n\n const linesToAdd: string[] = [];\n\n for (const key of keys) {\n if (existing[key] !== undefined) continue; // do not overwrite existing values (even empty)\n\n const spec = schema[key];\n const typeLabel = commentTypes ? getTypeLabel(spec) : undefined;\n\n let val = \"\";\n\n if (useDefaults) {\n const ns = normalizeSpec(spec);\n if (ns.defaultValue !== undefined) {\n val = defaultToEnvString(ns.defaultValue);\n }\n }\n\n linesToAdd.push(formatEnvLine(key, val, typeLabel));\n }\n\n if (linesToAdd.length === 0) {\n io.log(\"✅ No missing variables. Nothing to generate.\");\n return 0;\n }\n\n if (mode === \"create\") {\n fs.writeFileSync(absOut, linesToAdd.join(\"\\n\") + \"\\n\", \"utf8\");\n io.log(`✅ Created ${outPath} with ${linesToAdd.length} variables.`);\n return 0;\n }\n\n // update mode: append\n const prefix = fs.existsSync(absOut) ? \"\\n\" : \"\";\n fs.appendFileSync(absOut, prefix + linesToAdd.join(\"\\n\") + \"\\n\", \"utf8\");\n io.log(\n `✅ Updated ${outPath}. Added ${linesToAdd.length} missing variables.`,\n );\n return 0;\n}\n\n// -------- main --------\n\nexport function runCli(argv: string[], io: Io = console): number {\n const {\n cmd,\n schemaPath,\n envFile,\n useDotenv,\n outFile,\n mode,\n useDefaults,\n commentTypes,\n } = parseArgs(argv);\n\n if (!cmd || cmd === \"help\" || cmd === \"--help\" || cmd === \"-h\") {\n io.log(\n [\n \"env-typed-checker\",\n \"\",\n \"Usage:\",\n \" env-typed-checker check --schema <file> [--env-file <file>] [--no-dotenv]\",\n \" env-typed-checker generate --schema <file> [--out <file>] [--mode update|create] [--no-defaults] [--comment-types]\",\n \"\",\n \"Options:\",\n \" --schema <file> Path to schema JSON (required)\",\n \" --env-file <file> Env file path (default: .env) [check]\",\n \" --no-dotenv Do not load env file; use process.env only [check]\",\n \" --out <file> Output env file (default: .env) [generate]\",\n \" --mode update|create update appends missing keys; create fails if file exists (default: update)\",\n \" --no-defaults do not write schema defaults; write empty placeholders [generate]\",\n \" --comment-types add inline comments with type info [generate]\",\n \"\",\n \"Exit codes:\",\n \" 0 = OK, 1 = validation failed, 2 = CLI error\",\n ].join(\"\\n\"),\n );\n return 0;\n }\n\n if (!schemaPath) {\n io.error(\"Missing required option: --schema <file>\");\n return 2;\n }\n\n try {\n const schema = loadSchema(schemaPath);\n\n if (cmd === \"check\") {\n const env = buildEnv(useDotenv, envFile);\n envDoctor(schema, { loadDotEnv: false, env });\n io.log(\"✅ Environment is valid.\");\n return 0;\n }\n\n if (cmd === \"generate\") {\n const out = outFile ?? \".env\";\n const m = mode ?? \"update\";\n return runGenerate(schema, out, m, useDefaults, commentTypes, io);\n }\n\n io.error(`Unknown command: ${cmd}`);\n return 2;\n } catch (e) {\n if (e instanceof EnvDoctorError) {\n io.error(e.message);\n return 1;\n }\n io.error(e instanceof Error ? e.message : String(e));\n return 2;\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/cli.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport * as dotenv from \"dotenv\";\nimport { envDoctor, EnvDoctorError } from \"../index\";\nimport { normalizeSpec } from \"../validators/primitives\";\nimport type { EnvDoctorSchema, EnvSchemaValue } from \"../types\";\n\ntype Io = {\n log: (msg: string) => void;\n error: (msg: string) => void;\n};\n\ntype CheckOutputFormat = \"pretty\" | \"json\" | \"github\";\n\nfunction isCheckOutputFormat(value: unknown): value is CheckOutputFormat {\n return value === \"pretty\" || value === \"json\" || value === \"github\";\n}\n\nfunction parseArgs(argv: string[]) {\n const out: {\n cmd?: string;\n schemaPath?: string;\n envFile?: string;\n checkFormat: CheckOutputFormat;\n invalidCheckFormat?: string;\n useDotenv: boolean;\n\n // generate options\n outFile?: string;\n mode?: \"update\" | \"create\";\n useDefaults: boolean;\n commentTypes: boolean;\n commentDocs: boolean;\n exampleValues: boolean;\n } = {\n checkFormat: \"pretty\",\n useDotenv: true,\n useDefaults: true,\n commentTypes: false,\n commentDocs: false,\n exampleValues: false,\n };\n\n const [cmd, ...rest] = argv;\n out.cmd = cmd;\n\n for (let i = 0; i < rest.length; i++) {\n const a = rest[i];\n\n if (a === \"--schema\") out.schemaPath = rest[++i];\n else if (a.startsWith(\"--schema=\")) out.schemaPath = a.split(\"=\", 2)[1];\n else if (a === \"--env-file\") out.envFile = rest[++i];\n else if (a.startsWith(\"--env-file=\")) out.envFile = a.split(\"=\", 2)[1];\n else if (a === \"--format\") {\n const f = rest[++i];\n if (isCheckOutputFormat(f)) out.checkFormat = f;\n else out.invalidCheckFormat = String(f);\n } else if (a.startsWith(\"--format=\")) {\n const f = a.slice(\"--format=\".length);\n if (isCheckOutputFormat(f)) out.checkFormat = f;\n else out.invalidCheckFormat = f;\n }\n else if (a === \"--no-dotenv\") out.useDotenv = false;\n // generate flags\n else if (a === \"--out\") out.outFile = rest[++i];\n else if (a.startsWith(\"--out=\")) out.outFile = a.split(\"=\", 2)[1];\n else if (a === \"--mode\") {\n const m = rest[++i];\n if (m === \"update\" || m === \"create\") out.mode = m;\n } else if (a.startsWith(\"--mode=\")) {\n const m = a.split(\"=\", 2)[1];\n if (m === \"update\" || m === \"create\") out.mode = m;\n } else if (a === \"--no-defaults\") out.useDefaults = false;\n else if (a === \"--comment-types\") out.commentTypes = true;\n else if (a === \"--comment-docs\") out.commentDocs = true;\n else if (a === \"--example-values\") out.exampleValues = true;\n }\n\n return out;\n}\n\nfunction loadSchema(schemaPath: string): EnvDoctorSchema {\n const abs = path.resolve(process.cwd(), schemaPath);\n const raw = fs.readFileSync(abs, \"utf8\");\n\n // Let JSON.parse throw with its native message; CLI catches and prints it\n const json = JSON.parse(raw);\n\n if (!json || typeof json !== \"object\" || Array.isArray(json)) {\n throw new Error(\"Schema must be a JSON object of key -> spec.\");\n }\n\n // Validate using the same core logic (reduces CLI branch complexity a lot)\n for (const [k, v] of Object.entries(json)) {\n try {\n normalizeSpec(v as EnvSchemaValue);\n } catch (e) {\n throw new Error(`Invalid schema value for \"${k}\": ${String(e)}`);\n }\n }\n\n return json as EnvDoctorSchema;\n}\n\nfunction buildEnv(\n useDotenv: boolean,\n envFile?: string,\n): Record<string, string | undefined> {\n const env: Record<string, string | undefined> = { ...process.env };\n\n if (!useDotenv) return env;\n\n const p = envFile ?? \".env\";\n const envAbsPath = path.resolve(process.cwd(), p);\n\n if (fs.existsSync(envAbsPath)) {\n const fileRaw = fs.readFileSync(envAbsPath, \"utf8\");\n const parsed = dotenv.parse(fileRaw);\n Object.assign(env, parsed); // env-file overrides shell env\n }\n\n return env;\n}\n\n// -------- generate helpers --------\n\nfunction readEnvFile(filePath: string): Record<string, string> {\n if (!fs.existsSync(filePath)) return {};\n // allow \"export KEY=...\" lines too\n const raw = fs.readFileSync(filePath, \"utf8\").replace(/^export\\s+/gm, \"\");\n return dotenv.parse(raw);\n}\n\nfunction getTypeLabel(spec: EnvSchemaValue): string {\n // loadSchema() already validates specs are string or object\n if (typeof spec === \"string\") return spec;\n return (spec as any).type as string;\n}\n\nfunction defaultToEnvString(x: unknown): string {\n if (x === undefined || x === null) return \"\";\n if (typeof x === \"string\") return x;\n if (typeof x === \"number\" || typeof x === \"boolean\") return String(x);\n\n // Schema defaults come from JSON => JSON.stringify won't throw and won't return undefined\n return JSON.stringify(x) as string;\n}\n\nfunction needsQuoting(v: string): boolean {\n if (v === \"\") return true;\n return /[\\s#\\n\"']/.test(v);\n}\n\nfunction formatEnvLine(key: string, value: string, comment?: string): string {\n const safe = needsQuoting(value) ? JSON.stringify(value) : value;\n return comment ? `${key}=${safe} # ${comment}` : `${key}=${safe}`;\n}\n\nfunction normalizeCommentText(s: string): string {\n return s\n .replace(/\\r?\\n+/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\nfunction getDocCommentLines(description?: string, example?: string): string[] {\n const lines: string[] = [];\n\n if (typeof description === \"string\") {\n const d = normalizeCommentText(description);\n if (d) lines.push(`# ${d}`);\n }\n\n if (typeof example === \"string\") {\n const ex = normalizeCommentText(example);\n if (ex) lines.push(`# example: ${ex}`);\n }\n\n return lines;\n}\n\nfunction runGenerate(\n schema: EnvDoctorSchema,\n outPath: string,\n mode: \"update\" | \"create\",\n useDefaults: boolean,\n commentTypes: boolean,\n commentDocs: boolean,\n exampleValues: boolean,\n io: Io,\n): number {\n const absOut = path.resolve(process.cwd(), outPath);\n\n if (mode === \"create\" && fs.existsSync(absOut)) {\n io.error(`Refusing to overwrite existing file: ${outPath}`);\n return 2;\n }\n\n const existing = mode === \"update\" ? readEnvFile(absOut) : {};\n const keys = Object.keys(schema).sort();\n\n const linesToAdd: string[] = [];\n let addedVars = 0;\n\n for (const key of keys) {\n if (existing[key] !== undefined) continue; // do not overwrite existing values (even empty)\n\n const spec = schema[key];\n const ns = normalizeSpec(spec);\n const typeLabel = commentTypes ? getTypeLabel(spec) : undefined;\n\n let val = \"\";\n\n if (exampleValues && ns.example !== undefined) {\n val = ns.example;\n } else if (useDefaults) {\n if (ns.defaultValue !== undefined) {\n val = defaultToEnvString(ns.defaultValue);\n }\n }\n\n if (commentDocs) {\n linesToAdd.push(...getDocCommentLines(ns.description, ns.example));\n }\n\n linesToAdd.push(formatEnvLine(key, val, typeLabel));\n addedVars++;\n }\n\n if (addedVars === 0) {\n io.log(\"✅ No missing variables. Nothing to generate.\");\n return 0;\n }\n\n if (mode === \"create\") {\n fs.writeFileSync(absOut, linesToAdd.join(\"\\n\") + \"\\n\", \"utf8\");\n io.log(`✅ Created ${outPath} with ${addedVars} variables.`);\n return 0;\n }\n\n // update mode: append\n const prefix = fs.existsSync(absOut) ? \"\\n\" : \"\";\n fs.appendFileSync(absOut, prefix + linesToAdd.join(\"\\n\") + \"\\n\", \"utf8\");\n io.log(`✅ Updated ${outPath}. Added ${addedVars} missing variables.`);\n return 0;\n}\n\nfunction redactIssueMessage(message: string): string {\n const sep = \", got \";\n const i = message.indexOf(sep);\n if (i >= 0) {\n return `${message.slice(0, i)}, got \"<redacted>\"`;\n }\n return `invalid value, got \"<redacted>\"`;\n}\n\nfunction isSecretKey(schema: EnvDoctorSchema, key: string): boolean {\n const spec = schema[key];\n if (spec === undefined) return false;\n\n try {\n const ns = normalizeSpec(spec);\n return ns.secret === true;\n } catch {\n return false;\n }\n}\n\nfunction getIssueMessage(\n issue: EnvDoctorError[\"issues\"][number],\n schema: EnvDoctorSchema,\n): string {\n const redact = issue.kind === \"invalid\" && isSecretKey(schema, issue.key);\n return redact ? redactIssueMessage(issue.message) : issue.message;\n}\n\nfunction escapeGithubCommandData(value: string): string {\n return value.replace(/%/g, \"%25\").replace(/\\r/g, \"%0D\").replace(/\\n/g, \"%0A\");\n}\n\nfunction escapeGithubCommandProperty(value: string): string {\n return escapeGithubCommandData(value)\n .replace(/:/g, \"%3A\")\n .replace(/,/g, \"%2C\");\n}\n\nfunction formatValidationErrorForCli(\n err: EnvDoctorError,\n schema: EnvDoctorSchema,\n format: CheckOutputFormat,\n): string[] {\n const issues = err.issues.map((issue) => {\n const message = getIssueMessage(issue, schema);\n return { key: issue.key, kind: issue.kind, message };\n });\n\n if (format === \"github\") {\n const title = escapeGithubCommandProperty(\"ENV validation\");\n return issues.map(\n (issue) =>\n `::error title=${title}::${escapeGithubCommandData(`${issue.key}: ${issue.message}`)}`,\n );\n }\n\n if (format === \"json\") {\n return [JSON.stringify({ error: \"ENV validation failed\", issues })];\n }\n\n const header = \"ENV validation failed\";\n const lines = issues.map((issue) => `- ${issue.key}: ${issue.message}`);\n return [[header, ...lines].join(\"\\n\")];\n}\n\n// -------- main --------\n\nexport function runCli(argv: string[], io: Io = console): number {\n const {\n cmd,\n schemaPath,\n envFile,\n checkFormat,\n invalidCheckFormat,\n useDotenv,\n outFile,\n mode,\n useDefaults,\n commentTypes,\n commentDocs,\n exampleValues,\n } = parseArgs(argv);\n\n if (!cmd || cmd === \"help\" || cmd === \"--help\" || cmd === \"-h\") {\n io.log(\n [\n \"env-typed-checker\",\n \"\",\n \"Usage:\",\n \" env-typed-checker check --schema <file> [--env-file <file>] [--no-dotenv] [--format pretty|json|github]\",\n \" env-typed-checker generate --schema <file> [--out <file>] [--mode update|create] [--no-defaults] [--comment-types] [--comment-docs] [--example-values]\",\n \"\",\n \"Options:\",\n \" --schema <file> Path to schema JSON (required)\",\n \" --env-file <file> Env file path (default: .env) [check]\",\n \" --no-dotenv Do not load env file; use process.env only [check]\",\n \" --format <name> check output format: pretty|json|github (default: pretty) [check]\",\n \" --out <file> Output env file (default: .env) [generate]\",\n \" --mode update|create update appends missing keys; create fails if file exists (default: update)\",\n \" --no-defaults do not write schema defaults; write empty placeholders [generate]\",\n \" --comment-types add inline comments with type info [generate]\",\n \" --comment-docs add description/example comments above each key [generate]\",\n \" --example-values use schema example values when generating missing keys [generate]\",\n \"\",\n \"Exit codes:\",\n \" 0 = OK, 1 = validation failed, 2 = CLI error\",\n ].join(\"\\n\"),\n );\n return 0;\n }\n\n if (!schemaPath) {\n io.error(\"Missing required option: --schema <file>\");\n return 2;\n }\n\n if (cmd === \"check\" && invalidCheckFormat !== undefined) {\n io.error(\n `Invalid value for --format: \"${invalidCheckFormat}\". Expected: pretty, json, github`,\n );\n return 2;\n }\n\n try {\n const schema = loadSchema(schemaPath);\n\n if (cmd === \"check\") {\n const env = buildEnv(useDotenv, envFile);\n try {\n envDoctor(schema, { loadDotEnv: false, env });\n } catch (e) {\n if (e instanceof EnvDoctorError) {\n for (const line of formatValidationErrorForCli(e, schema, checkFormat)) {\n io.error(line);\n }\n return 1;\n }\n throw e;\n }\n io.log(\"✅ Environment is valid.\");\n return 0;\n }\n\n if (cmd === \"generate\") {\n const out = outFile ?? \".env\";\n const m = mode ?? \"update\";\n return runGenerate(\n schema,\n out,\n m,\n useDefaults,\n commentTypes,\n commentDocs,\n exampleValues,\n io,\n );\n }\n\n io.error(`Unknown command: ${cmd}`);\n return 2;\n } catch (e) {\n io.error(e instanceof Error ? e.message : String(e));\n return 2;\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,21 +1,29 @@
|
|
|
1
1
|
type EnvBaseType = "string" | "number" | "boolean" | "json" | "url" | "email";
|
|
2
2
|
type EnvStringSpec = EnvBaseType | `${EnvBaseType}?`;
|
|
3
|
+
type EnvSpecMeta = {
|
|
4
|
+
/** Human-readable description used by docs / .env.example generation */
|
|
5
|
+
description?: string;
|
|
6
|
+
/** Example string value used by docs / optional generation */
|
|
7
|
+
example?: string;
|
|
8
|
+
/** Marks sensitive values (CLI check redacts invalid raw values) */
|
|
9
|
+
secret?: boolean;
|
|
10
|
+
};
|
|
3
11
|
type EnumSpec<T extends readonly string[] = readonly string[]> = {
|
|
4
12
|
type: "enum";
|
|
5
13
|
values: T;
|
|
6
14
|
optional?: boolean;
|
|
7
|
-
};
|
|
15
|
+
} & EnvSpecMeta;
|
|
8
16
|
type RegexSpec = {
|
|
9
17
|
type: "regex";
|
|
10
18
|
pattern: string;
|
|
11
19
|
flags?: string;
|
|
12
20
|
optional?: boolean;
|
|
13
|
-
};
|
|
21
|
+
} & EnvSpecMeta;
|
|
14
22
|
type PrimitiveObjectSpec = {
|
|
15
23
|
type: EnvBaseType;
|
|
16
24
|
optional?: boolean;
|
|
17
25
|
default?: unknown;
|
|
18
|
-
};
|
|
26
|
+
} & EnvSpecMeta;
|
|
19
27
|
type EnvSchemaValue = EnvStringSpec | EnumSpec | RegexSpec | PrimitiveObjectSpec;
|
|
20
28
|
type EnvDoctorSchema = Record<string, EnvSchemaValue>;
|
|
21
29
|
type EnvDoctorOptions = {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,21 +1,29 @@
|
|
|
1
1
|
type EnvBaseType = "string" | "number" | "boolean" | "json" | "url" | "email";
|
|
2
2
|
type EnvStringSpec = EnvBaseType | `${EnvBaseType}?`;
|
|
3
|
+
type EnvSpecMeta = {
|
|
4
|
+
/** Human-readable description used by docs / .env.example generation */
|
|
5
|
+
description?: string;
|
|
6
|
+
/** Example string value used by docs / optional generation */
|
|
7
|
+
example?: string;
|
|
8
|
+
/** Marks sensitive values (CLI check redacts invalid raw values) */
|
|
9
|
+
secret?: boolean;
|
|
10
|
+
};
|
|
3
11
|
type EnumSpec<T extends readonly string[] = readonly string[]> = {
|
|
4
12
|
type: "enum";
|
|
5
13
|
values: T;
|
|
6
14
|
optional?: boolean;
|
|
7
|
-
};
|
|
15
|
+
} & EnvSpecMeta;
|
|
8
16
|
type RegexSpec = {
|
|
9
17
|
type: "regex";
|
|
10
18
|
pattern: string;
|
|
11
19
|
flags?: string;
|
|
12
20
|
optional?: boolean;
|
|
13
|
-
};
|
|
21
|
+
} & EnvSpecMeta;
|
|
14
22
|
type PrimitiveObjectSpec = {
|
|
15
23
|
type: EnvBaseType;
|
|
16
24
|
optional?: boolean;
|
|
17
25
|
default?: unknown;
|
|
18
|
-
};
|
|
26
|
+
} & EnvSpecMeta;
|
|
19
27
|
type EnvSchemaValue = EnvStringSpec | EnumSpec | RegexSpec | PrimitiveObjectSpec;
|
|
20
28
|
type EnvDoctorSchema = Record<string, EnvSchemaValue>;
|
|
21
29
|
type EnvDoctorOptions = {
|
package/dist/index.js
CHANGED
|
@@ -139,6 +139,33 @@ function coerceDefault(kind, def) {
|
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
|
+
function normalizeMeta(schemaValue) {
|
|
143
|
+
let description = void 0;
|
|
144
|
+
if (hasOwn(schemaValue, "description")) {
|
|
145
|
+
const d = schemaValue.description;
|
|
146
|
+
if (d !== void 0 && typeof d !== "string") {
|
|
147
|
+
throw new Error(`"description" must be a string if provided`);
|
|
148
|
+
}
|
|
149
|
+
description = d;
|
|
150
|
+
}
|
|
151
|
+
let example = void 0;
|
|
152
|
+
if (hasOwn(schemaValue, "example")) {
|
|
153
|
+
const ex = schemaValue.example;
|
|
154
|
+
if (ex !== void 0 && typeof ex !== "string") {
|
|
155
|
+
throw new Error(`"example" must be a string if provided`);
|
|
156
|
+
}
|
|
157
|
+
example = ex;
|
|
158
|
+
}
|
|
159
|
+
let secret = false;
|
|
160
|
+
if (hasOwn(schemaValue, "secret")) {
|
|
161
|
+
const s = schemaValue.secret;
|
|
162
|
+
if (s !== void 0 && typeof s !== "boolean") {
|
|
163
|
+
throw new Error(`"secret" must be a boolean if provided`);
|
|
164
|
+
}
|
|
165
|
+
secret = s === true;
|
|
166
|
+
}
|
|
167
|
+
return { description, example, secret };
|
|
168
|
+
}
|
|
142
169
|
function normalizeSpec(schemaValue) {
|
|
143
170
|
if (typeof schemaValue === "string") {
|
|
144
171
|
const optional = schemaValue.endsWith("?");
|
|
@@ -156,12 +183,17 @@ function normalizeSpec(schemaValue) {
|
|
|
156
183
|
`Unsupported type "${schemaValue}". Supported: string, number, boolean, json, url, email (optional with ?)`
|
|
157
184
|
);
|
|
158
185
|
}
|
|
159
|
-
return {
|
|
186
|
+
return {
|
|
187
|
+
kind: base,
|
|
188
|
+
optional,
|
|
189
|
+
secret: false
|
|
190
|
+
};
|
|
160
191
|
}
|
|
161
192
|
if (!schemaValue || typeof schemaValue !== "object" || Array.isArray(schemaValue)) {
|
|
162
193
|
throw new Error("Schema value must be a string or object spec.");
|
|
163
194
|
}
|
|
164
195
|
const t = schemaValue.type;
|
|
196
|
+
const meta = normalizeMeta(schemaValue);
|
|
165
197
|
const primitiveAllowed = [
|
|
166
198
|
"string",
|
|
167
199
|
"number",
|
|
@@ -173,7 +205,12 @@ function normalizeSpec(schemaValue) {
|
|
|
173
205
|
if (primitiveAllowed.includes(t)) {
|
|
174
206
|
const optional = !!schemaValue.optional;
|
|
175
207
|
const defaultValue = hasOwn(schemaValue, "default") ? coerceDefault(t, schemaValue.default) : void 0;
|
|
176
|
-
return {
|
|
208
|
+
return {
|
|
209
|
+
kind: t,
|
|
210
|
+
optional,
|
|
211
|
+
defaultValue,
|
|
212
|
+
...meta
|
|
213
|
+
};
|
|
177
214
|
}
|
|
178
215
|
if (t === "enum") {
|
|
179
216
|
const values = schemaValue.values;
|
|
@@ -194,7 +231,13 @@ function normalizeSpec(schemaValue) {
|
|
|
194
231
|
}
|
|
195
232
|
defaultValue = def;
|
|
196
233
|
}
|
|
197
|
-
return {
|
|
234
|
+
return {
|
|
235
|
+
kind: "enum",
|
|
236
|
+
optional,
|
|
237
|
+
values,
|
|
238
|
+
defaultValue,
|
|
239
|
+
...meta
|
|
240
|
+
};
|
|
198
241
|
}
|
|
199
242
|
if (t === "regex") {
|
|
200
243
|
const pattern = schemaValue.pattern;
|
|
@@ -224,7 +267,14 @@ function normalizeSpec(schemaValue) {
|
|
|
224
267
|
}
|
|
225
268
|
defaultValue = def;
|
|
226
269
|
}
|
|
227
|
-
return {
|
|
270
|
+
return {
|
|
271
|
+
kind: "regex",
|
|
272
|
+
optional,
|
|
273
|
+
re,
|
|
274
|
+
display,
|
|
275
|
+
defaultValue,
|
|
276
|
+
...meta
|
|
277
|
+
};
|
|
228
278
|
}
|
|
229
279
|
throw new Error(
|
|
230
280
|
`Unsupported object spec type "${String(t)}". Supported: primitives (string/number/boolean/json/url/email), enum, regex`
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/core/envDoctor.ts","../src/errors/EnvDoctorError.ts","../src/validators/primitives.ts","../src/core/runner.ts"],"sourcesContent":["export { envDoctor } from \"./core/envDoctor\";\n\nexport type { EnvDoctorOptions, EnvDoctorSchema } from \"./types\";\n\nexport { EnvDoctorError } from \"./errors/EnvDoctorError\";\n","import * as dotenv from \"dotenv\";\nimport { validateAndParse } from \"./runner\";\nimport type { EnvDoctorOptions, EnvDoctorResult, EnvDoctorSchema } from \"../types\";\n\nexport type { EnvDoctorOptions, EnvDoctorSchema } from \"../types\";\nexport { EnvDoctorError } from \"../errors/EnvDoctorError\";\n\nexport function envDoctor<TSchema extends EnvDoctorSchema>(\n schema: TSchema,\n options: EnvDoctorOptions = {}\n): EnvDoctorResult<TSchema> {\n const { loadDotEnv = true, env = process.env } = options;\n\n if (loadDotEnv) dotenv.config();\n\n return validateAndParse(schema, env);\n}\n","export type EnvDoctorIssue =\n | { key: string; kind: \"missing\"; message: string }\n | { key: string; kind: \"invalid\"; message: string };\n\nexport class EnvDoctorError extends Error {\n public readonly issues: EnvDoctorIssue[];\n\n constructor(issues: EnvDoctorIssue[]) {\n const header = \"ENV validation failed\";\n const lines = issues.map((i) => `- ${i.key}: ${i.message}`);\n super([header, ...lines].join(\"\\n\"));\n this.name = \"EnvDoctorError\";\n this.issues = issues;\n }\n}\n","import type { EnvBaseType, EnvSchemaValue } from \"../types\";\n\nconst EMAIL_RE = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\nexport function parseByType(type: EnvBaseType, raw: string): unknown {\n switch (type) {\n case \"string\":\n return raw;\n\n case \"number\": {\n const n = Number(raw.trim());\n if (!Number.isFinite(n)) throw new Error(`expected number, got \"${raw}\"`);\n return n;\n }\n\n case \"boolean\": {\n const v = raw.trim().toLowerCase();\n if ([\"true\", \"1\", \"yes\", \"y\", \"on\"].includes(v)) return true;\n if ([\"false\", \"0\", \"no\", \"n\", \"off\"].includes(v)) return false;\n throw new Error(\n `expected boolean (true/false/1/0/yes/no/on/off), got \"${raw}\"`,\n );\n }\n\n case \"json\": {\n try {\n return JSON.parse(raw);\n } catch {\n throw new Error(`expected json, got \"${raw}\"`);\n }\n }\n\n case \"url\": {\n try {\n new URL(raw);\n return raw;\n } catch {\n throw new Error(`expected url, got \"${raw}\"`);\n }\n }\n\n case \"email\": {\n const s = raw.trim();\n if (!EMAIL_RE.test(s)) {\n throw new Error(`expected email, got \"${raw}\"`);\n }\n return s;\n }\n\n default: {\n throw new Error(`unsupported primitive type: ${String(type)}`);\n }\n }\n}\n\nfunction hasOwn(obj: unknown, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\n\n/**\n * Type-check + normalize a default value into the right runtime type.\n * - Allows string defaults for number/boolean (parsed)\n * - Validates url/email defaults\n * - json defaults can be any value\n */\nfunction coerceDefault(kind: EnvBaseType, def: unknown): unknown {\n if (def === undefined) return undefined;\n\n switch (kind) {\n case \"string\": {\n if (typeof def !== \"string\")\n throw new Error(`default for string must be a string`);\n return def;\n }\n\n case \"number\": {\n if (typeof def === \"number\") {\n if (!Number.isFinite(def))\n throw new Error(`default for number must be finite`);\n return def;\n }\n if (typeof def === \"string\") return parseByType(\"number\", def);\n throw new Error(`default for number must be number or string`);\n }\n\n case \"boolean\": {\n if (typeof def === \"boolean\") return def;\n if (typeof def === \"string\") return parseByType(\"boolean\", def);\n throw new Error(`default for boolean must be boolean or string`);\n }\n\n case \"json\": {\n // allow any JSON-ish value\n return def;\n }\n\n case \"url\": {\n if (typeof def !== \"string\")\n throw new Error(`default for url must be a string`);\n return parseByType(\"url\", def);\n }\n\n case \"email\": {\n if (typeof def !== \"string\")\n throw new Error(`default for email must be a string`);\n return parseByType(\"email\", def);\n }\n\n /* c8 ignore next */\n default: {\n throw new Error(`unsupported default kind: ${String(kind)}`);\n }\n }\n}\n\n/** Normalized spec used by the runner */\nexport type NormalizedSpec =\n | { kind: EnvBaseType; optional: boolean; defaultValue?: unknown }\n | {\n kind: \"enum\";\n optional: boolean;\n values: readonly string[];\n defaultValue?: string;\n }\n | {\n kind: \"regex\";\n optional: boolean;\n re: RegExp;\n display: string;\n defaultValue?: string;\n };\n\nexport function normalizeSpec(schemaValue: EnvSchemaValue): NormalizedSpec {\n // --------------------\n // String style: \"number?\" etc.\n // --------------------\n if (typeof schemaValue === \"string\") {\n const optional = schemaValue.endsWith(\"?\");\n const base = optional ? schemaValue.slice(0, -1) : schemaValue;\n\n const allowed: readonly EnvBaseType[] = [\n \"string\",\n \"number\",\n \"boolean\",\n \"json\",\n \"url\",\n \"email\",\n ];\n\n if (!allowed.includes(base as EnvBaseType)) {\n throw new Error(\n `Unsupported type \"${schemaValue}\". Supported: string, number, boolean, json, url, email (optional with ?)`,\n );\n }\n\n return { kind: base as EnvBaseType, optional };\n }\n\n // --------------------\n // Object style\n // --------------------\n if (\n !schemaValue ||\n typeof schemaValue !== \"object\" ||\n Array.isArray(schemaValue)\n ) {\n throw new Error(\"Schema value must be a string or object spec.\");\n }\n\n const t = (schemaValue as any).type;\n\n // --------------------\n // Primitive object spec: { type: \"number\", optional?: true, default?: ... }\n // --------------------\n const primitiveAllowed: readonly EnvBaseType[] = [\n \"string\",\n \"number\",\n \"boolean\",\n \"json\",\n \"url\",\n \"email\",\n ];\n\n if (primitiveAllowed.includes(t)) {\n const optional = !!(schemaValue as any).optional;\n const defaultValue = hasOwn(schemaValue, \"default\")\n ? coerceDefault(t as EnvBaseType, (schemaValue as any).default)\n : undefined;\n\n return { kind: t as EnvBaseType, optional, defaultValue };\n }\n\n // --------------------\n // Enum: { type: \"enum\", values: [...], optional?: true, default?: \"dev\" }\n // --------------------\n if (t === \"enum\") {\n const values = (schemaValue as any).values;\n if (\n !Array.isArray(values) ||\n values.length === 0 ||\n !values.every((v: any) => typeof v === \"string\")\n ) {\n throw new Error(`enum spec requires \"values\": string[] (non-empty)`);\n }\n\n const optional = !!(schemaValue as any).optional;\n\n let defaultValue: string | undefined = undefined;\n if (hasOwn(schemaValue, \"default\")) {\n const def = (schemaValue as any).default;\n if (typeof def !== \"string\") {\n throw new Error(`default for enum must be a string`);\n }\n if (!values.includes(def)) {\n throw new Error(\n `default \"${def}\" must be one of [${values.join(\", \")}]`,\n );\n }\n defaultValue = def;\n }\n\n return { kind: \"enum\", optional, values, defaultValue };\n }\n\n // --------------------\n // Regex: { type: \"regex\", pattern: \"...\", flags?: \"...\", optional?: true, default?: \"abc\" }\n // --------------------\n if (t === \"regex\") {\n const pattern = (schemaValue as any).pattern;\n const flags = (schemaValue as any).flags;\n\n if (typeof pattern !== \"string\" || pattern.length === 0) {\n throw new Error(`regex spec requires \"pattern\": string`);\n }\n if (flags !== undefined && typeof flags !== \"string\") {\n throw new Error(`regex spec \"flags\" must be a string if provided`);\n }\n\n let re: RegExp;\n try {\n re = new RegExp(pattern, flags);\n } catch (e) {\n throw new Error(`invalid regex: ${String(e)}`);\n }\n\n const display = `/${pattern}/${flags ?? \"\"}`;\n const optional = !!(schemaValue as any).optional;\n\n let defaultValue: string | undefined = undefined;\n if (hasOwn(schemaValue, \"default\")) {\n const def = (schemaValue as any).default;\n if (typeof def !== \"string\") {\n throw new Error(`default for regex must be a string`);\n }\n if (!re.test(def)) {\n throw new Error(`default \"${def}\" does not match ${display}`);\n }\n defaultValue = def;\n }\n\n return { kind: \"regex\", optional, re, display, defaultValue };\n }\n\n throw new Error(\n `Unsupported object spec type \"${String(t)}\". Supported: primitives (string/number/boolean/json/url/email), enum, regex`,\n );\n}\n","import { EnvDoctorError, type EnvDoctorIssue } from \"../errors/EnvDoctorError\";\nimport { normalizeSpec, parseByType } from \"../validators/primitives\";\nimport type { EnvDoctorResult, EnvDoctorSchema } from \"../types\";\n\nexport function validateAndParse<TSchema extends EnvDoctorSchema>(\n schema: TSchema,\n env: Record<string, string | undefined>,\n): EnvDoctorResult<TSchema> {\n const issues: EnvDoctorIssue[] = [];\n const out: Record<string, unknown> = {};\n\n for (const [key, schemaValue] of Object.entries(schema)) {\n let spec: ReturnType<typeof normalizeSpec>;\n\n try {\n spec = normalizeSpec(schemaValue);\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n issues.push({ key, kind: \"invalid\", message: msg });\n continue;\n }\n\n const raw = env[key];\n\n // treat undefined or empty string as \"missing\"\n if (raw === undefined || raw === \"\") {\n if (spec.defaultValue !== undefined) {\n out[key] = spec.defaultValue;\n } else if (spec.optional) {\n out[key] = undefined;\n } else {\n issues.push({\n key,\n kind: \"missing\",\n message: \"missing required environment variable\",\n });\n }\n continue;\n }\n\n try {\n if (spec.kind === \"enum\") {\n if (!spec.values.includes(raw)) {\n throw new Error(\n `expected one of [${spec.values.join(\", \")}], got \"${raw}\"`,\n );\n }\n out[key] = raw;\n } else if (spec.kind === \"regex\") {\n if (!spec.re.test(raw)) {\n throw new Error(`does not match ${spec.display}`);\n }\n out[key] = raw;\n } else {\n // primitives: string/number/boolean/json/url/email\n out[key] = parseByType(spec.kind, raw);\n }\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n issues.push({ key, kind: \"invalid\", message: msg });\n }\n }\n\n if (issues.length > 0) throw new EnvDoctorError(issues);\n\n return out as EnvDoctorResult<TSchema>;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/core/envDoctor.ts","../src/errors/EnvDoctorError.ts","../src/validators/primitives.ts","../src/core/runner.ts"],"sourcesContent":["export { envDoctor } from \"./core/envDoctor\";\n\nexport type { EnvDoctorOptions, EnvDoctorSchema } from \"./types\";\n\nexport { EnvDoctorError } from \"./errors/EnvDoctorError\";\n","import * as dotenv from \"dotenv\";\nimport { validateAndParse } from \"./runner\";\nimport type { EnvDoctorOptions, EnvDoctorResult, EnvDoctorSchema } from \"../types\";\n\nexport type { EnvDoctorOptions, EnvDoctorSchema } from \"../types\";\nexport { EnvDoctorError } from \"../errors/EnvDoctorError\";\n\nexport function envDoctor<TSchema extends EnvDoctorSchema>(\n schema: TSchema,\n options: EnvDoctorOptions = {}\n): EnvDoctorResult<TSchema> {\n const { loadDotEnv = true, env = process.env } = options;\n\n if (loadDotEnv) dotenv.config();\n\n return validateAndParse(schema, env);\n}\n","export type EnvDoctorIssue =\n | { key: string; kind: \"missing\"; message: string }\n | { key: string; kind: \"invalid\"; message: string };\n\nexport class EnvDoctorError extends Error {\n public readonly issues: EnvDoctorIssue[];\n\n constructor(issues: EnvDoctorIssue[]) {\n const header = \"ENV validation failed\";\n const lines = issues.map((i) => `- ${i.key}: ${i.message}`);\n super([header, ...lines].join(\"\\n\"));\n this.name = \"EnvDoctorError\";\n this.issues = issues;\n }\n}\n","import type { EnvBaseType, EnvSchemaValue } from \"../types\";\n\nconst EMAIL_RE = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\nexport function parseByType(type: EnvBaseType, raw: string): unknown {\n switch (type) {\n case \"string\":\n return raw;\n\n case \"number\": {\n const n = Number(raw.trim());\n if (!Number.isFinite(n)) throw new Error(`expected number, got \"${raw}\"`);\n return n;\n }\n\n case \"boolean\": {\n const v = raw.trim().toLowerCase();\n if ([\"true\", \"1\", \"yes\", \"y\", \"on\"].includes(v)) return true;\n if ([\"false\", \"0\", \"no\", \"n\", \"off\"].includes(v)) return false;\n throw new Error(\n `expected boolean (true/false/1/0/yes/no/on/off), got \"${raw}\"`,\n );\n }\n\n case \"json\": {\n try {\n return JSON.parse(raw);\n } catch {\n throw new Error(`expected json, got \"${raw}\"`);\n }\n }\n\n case \"url\": {\n try {\n new URL(raw);\n return raw;\n } catch {\n throw new Error(`expected url, got \"${raw}\"`);\n }\n }\n\n case \"email\": {\n const s = raw.trim();\n if (!EMAIL_RE.test(s)) {\n throw new Error(`expected email, got \"${raw}\"`);\n }\n return s;\n }\n\n default: {\n throw new Error(`unsupported primitive type: ${String(type)}`);\n }\n }\n}\n\nfunction hasOwn(obj: unknown, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(obj, key);\n}\n\n/**\n * Type-check + normalize a default value into the right runtime type.\n * - Allows string defaults for number/boolean (parsed)\n * - Validates url/email defaults\n * - json defaults can be any value\n */\nfunction coerceDefault(kind: EnvBaseType, def: unknown): unknown {\n if (def === undefined) return undefined;\n\n switch (kind) {\n case \"string\": {\n if (typeof def !== \"string\")\n throw new Error(`default for string must be a string`);\n return def;\n }\n\n case \"number\": {\n if (typeof def === \"number\") {\n if (!Number.isFinite(def))\n throw new Error(`default for number must be finite`);\n return def;\n }\n if (typeof def === \"string\") return parseByType(\"number\", def);\n throw new Error(`default for number must be number or string`);\n }\n\n case \"boolean\": {\n if (typeof def === \"boolean\") return def;\n if (typeof def === \"string\") return parseByType(\"boolean\", def);\n throw new Error(`default for boolean must be boolean or string`);\n }\n\n case \"json\": {\n // allow any JSON-ish value\n return def;\n }\n\n case \"url\": {\n if (typeof def !== \"string\")\n throw new Error(`default for url must be a string`);\n return parseByType(\"url\", def);\n }\n\n case \"email\": {\n if (typeof def !== \"string\")\n throw new Error(`default for email must be a string`);\n return parseByType(\"email\", def);\n }\n\n /* c8 ignore next */\n default: {\n throw new Error(`unsupported default kind: ${String(kind)}`);\n }\n }\n}\n\n/** Normalized spec used by the runner */\nexport type NormalizedSpec =\n | {\n kind: EnvBaseType;\n optional: boolean;\n defaultValue?: unknown;\n description?: string;\n example?: string;\n secret: boolean;\n }\n | {\n kind: \"enum\";\n optional: boolean;\n values: readonly string[];\n defaultValue?: string;\n description?: string;\n example?: string;\n secret: boolean;\n }\n | {\n kind: \"regex\";\n optional: boolean;\n re: RegExp;\n display: string;\n defaultValue?: string;\n description?: string;\n example?: string;\n secret: boolean;\n };\n\nfunction normalizeMeta(schemaValue: Record<string, unknown>): {\n description?: string;\n example?: string;\n secret: boolean;\n} {\n let description: string | undefined = undefined;\n if (hasOwn(schemaValue, \"description\")) {\n const d = schemaValue.description;\n if (d !== undefined && typeof d !== \"string\") {\n throw new Error(`\"description\" must be a string if provided`);\n }\n description = d;\n }\n\n let example: string | undefined = undefined;\n if (hasOwn(schemaValue, \"example\")) {\n const ex = schemaValue.example;\n if (ex !== undefined && typeof ex !== \"string\") {\n throw new Error(`\"example\" must be a string if provided`);\n }\n example = ex;\n }\n\n let secret = false;\n if (hasOwn(schemaValue, \"secret\")) {\n const s = schemaValue.secret;\n if (s !== undefined && typeof s !== \"boolean\") {\n throw new Error(`\"secret\" must be a boolean if provided`);\n }\n secret = s === true;\n }\n\n return { description, example, secret };\n}\n\nexport function normalizeSpec(schemaValue: EnvSchemaValue): NormalizedSpec {\n // --------------------\n // String style: \"number?\" etc.\n // --------------------\n if (typeof schemaValue === \"string\") {\n const optional = schemaValue.endsWith(\"?\");\n const base = optional ? schemaValue.slice(0, -1) : schemaValue;\n\n const allowed: readonly EnvBaseType[] = [\n \"string\",\n \"number\",\n \"boolean\",\n \"json\",\n \"url\",\n \"email\",\n ];\n\n if (!allowed.includes(base as EnvBaseType)) {\n throw new Error(\n `Unsupported type \"${schemaValue}\". Supported: string, number, boolean, json, url, email (optional with ?)`,\n );\n }\n\n return {\n kind: base as EnvBaseType,\n optional,\n secret: false,\n };\n }\n\n // --------------------\n // Object style\n // --------------------\n if (\n !schemaValue ||\n typeof schemaValue !== \"object\" ||\n Array.isArray(schemaValue)\n ) {\n throw new Error(\"Schema value must be a string or object spec.\");\n }\n\n const t = (schemaValue as any).type;\n const meta = normalizeMeta(schemaValue as Record<string, unknown>);\n\n // --------------------\n // Primitive object spec: { type: \"number\", optional?: true, default?: ... }\n // --------------------\n const primitiveAllowed: readonly EnvBaseType[] = [\n \"string\",\n \"number\",\n \"boolean\",\n \"json\",\n \"url\",\n \"email\",\n ];\n\n if (primitiveAllowed.includes(t)) {\n const optional = !!(schemaValue as any).optional;\n const defaultValue = hasOwn(schemaValue, \"default\")\n ? coerceDefault(t as EnvBaseType, (schemaValue as any).default)\n : undefined;\n\n return {\n kind: t as EnvBaseType,\n optional,\n defaultValue,\n ...meta,\n };\n }\n\n // --------------------\n // Enum: { type: \"enum\", values: [...], optional?: true, default?: \"dev\" }\n // --------------------\n if (t === \"enum\") {\n const values = (schemaValue as any).values;\n if (\n !Array.isArray(values) ||\n values.length === 0 ||\n !values.every((v: any) => typeof v === \"string\")\n ) {\n throw new Error(`enum spec requires \"values\": string[] (non-empty)`);\n }\n\n const optional = !!(schemaValue as any).optional;\n\n let defaultValue: string | undefined = undefined;\n if (hasOwn(schemaValue, \"default\")) {\n const def = (schemaValue as any).default;\n if (typeof def !== \"string\") {\n throw new Error(`default for enum must be a string`);\n }\n if (!values.includes(def)) {\n throw new Error(\n `default \"${def}\" must be one of [${values.join(\", \")}]`,\n );\n }\n defaultValue = def;\n }\n\n return {\n kind: \"enum\",\n optional,\n values,\n defaultValue,\n ...meta,\n };\n }\n\n // --------------------\n // Regex: { type: \"regex\", pattern: \"...\", flags?: \"...\", optional?: true, default?: \"abc\" }\n // --------------------\n if (t === \"regex\") {\n const pattern = (schemaValue as any).pattern;\n const flags = (schemaValue as any).flags;\n\n if (typeof pattern !== \"string\" || pattern.length === 0) {\n throw new Error(`regex spec requires \"pattern\": string`);\n }\n if (flags !== undefined && typeof flags !== \"string\") {\n throw new Error(`regex spec \"flags\" must be a string if provided`);\n }\n\n let re: RegExp;\n try {\n re = new RegExp(pattern, flags);\n } catch (e) {\n throw new Error(`invalid regex: ${String(e)}`);\n }\n\n const display = `/${pattern}/${flags ?? \"\"}`;\n const optional = !!(schemaValue as any).optional;\n\n let defaultValue: string | undefined = undefined;\n if (hasOwn(schemaValue, \"default\")) {\n const def = (schemaValue as any).default;\n if (typeof def !== \"string\") {\n throw new Error(`default for regex must be a string`);\n }\n if (!re.test(def)) {\n throw new Error(`default \"${def}\" does not match ${display}`);\n }\n defaultValue = def;\n }\n\n return {\n kind: \"regex\",\n optional,\n re,\n display,\n defaultValue,\n ...meta,\n };\n }\n\n throw new Error(\n `Unsupported object spec type \"${String(t)}\". Supported: primitives (string/number/boolean/json/url/email), enum, regex`,\n );\n}\n","import { EnvDoctorError, type EnvDoctorIssue } from \"../errors/EnvDoctorError\";\nimport { normalizeSpec, parseByType } from \"../validators/primitives\";\nimport type { EnvDoctorResult, EnvDoctorSchema } from \"../types\";\n\nexport function validateAndParse<TSchema extends EnvDoctorSchema>(\n schema: TSchema,\n env: Record<string, string | undefined>,\n): EnvDoctorResult<TSchema> {\n const issues: EnvDoctorIssue[] = [];\n const out: Record<string, unknown> = {};\n\n for (const [key, schemaValue] of Object.entries(schema)) {\n let spec: ReturnType<typeof normalizeSpec>;\n\n try {\n spec = normalizeSpec(schemaValue);\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n issues.push({ key, kind: \"invalid\", message: msg });\n continue;\n }\n\n const raw = env[key];\n\n // treat undefined or empty string as \"missing\"\n if (raw === undefined || raw === \"\") {\n if (spec.defaultValue !== undefined) {\n out[key] = spec.defaultValue;\n } else if (spec.optional) {\n out[key] = undefined;\n } else {\n issues.push({\n key,\n kind: \"missing\",\n message: \"missing required environment variable\",\n });\n }\n continue;\n }\n\n try {\n if (spec.kind === \"enum\") {\n if (!spec.values.includes(raw)) {\n throw new Error(\n `expected one of [${spec.values.join(\", \")}], got \"${raw}\"`,\n );\n }\n out[key] = raw;\n } else if (spec.kind === \"regex\") {\n if (!spec.re.test(raw)) {\n throw new Error(`does not match ${spec.display}`);\n }\n out[key] = raw;\n } else {\n // primitives: string/number/boolean/json/url/email\n out[key] = parseByType(spec.kind, raw);\n }\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n issues.push({ key, kind: \"invalid\", message: msg });\n }\n }\n\n if (issues.length > 0) throw new EnvDoctorError(issues);\n\n return out as EnvDoctorResult<TSchema>;\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "env-typed-checker",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Validate and parse environment variables with a tiny, type-safe schema.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"module": "dist/index.mjs",
|
|
10
10
|
"types": "dist/index.d.ts",
|
|
11
11
|
"bin": {
|
|
12
|
-
"env-typed-checker": "
|
|
12
|
+
"env-typed-checker": "bin/env-typed-checker.cjs"
|
|
13
13
|
},
|
|
14
14
|
"exports": {
|
|
15
15
|
".": {
|