env-typed-checker 0.2.3 → 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/dist/cli/index.js CHANGED
@@ -143,6 +143,33 @@ function coerceDefault(kind, def) {
143
143
  }
144
144
  }
145
145
  }
146
+ function normalizeMeta(schemaValue) {
147
+ let description = void 0;
148
+ if (hasOwn(schemaValue, "description")) {
149
+ const d = schemaValue.description;
150
+ if (d !== void 0 && typeof d !== "string") {
151
+ throw new Error(`"description" must be a string if provided`);
152
+ }
153
+ description = d;
154
+ }
155
+ let example = void 0;
156
+ if (hasOwn(schemaValue, "example")) {
157
+ const ex = schemaValue.example;
158
+ if (ex !== void 0 && typeof ex !== "string") {
159
+ throw new Error(`"example" must be a string if provided`);
160
+ }
161
+ example = ex;
162
+ }
163
+ let secret = false;
164
+ if (hasOwn(schemaValue, "secret")) {
165
+ const s = schemaValue.secret;
166
+ if (s !== void 0 && typeof s !== "boolean") {
167
+ throw new Error(`"secret" must be a boolean if provided`);
168
+ }
169
+ secret = s === true;
170
+ }
171
+ return { description, example, secret };
172
+ }
146
173
  function normalizeSpec(schemaValue) {
147
174
  if (typeof schemaValue === "string") {
148
175
  const optional = schemaValue.endsWith("?");
@@ -160,12 +187,17 @@ function normalizeSpec(schemaValue) {
160
187
  `Unsupported type "${schemaValue}". Supported: string, number, boolean, json, url, email (optional with ?)`
161
188
  );
162
189
  }
163
- return { kind: base, optional };
190
+ return {
191
+ kind: base,
192
+ optional,
193
+ secret: false
194
+ };
164
195
  }
165
196
  if (!schemaValue || typeof schemaValue !== "object" || Array.isArray(schemaValue)) {
166
197
  throw new Error("Schema value must be a string or object spec.");
167
198
  }
168
199
  const t = schemaValue.type;
200
+ const meta = normalizeMeta(schemaValue);
169
201
  const primitiveAllowed = [
170
202
  "string",
171
203
  "number",
@@ -177,7 +209,12 @@ function normalizeSpec(schemaValue) {
177
209
  if (primitiveAllowed.includes(t)) {
178
210
  const optional = !!schemaValue.optional;
179
211
  const defaultValue = hasOwn(schemaValue, "default") ? coerceDefault(t, schemaValue.default) : void 0;
180
- return { kind: t, optional, defaultValue };
212
+ return {
213
+ kind: t,
214
+ optional,
215
+ defaultValue,
216
+ ...meta
217
+ };
181
218
  }
182
219
  if (t === "enum") {
183
220
  const values = schemaValue.values;
@@ -198,7 +235,13 @@ function normalizeSpec(schemaValue) {
198
235
  }
199
236
  defaultValue = def;
200
237
  }
201
- return { kind: "enum", optional, values, defaultValue };
238
+ return {
239
+ kind: "enum",
240
+ optional,
241
+ values,
242
+ defaultValue,
243
+ ...meta
244
+ };
202
245
  }
203
246
  if (t === "regex") {
204
247
  const pattern = schemaValue.pattern;
@@ -228,7 +271,14 @@ function normalizeSpec(schemaValue) {
228
271
  }
229
272
  defaultValue = def;
230
273
  }
231
- return { kind: "regex", optional, re, display, defaultValue };
274
+ return {
275
+ kind: "regex",
276
+ optional,
277
+ re,
278
+ display,
279
+ defaultValue,
280
+ ...meta
281
+ };
232
282
  }
233
283
  throw new Error(
234
284
  `Unsupported object spec type "${String(t)}". Supported: primitives (string/number/boolean/json/url/email), enum, regex`
@@ -296,8 +346,18 @@ function envDoctor(schema, options = {}) {
296
346
  }
297
347
 
298
348
  // src/cli/cli.ts
349
+ function isCheckOutputFormat(value) {
350
+ return value === "pretty" || value === "json" || value === "github";
351
+ }
299
352
  function parseArgs(argv) {
300
- const out = { useDotenv: true, useDefaults: true, commentTypes: false };
353
+ const out = {
354
+ checkFormat: "pretty",
355
+ useDotenv: true,
356
+ useDefaults: true,
357
+ commentTypes: false,
358
+ commentDocs: false,
359
+ exampleValues: false
360
+ };
301
361
  const [cmd, ...rest] = argv;
302
362
  out.cmd = cmd;
303
363
  for (let i = 0; i < rest.length; i++) {
@@ -306,7 +366,15 @@ function parseArgs(argv) {
306
366
  else if (a.startsWith("--schema=")) out.schemaPath = a.split("=", 2)[1];
307
367
  else if (a === "--env-file") out.envFile = rest[++i];
308
368
  else if (a.startsWith("--env-file=")) out.envFile = a.split("=", 2)[1];
309
- else if (a === "--no-dotenv") out.useDotenv = false;
369
+ else if (a === "--format") {
370
+ const f = rest[++i];
371
+ if (isCheckOutputFormat(f)) out.checkFormat = f;
372
+ else out.invalidCheckFormat = String(f);
373
+ } else if (a.startsWith("--format=")) {
374
+ const f = a.slice("--format=".length);
375
+ if (isCheckOutputFormat(f)) out.checkFormat = f;
376
+ else out.invalidCheckFormat = f;
377
+ } else if (a === "--no-dotenv") out.useDotenv = false;
310
378
  else if (a === "--out") out.outFile = rest[++i];
311
379
  else if (a.startsWith("--out=")) out.outFile = a.split("=", 2)[1];
312
380
  else if (a === "--mode") {
@@ -317,6 +385,8 @@ function parseArgs(argv) {
317
385
  if (m === "update" || m === "create") out.mode = m;
318
386
  } else if (a === "--no-defaults") out.useDefaults = false;
319
387
  else if (a === "--comment-types") out.commentTypes = true;
388
+ else if (a === "--comment-docs") out.commentDocs = true;
389
+ else if (a === "--example-values") out.exampleValues = true;
320
390
  }
321
391
  return out;
322
392
  }
@@ -371,7 +441,22 @@ function formatEnvLine(key, value, comment) {
371
441
  const safe = needsQuoting(value) ? JSON.stringify(value) : value;
372
442
  return comment ? `${key}=${safe} # ${comment}` : `${key}=${safe}`;
373
443
  }
374
- function runGenerate(schema, outPath, mode, useDefaults, commentTypes, io) {
444
+ function normalizeCommentText(s) {
445
+ return s.replace(/\r?\n+/g, " ").replace(/\s+/g, " ").trim();
446
+ }
447
+ function getDocCommentLines(description, example) {
448
+ const lines = [];
449
+ if (typeof description === "string") {
450
+ const d = normalizeCommentText(description);
451
+ if (d) lines.push(`# ${d}`);
452
+ }
453
+ if (typeof example === "string") {
454
+ const ex = normalizeCommentText(example);
455
+ if (ex) lines.push(`# example: ${ex}`);
456
+ }
457
+ return lines;
458
+ }
459
+ function runGenerate(schema, outPath, mode, useDefaults, commentTypes, commentDocs, exampleValues, io) {
375
460
  const absOut = import_node_path.default.resolve(process.cwd(), outPath);
376
461
  if (mode === "create" && import_node_fs.default.existsSync(absOut)) {
377
462
  io.error(`Refusing to overwrite existing file: ${outPath}`);
@@ -380,45 +465,100 @@ function runGenerate(schema, outPath, mode, useDefaults, commentTypes, io) {
380
465
  const existing = mode === "update" ? readEnvFile(absOut) : {};
381
466
  const keys = Object.keys(schema).sort();
382
467
  const linesToAdd = [];
468
+ let addedVars = 0;
383
469
  for (const key of keys) {
384
470
  if (existing[key] !== void 0) continue;
385
471
  const spec = schema[key];
472
+ const ns = normalizeSpec(spec);
386
473
  const typeLabel = commentTypes ? getTypeLabel(spec) : void 0;
387
474
  let val = "";
388
- if (useDefaults) {
389
- const ns = normalizeSpec(spec);
475
+ if (exampleValues && ns.example !== void 0) {
476
+ val = ns.example;
477
+ } else if (useDefaults) {
390
478
  if (ns.defaultValue !== void 0) {
391
479
  val = defaultToEnvString(ns.defaultValue);
392
480
  }
393
481
  }
482
+ if (commentDocs) {
483
+ linesToAdd.push(...getDocCommentLines(ns.description, ns.example));
484
+ }
394
485
  linesToAdd.push(formatEnvLine(key, val, typeLabel));
486
+ addedVars++;
395
487
  }
396
- if (linesToAdd.length === 0) {
488
+ if (addedVars === 0) {
397
489
  io.log("\u2705 No missing variables. Nothing to generate.");
398
490
  return 0;
399
491
  }
400
492
  if (mode === "create") {
401
493
  import_node_fs.default.writeFileSync(absOut, linesToAdd.join("\n") + "\n", "utf8");
402
- io.log(`\u2705 Created ${outPath} with ${linesToAdd.length} variables.`);
494
+ io.log(`\u2705 Created ${outPath} with ${addedVars} variables.`);
403
495
  return 0;
404
496
  }
405
497
  const prefix = import_node_fs.default.existsSync(absOut) ? "\n" : "";
406
498
  import_node_fs.default.appendFileSync(absOut, prefix + linesToAdd.join("\n") + "\n", "utf8");
407
- io.log(
408
- `\u2705 Updated ${outPath}. Added ${linesToAdd.length} missing variables.`
409
- );
499
+ io.log(`\u2705 Updated ${outPath}. Added ${addedVars} missing variables.`);
410
500
  return 0;
411
501
  }
502
+ function redactIssueMessage(message) {
503
+ const sep = ", got ";
504
+ const i = message.indexOf(sep);
505
+ if (i >= 0) {
506
+ return `${message.slice(0, i)}, got "<redacted>"`;
507
+ }
508
+ return `invalid value, got "<redacted>"`;
509
+ }
510
+ function isSecretKey(schema, key) {
511
+ const spec = schema[key];
512
+ if (spec === void 0) return false;
513
+ try {
514
+ const ns = normalizeSpec(spec);
515
+ return ns.secret === true;
516
+ } catch {
517
+ return false;
518
+ }
519
+ }
520
+ function getIssueMessage(issue, schema) {
521
+ const redact = issue.kind === "invalid" && isSecretKey(schema, issue.key);
522
+ return redact ? redactIssueMessage(issue.message) : issue.message;
523
+ }
524
+ function escapeGithubCommandData(value) {
525
+ return value.replace(/%/g, "%25").replace(/\r/g, "%0D").replace(/\n/g, "%0A");
526
+ }
527
+ function escapeGithubCommandProperty(value) {
528
+ return escapeGithubCommandData(value).replace(/:/g, "%3A").replace(/,/g, "%2C");
529
+ }
530
+ function formatValidationErrorForCli(err, schema, format) {
531
+ const issues = err.issues.map((issue) => {
532
+ const message = getIssueMessage(issue, schema);
533
+ return { key: issue.key, kind: issue.kind, message };
534
+ });
535
+ if (format === "github") {
536
+ const title = escapeGithubCommandProperty("ENV validation");
537
+ return issues.map(
538
+ (issue) => `::error title=${title}::${escapeGithubCommandData(`${issue.key}: ${issue.message}`)}`
539
+ );
540
+ }
541
+ if (format === "json") {
542
+ return [JSON.stringify({ error: "ENV validation failed", issues })];
543
+ }
544
+ const header = "ENV validation failed";
545
+ const lines = issues.map((issue) => `- ${issue.key}: ${issue.message}`);
546
+ return [[header, ...lines].join("\n")];
547
+ }
412
548
  function runCli(argv, io = console) {
413
549
  const {
414
550
  cmd,
415
551
  schemaPath,
416
552
  envFile,
553
+ checkFormat,
554
+ invalidCheckFormat,
417
555
  useDotenv,
418
556
  outFile,
419
557
  mode,
420
558
  useDefaults,
421
- commentTypes
559
+ commentTypes,
560
+ commentDocs,
561
+ exampleValues
422
562
  } = parseArgs(argv);
423
563
  if (!cmd || cmd === "help" || cmd === "--help" || cmd === "-h") {
424
564
  io.log(
@@ -426,17 +566,20 @@ function runCli(argv, io = console) {
426
566
  "env-typed-checker",
427
567
  "",
428
568
  "Usage:",
429
- " env-typed-checker check --schema <file> [--env-file <file>] [--no-dotenv]",
430
- " env-typed-checker generate --schema <file> [--out <file>] [--mode update|create] [--no-defaults] [--comment-types]",
569
+ " env-typed-checker check --schema <file> [--env-file <file>] [--no-dotenv] [--format pretty|json|github]",
570
+ " env-typed-checker generate --schema <file> [--out <file>] [--mode update|create] [--no-defaults] [--comment-types] [--comment-docs] [--example-values]",
431
571
  "",
432
572
  "Options:",
433
573
  " --schema <file> Path to schema JSON (required)",
434
574
  " --env-file <file> Env file path (default: .env) [check]",
435
575
  " --no-dotenv Do not load env file; use process.env only [check]",
576
+ " --format <name> check output format: pretty|json|github (default: pretty) [check]",
436
577
  " --out <file> Output env file (default: .env) [generate]",
437
578
  " --mode update|create update appends missing keys; create fails if file exists (default: update)",
438
579
  " --no-defaults do not write schema defaults; write empty placeholders [generate]",
439
580
  " --comment-types add inline comments with type info [generate]",
581
+ " --comment-docs add description/example comments above each key [generate]",
582
+ " --example-values use schema example values when generating missing keys [generate]",
440
583
  "",
441
584
  "Exit codes:",
442
585
  " 0 = OK, 1 = validation failed, 2 = CLI error"
@@ -448,26 +591,47 @@ function runCli(argv, io = console) {
448
591
  io.error("Missing required option: --schema <file>");
449
592
  return 2;
450
593
  }
594
+ if (cmd === "check" && invalidCheckFormat !== void 0) {
595
+ io.error(
596
+ `Invalid value for --format: "${invalidCheckFormat}". Expected: pretty, json, github`
597
+ );
598
+ return 2;
599
+ }
451
600
  try {
452
601
  const schema = loadSchema(schemaPath);
453
602
  if (cmd === "check") {
454
603
  const env = buildEnv(useDotenv, envFile);
455
- envDoctor(schema, { loadDotEnv: false, env });
604
+ try {
605
+ envDoctor(schema, { loadDotEnv: false, env });
606
+ } catch (e) {
607
+ if (e instanceof EnvDoctorError) {
608
+ for (const line of formatValidationErrorForCli(e, schema, checkFormat)) {
609
+ io.error(line);
610
+ }
611
+ return 1;
612
+ }
613
+ throw e;
614
+ }
456
615
  io.log("\u2705 Environment is valid.");
457
616
  return 0;
458
617
  }
459
618
  if (cmd === "generate") {
460
619
  const out = outFile ?? ".env";
461
620
  const m = mode ?? "update";
462
- return runGenerate(schema, out, m, useDefaults, commentTypes, io);
621
+ return runGenerate(
622
+ schema,
623
+ out,
624
+ m,
625
+ useDefaults,
626
+ commentTypes,
627
+ commentDocs,
628
+ exampleValues,
629
+ io
630
+ );
463
631
  }
464
632
  io.error(`Unknown command: ${cmd}`);
465
633
  return 2;
466
634
  } catch (e) {
467
- if (e instanceof EnvDoctorError) {
468
- io.error(e.message);
469
- return 1;
470
- }
471
635
  io.error(e instanceof Error ? e.message : String(e));
472
636
  return 2;
473
637
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/index.ts","../../src/cli/cli.ts","../../src/core/envDoctor.ts","../../src/errors/EnvDoctorError.ts","../../src/validators/primitives.ts","../../src/core/runner.ts"],"sourcesContent":["export { runCli } from \"./cli\";\n","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","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":["dotenv","path","fs"]}
1
+ {"version":3,"sources":["../../src/cli/index.ts","../../src/cli/cli.ts","../../src/core/envDoctor.ts","../../src/errors/EnvDoctorError.ts","../../src/validators/primitives.ts","../../src/core/runner.ts"],"sourcesContent":["export { runCli } from \"./cli\";\n","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","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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,qBAAe;AACf,uBAAiB;AACjB,IAAAA,UAAwB;;;ACFxB,aAAwB;;;ACIjB,IAAM,iBAAN,cAA6B,MAAM;AAAA,EAGxC,YAAY,QAA0B;AACpC,UAAM,SAAS;AACf,UAAM,QAAQ,OAAO,IAAI,CAAC,MAAM,KAAK,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE;AAC1D,UAAM,CAAC,QAAQ,GAAG,KAAK,EAAE,KAAK,IAAI,CAAC;AACnC,SAAK,OAAO;AACZ,SAAK,SAAS;AAAA,EAChB;AACF;;;ACZA,IAAM,WAAW;AAEV,SAAS,YAAY,MAAmB,KAAsB;AACnE,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO;AAAA,IAET,KAAK,UAAU;AACb,YAAM,IAAI,OAAO,IAAI,KAAK,CAAC;AAC3B,UAAI,CAAC,OAAO,SAAS,CAAC,EAAG,OAAM,IAAI,MAAM,yBAAyB,GAAG,GAAG;AACxE,aAAO;AAAA,IACT;AAAA,IAEA,KAAK,WAAW;AACd,YAAM,IAAI,IAAI,KAAK,EAAE,YAAY;AACjC,UAAI,CAAC,QAAQ,KAAK,OAAO,KAAK,IAAI,EAAE,SAAS,CAAC,EAAG,QAAO;AACxD,UAAI,CAAC,SAAS,KAAK,MAAM,KAAK,KAAK,EAAE,SAAS,CAAC,EAAG,QAAO;AACzD,YAAM,IAAI;AAAA,QACR,yDAAyD,GAAG;AAAA,MAC9D;AAAA,IACF;AAAA,IAEA,KAAK,QAAQ;AACX,UAAI;AACF,eAAO,KAAK,MAAM,GAAG;AAAA,MACvB,QAAQ;AACN,cAAM,IAAI,MAAM,uBAAuB,GAAG,GAAG;AAAA,MAC/C;AAAA,IACF;AAAA,IAEA,KAAK,OAAO;AACV,UAAI;AACF,YAAI,IAAI,GAAG;AACX,eAAO;AAAA,MACT,QAAQ;AACN,cAAM,IAAI,MAAM,sBAAsB,GAAG,GAAG;AAAA,MAC9C;AAAA,IACF;AAAA,IAEA,KAAK,SAAS;AACZ,YAAM,IAAI,IAAI,KAAK;AACnB,UAAI,CAAC,SAAS,KAAK,CAAC,GAAG;AACrB,cAAM,IAAI,MAAM,wBAAwB,GAAG,GAAG;AAAA,MAChD;AACA,aAAO;AAAA,IACT;AAAA,IAEA,SAAS;AACP,YAAM,IAAI,MAAM,+BAA+B,OAAO,IAAI,CAAC,EAAE;AAAA,IAC/D;AAAA,EACF;AACF;AAEA,SAAS,OAAO,KAAc,KAAsB;AAClD,SAAO,OAAO,UAAU,eAAe,KAAK,KAAK,GAAG;AACtD;AAQA,SAAS,cAAc,MAAmB,KAAuB;AAC/D,MAAI,QAAQ,OAAW,QAAO;AAE9B,UAAQ,MAAM;AAAA,IACZ,KAAK,UAAU;AACb,UAAI,OAAO,QAAQ;AACjB,cAAM,IAAI,MAAM,qCAAqC;AACvD,aAAO;AAAA,IACT;AAAA,IAEA,KAAK,UAAU;AACb,UAAI,OAAO,QAAQ,UAAU;AAC3B,YAAI,CAAC,OAAO,SAAS,GAAG;AACtB,gBAAM,IAAI,MAAM,mCAAmC;AACrD,eAAO;AAAA,MACT;AACA,UAAI,OAAO,QAAQ,SAAU,QAAO,YAAY,UAAU,GAAG;AAC7D,YAAM,IAAI,MAAM,6CAA6C;AAAA,IAC/D;AAAA,IAEA,KAAK,WAAW;AACd,UAAI,OAAO,QAAQ,UAAW,QAAO;AACrC,UAAI,OAAO,QAAQ,SAAU,QAAO,YAAY,WAAW,GAAG;AAC9D,YAAM,IAAI,MAAM,+CAA+C;AAAA,IACjE;AAAA,IAEA,KAAK,QAAQ;AAEX,aAAO;AAAA,IACT;AAAA,IAEA,KAAK,OAAO;AACV,UAAI,OAAO,QAAQ;AACjB,cAAM,IAAI,MAAM,kCAAkC;AACpD,aAAO,YAAY,OAAO,GAAG;AAAA,IAC/B;AAAA,IAEA,KAAK,SAAS;AACZ,UAAI,OAAO,QAAQ;AACjB,cAAM,IAAI,MAAM,oCAAoC;AACtD,aAAO,YAAY,SAAS,GAAG;AAAA,IACjC;AAAA;AAAA,IAGA,SAAS;AACP,YAAM,IAAI,MAAM,6BAA6B,OAAO,IAAI,CAAC,EAAE;AAAA,IAC7D;AAAA,EACF;AACF;AAgCA,SAAS,cAAc,aAIrB;AACA,MAAI,cAAkC;AACtC,MAAI,OAAO,aAAa,aAAa,GAAG;AACtC,UAAM,IAAI,YAAY;AACtB,QAAI,MAAM,UAAa,OAAO,MAAM,UAAU;AAC5C,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AACA,kBAAc;AAAA,EAChB;AAEA,MAAI,UAA8B;AAClC,MAAI,OAAO,aAAa,SAAS,GAAG;AAClC,UAAM,KAAK,YAAY;AACvB,QAAI,OAAO,UAAa,OAAO,OAAO,UAAU;AAC9C,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC1D;AACA,cAAU;AAAA,EACZ;AAEA,MAAI,SAAS;AACb,MAAI,OAAO,aAAa,QAAQ,GAAG;AACjC,UAAM,IAAI,YAAY;AACtB,QAAI,MAAM,UAAa,OAAO,MAAM,WAAW;AAC7C,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC1D;AACA,aAAS,MAAM;AAAA,EACjB;AAEA,SAAO,EAAE,aAAa,SAAS,OAAO;AACxC;AAEO,SAAS,cAAc,aAA6C;AAIzE,MAAI,OAAO,gBAAgB,UAAU;AACnC,UAAM,WAAW,YAAY,SAAS,GAAG;AACzC,UAAM,OAAO,WAAW,YAAY,MAAM,GAAG,EAAE,IAAI;AAEnD,UAAM,UAAkC;AAAA,MACtC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,QAAI,CAAC,QAAQ,SAAS,IAAmB,GAAG;AAC1C,YAAM,IAAI;AAAA,QACR,qBAAqB,WAAW;AAAA,MAClC;AAAA,IACF;AAEA,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,EACF;AAKA,MACE,CAAC,eACD,OAAO,gBAAgB,YACvB,MAAM,QAAQ,WAAW,GACzB;AACA,UAAM,IAAI,MAAM,+CAA+C;AAAA,EACjE;AAEA,QAAM,IAAK,YAAoB;AAC/B,QAAM,OAAO,cAAc,WAAsC;AAKjE,QAAM,mBAA2C;AAAA,IAC/C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI,iBAAiB,SAAS,CAAC,GAAG;AAChC,UAAM,WAAW,CAAC,CAAE,YAAoB;AACxC,UAAM,eAAe,OAAO,aAAa,SAAS,IAC9C,cAAc,GAAmB,YAAoB,OAAO,IAC5D;AAEJ,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACL;AAAA,EACF;AAKA,MAAI,MAAM,QAAQ;AAChB,UAAM,SAAU,YAAoB;AACpC,QACE,CAAC,MAAM,QAAQ,MAAM,KACrB,OAAO,WAAW,KAClB,CAAC,OAAO,MAAM,CAAC,MAAW,OAAO,MAAM,QAAQ,GAC/C;AACA,YAAM,IAAI,MAAM,mDAAmD;AAAA,IACrE;AAEA,UAAM,WAAW,CAAC,CAAE,YAAoB;AAExC,QAAI,eAAmC;AACvC,QAAI,OAAO,aAAa,SAAS,GAAG;AAClC,YAAM,MAAO,YAAoB;AACjC,UAAI,OAAO,QAAQ,UAAU;AAC3B,cAAM,IAAI,MAAM,mCAAmC;AAAA,MACrD;AACA,UAAI,CAAC,OAAO,SAAS,GAAG,GAAG;AACzB,cAAM,IAAI;AAAA,UACR,YAAY,GAAG,qBAAqB,OAAO,KAAK,IAAI,CAAC;AAAA,QACvD;AAAA,MACF;AACA,qBAAe;AAAA,IACjB;AAEA,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACL;AAAA,EACF;AAKA,MAAI,MAAM,SAAS;AACjB,UAAM,UAAW,YAAoB;AACrC,UAAM,QAAS,YAAoB;AAEnC,QAAI,OAAO,YAAY,YAAY,QAAQ,WAAW,GAAG;AACvD,YAAM,IAAI,MAAM,uCAAuC;AAAA,IACzD;AACA,QAAI,UAAU,UAAa,OAAO,UAAU,UAAU;AACpD,YAAM,IAAI,MAAM,iDAAiD;AAAA,IACnE;AAEA,QAAI;AACJ,QAAI;AACF,WAAK,IAAI,OAAO,SAAS,KAAK;AAAA,IAChC,SAAS,GAAG;AACV,YAAM,IAAI,MAAM,kBAAkB,OAAO,CAAC,CAAC,EAAE;AAAA,IAC/C;AAEA,UAAM,UAAU,IAAI,OAAO,IAAI,SAAS,EAAE;AAC1C,UAAM,WAAW,CAAC,CAAE,YAAoB;AAExC,QAAI,eAAmC;AACvC,QAAI,OAAO,aAAa,SAAS,GAAG;AAClC,YAAM,MAAO,YAAoB;AACjC,UAAI,OAAO,QAAQ,UAAU;AAC3B,cAAM,IAAI,MAAM,oCAAoC;AAAA,MACtD;AACA,UAAI,CAAC,GAAG,KAAK,GAAG,GAAG;AACjB,cAAM,IAAI,MAAM,YAAY,GAAG,oBAAoB,OAAO,EAAE;AAAA,MAC9D;AACA,qBAAe;AAAA,IACjB;AAEA,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG;AAAA,IACL;AAAA,EACF;AAEA,QAAM,IAAI;AAAA,IACR,iCAAiC,OAAO,CAAC,CAAC;AAAA,EAC5C;AACF;;;AC7UO,SAAS,iBACd,QACA,KAC0B;AAC1B,QAAM,SAA2B,CAAC;AAClC,QAAM,MAA+B,CAAC;AAEtC,aAAW,CAAC,KAAK,WAAW,KAAK,OAAO,QAAQ,MAAM,GAAG;AACvD,QAAI;AAEJ,QAAI;AACF,aAAO,cAAc,WAAW;AAAA,IAClC,SAAS,GAAG;AACV,YAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,aAAO,KAAK,EAAE,KAAK,MAAM,WAAW,SAAS,IAAI,CAAC;AAClD;AAAA,IACF;AAEA,UAAM,MAAM,IAAI,GAAG;AAGnB,QAAI,QAAQ,UAAa,QAAQ,IAAI;AACnC,UAAI,KAAK,iBAAiB,QAAW;AACnC,YAAI,GAAG,IAAI,KAAK;AAAA,MAClB,WAAW,KAAK,UAAU;AACxB,YAAI,GAAG,IAAI;AAAA,MACb,OAAO;AACL,eAAO,KAAK;AAAA,UACV;AAAA,UACA,MAAM;AAAA,UACN,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AACA;AAAA,IACF;AAEA,QAAI;AACF,UAAI,KAAK,SAAS,QAAQ;AACxB,YAAI,CAAC,KAAK,OAAO,SAAS,GAAG,GAAG;AAC9B,gBAAM,IAAI;AAAA,YACR,oBAAoB,KAAK,OAAO,KAAK,IAAI,CAAC,WAAW,GAAG;AAAA,UAC1D;AAAA,QACF;AACA,YAAI,GAAG,IAAI;AAAA,MACb,WAAW,KAAK,SAAS,SAAS;AAChC,YAAI,CAAC,KAAK,GAAG,KAAK,GAAG,GAAG;AACtB,gBAAM,IAAI,MAAM,kBAAkB,KAAK,OAAO,EAAE;AAAA,QAClD;AACA,YAAI,GAAG,IAAI;AAAA,MACb,OAAO;AAEL,YAAI,GAAG,IAAI,YAAY,KAAK,MAAM,GAAG;AAAA,MACvC;AAAA,IACF,SAAS,GAAG;AACV,YAAM,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC;AACrD,aAAO,KAAK,EAAE,KAAK,MAAM,WAAW,SAAS,IAAI,CAAC;AAAA,IACpD;AAAA,EACF;AAEA,MAAI,OAAO,SAAS,EAAG,OAAM,IAAI,eAAe,MAAM;AAEtD,SAAO;AACT;;;AH3DO,SAAS,UACd,QACA,UAA4B,CAAC,GACH;AAC1B,QAAM,EAAE,aAAa,MAAM,MAAM,QAAQ,IAAI,IAAI;AAEjD,MAAI,WAAY,CAAO,cAAO;AAE9B,SAAO,iBAAiB,QAAQ,GAAG;AACrC;;;ADFA,SAAS,oBAAoB,OAA4C;AACvE,SAAO,UAAU,YAAY,UAAU,UAAU,UAAU;AAC7D;AAEA,SAAS,UAAU,MAAgB;AACjC,QAAM,MAeF;AAAA,IACF,aAAa;AAAA,IACb,WAAW;AAAA,IACX,aAAa;AAAA,IACb,cAAc;AAAA,IACd,aAAa;AAAA,IACb,eAAe;AAAA,EACjB;AAEA,QAAM,CAAC,KAAK,GAAG,IAAI,IAAI;AACvB,MAAI,MAAM;AAEV,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,IAAI,KAAK,CAAC;AAEhB,QAAI,MAAM,WAAY,KAAI,aAAa,KAAK,EAAE,CAAC;AAAA,aACtC,EAAE,WAAW,WAAW,EAAG,KAAI,aAAa,EAAE,MAAM,KAAK,CAAC,EAAE,CAAC;AAAA,aAC7D,MAAM,aAAc,KAAI,UAAU,KAAK,EAAE,CAAC;AAAA,aAC1C,EAAE,WAAW,aAAa,EAAG,KAAI,UAAU,EAAE,MAAM,KAAK,CAAC,EAAE,CAAC;AAAA,aAC5D,MAAM,YAAY;AACzB,YAAM,IAAI,KAAK,EAAE,CAAC;AAClB,UAAI,oBAAoB,CAAC,EAAG,KAAI,cAAc;AAAA,UACzC,KAAI,qBAAqB,OAAO,CAAC;AAAA,IACxC,WAAW,EAAE,WAAW,WAAW,GAAG;AACpC,YAAM,IAAI,EAAE,MAAM,YAAY,MAAM;AACpC,UAAI,oBAAoB,CAAC,EAAG,KAAI,cAAc;AAAA,UACzC,KAAI,qBAAqB;AAAA,IAChC,WACS,MAAM,cAAe,KAAI,YAAY;AAAA,aAErC,MAAM,QAAS,KAAI,UAAU,KAAK,EAAE,CAAC;AAAA,aACrC,EAAE,WAAW,QAAQ,EAAG,KAAI,UAAU,EAAE,MAAM,KAAK,CAAC,EAAE,CAAC;AAAA,aACvD,MAAM,UAAU;AACvB,YAAM,IAAI,KAAK,EAAE,CAAC;AAClB,UAAI,MAAM,YAAY,MAAM,SAAU,KAAI,OAAO;AAAA,IACnD,WAAW,EAAE,WAAW,SAAS,GAAG;AAClC,YAAM,IAAI,EAAE,MAAM,KAAK,CAAC,EAAE,CAAC;AAC3B,UAAI,MAAM,YAAY,MAAM,SAAU,KAAI,OAAO;AAAA,IACnD,WAAW,MAAM,gBAAiB,KAAI,cAAc;AAAA,aAC3C,MAAM,kBAAmB,KAAI,eAAe;AAAA,aAC5C,MAAM,iBAAkB,KAAI,cAAc;AAAA,aAC1C,MAAM,mBAAoB,KAAI,gBAAgB;AAAA,EACzD;AAEA,SAAO;AACT;AAEA,SAAS,WAAW,YAAqC;AACvD,QAAM,MAAM,iBAAAC,QAAK,QAAQ,QAAQ,IAAI,GAAG,UAAU;AAClD,QAAM,MAAM,eAAAC,QAAG,aAAa,KAAK,MAAM;AAGvC,QAAM,OAAO,KAAK,MAAM,GAAG;AAE3B,MAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,MAAM,QAAQ,IAAI,GAAG;AAC5D,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAChE;AAGA,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,IAAI,GAAG;AACzC,QAAI;AACF,oBAAc,CAAmB;AAAA,IACnC,SAAS,GAAG;AACV,YAAM,IAAI,MAAM,6BAA6B,CAAC,MAAM,OAAO,CAAC,CAAC,EAAE;AAAA,IACjE;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,SACP,WACA,SACoC;AACpC,QAAM,MAA0C,EAAE,GAAG,QAAQ,IAAI;AAEjE,MAAI,CAAC,UAAW,QAAO;AAEvB,QAAM,IAAI,WAAW;AACrB,QAAM,aAAa,iBAAAD,QAAK,QAAQ,QAAQ,IAAI,GAAG,CAAC;AAEhD,MAAI,eAAAC,QAAG,WAAW,UAAU,GAAG;AAC7B,UAAM,UAAU,eAAAA,QAAG,aAAa,YAAY,MAAM;AAClD,UAAM,SAAgB,cAAM,OAAO;AACnC,WAAO,OAAO,KAAK,MAAM;AAAA,EAC3B;AAEA,SAAO;AACT;AAIA,SAAS,YAAY,UAA0C;AAC7D,MAAI,CAAC,eAAAA,QAAG,WAAW,QAAQ,EAAG,QAAO,CAAC;AAEtC,QAAM,MAAM,eAAAA,QAAG,aAAa,UAAU,MAAM,EAAE,QAAQ,gBAAgB,EAAE;AACxE,SAAc,cAAM,GAAG;AACzB;AAEA,SAAS,aAAa,MAA8B;AAElD,MAAI,OAAO,SAAS,SAAU,QAAO;AACrC,SAAQ,KAAa;AACvB;AAEA,SAAS,mBAAmB,GAAoB;AAC9C,MAAI,MAAM,UAAa,MAAM,KAAM,QAAO;AAC1C,MAAI,OAAO,MAAM,SAAU,QAAO;AAClC,MAAI,OAAO,MAAM,YAAY,OAAO,MAAM,UAAW,QAAO,OAAO,CAAC;AAGpE,SAAO,KAAK,UAAU,CAAC;AACzB;AAEA,SAAS,aAAa,GAAoB;AACxC,MAAI,MAAM,GAAI,QAAO;AACrB,SAAO,YAAY,KAAK,CAAC;AAC3B;AAEA,SAAS,cAAc,KAAa,OAAe,SAA0B;AAC3E,QAAM,OAAO,aAAa,KAAK,IAAI,KAAK,UAAU,KAAK,IAAI;AAC3D,SAAO,UAAU,GAAG,GAAG,IAAI,IAAI,MAAM,OAAO,KAAK,GAAG,GAAG,IAAI,IAAI;AACjE;AAEA,SAAS,qBAAqB,GAAmB;AAC/C,SAAO,EACJ,QAAQ,WAAW,GAAG,EACtB,QAAQ,QAAQ,GAAG,EACnB,KAAK;AACV;AAEA,SAAS,mBAAmB,aAAsB,SAA4B;AAC5E,QAAM,QAAkB,CAAC;AAEzB,MAAI,OAAO,gBAAgB,UAAU;AACnC,UAAM,IAAI,qBAAqB,WAAW;AAC1C,QAAI,EAAG,OAAM,KAAK,KAAK,CAAC,EAAE;AAAA,EAC5B;AAEA,MAAI,OAAO,YAAY,UAAU;AAC/B,UAAM,KAAK,qBAAqB,OAAO;AACvC,QAAI,GAAI,OAAM,KAAK,cAAc,EAAE,EAAE;AAAA,EACvC;AAEA,SAAO;AACT;AAEA,SAAS,YACP,QACA,SACA,MACA,aACA,cACA,aACA,eACA,IACQ;AACR,QAAM,SAAS,iBAAAD,QAAK,QAAQ,QAAQ,IAAI,GAAG,OAAO;AAElD,MAAI,SAAS,YAAY,eAAAC,QAAG,WAAW,MAAM,GAAG;AAC9C,OAAG,MAAM,wCAAwC,OAAO,EAAE;AAC1D,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,SAAS,WAAW,YAAY,MAAM,IAAI,CAAC;AAC5D,QAAM,OAAO,OAAO,KAAK,MAAM,EAAE,KAAK;AAEtC,QAAM,aAAuB,CAAC;AAC9B,MAAI,YAAY;AAEhB,aAAW,OAAO,MAAM;AACtB,QAAI,SAAS,GAAG,MAAM,OAAW;AAEjC,UAAM,OAAO,OAAO,GAAG;AACvB,UAAM,KAAK,cAAc,IAAI;AAC7B,UAAM,YAAY,eAAe,aAAa,IAAI,IAAI;AAEtD,QAAI,MAAM;AAEV,QAAI,iBAAiB,GAAG,YAAY,QAAW;AAC7C,YAAM,GAAG;AAAA,IACX,WAAW,aAAa;AACtB,UAAI,GAAG,iBAAiB,QAAW;AACjC,cAAM,mBAAmB,GAAG,YAAY;AAAA,MAC1C;AAAA,IACF;AAEA,QAAI,aAAa;AACf,iBAAW,KAAK,GAAG,mBAAmB,GAAG,aAAa,GAAG,OAAO,CAAC;AAAA,IACnE;AAEA,eAAW,KAAK,cAAc,KAAK,KAAK,SAAS,CAAC;AAClD;AAAA,EACF;AAEA,MAAI,cAAc,GAAG;AACnB,OAAG,IAAI,mDAA8C;AACrD,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,UAAU;AACrB,mBAAAA,QAAG,cAAc,QAAQ,WAAW,KAAK,IAAI,IAAI,MAAM,MAAM;AAC7D,OAAG,IAAI,kBAAa,OAAO,SAAS,SAAS,aAAa;AAC1D,WAAO;AAAA,EACT;AAGA,QAAM,SAAS,eAAAA,QAAG,WAAW,MAAM,IAAI,OAAO;AAC9C,iBAAAA,QAAG,eAAe,QAAQ,SAAS,WAAW,KAAK,IAAI,IAAI,MAAM,MAAM;AACvE,KAAG,IAAI,kBAAa,OAAO,WAAW,SAAS,qBAAqB;AACpE,SAAO;AACT;AAEA,SAAS,mBAAmB,SAAyB;AACnD,QAAM,MAAM;AACZ,QAAM,IAAI,QAAQ,QAAQ,GAAG;AAC7B,MAAI,KAAK,GAAG;AACV,WAAO,GAAG,QAAQ,MAAM,GAAG,CAAC,CAAC;AAAA,EAC/B;AACA,SAAO;AACT;AAEA,SAAS,YAAY,QAAyB,KAAsB;AAClE,QAAM,OAAO,OAAO,GAAG;AACvB,MAAI,SAAS,OAAW,QAAO;AAE/B,MAAI;AACF,UAAM,KAAK,cAAc,IAAI;AAC7B,WAAO,GAAG,WAAW;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,gBACP,OACA,QACQ;AACR,QAAM,SAAS,MAAM,SAAS,aAAa,YAAY,QAAQ,MAAM,GAAG;AACxE,SAAO,SAAS,mBAAmB,MAAM,OAAO,IAAI,MAAM;AAC5D;AAEA,SAAS,wBAAwB,OAAuB;AACtD,SAAO,MAAM,QAAQ,MAAM,KAAK,EAAE,QAAQ,OAAO,KAAK,EAAE,QAAQ,OAAO,KAAK;AAC9E;AAEA,SAAS,4BAA4B,OAAuB;AAC1D,SAAO,wBAAwB,KAAK,EACjC,QAAQ,MAAM,KAAK,EACnB,QAAQ,MAAM,KAAK;AACxB;AAEA,SAAS,4BACP,KACA,QACA,QACU;AACV,QAAM,SAAS,IAAI,OAAO,IAAI,CAAC,UAAU;AACvC,UAAM,UAAU,gBAAgB,OAAO,MAAM;AAC7C,WAAO,EAAE,KAAK,MAAM,KAAK,MAAM,MAAM,MAAM,QAAQ;AAAA,EACrD,CAAC;AAED,MAAI,WAAW,UAAU;AACvB,UAAM,QAAQ,4BAA4B,gBAAgB;AAC1D,WAAO,OAAO;AAAA,MACZ,CAAC,UACC,iBAAiB,KAAK,KAAK,wBAAwB,GAAG,MAAM,GAAG,KAAK,MAAM,OAAO,EAAE,CAAC;AAAA,IACxF;AAAA,EACF;AAEA,MAAI,WAAW,QAAQ;AACrB,WAAO,CAAC,KAAK,UAAU,EAAE,OAAO,yBAAyB,OAAO,CAAC,CAAC;AAAA,EACpE;AAEA,QAAM,SAAS;AACf,QAAM,QAAQ,OAAO,IAAI,CAAC,UAAU,KAAK,MAAM,GAAG,KAAK,MAAM,OAAO,EAAE;AACtE,SAAO,CAAC,CAAC,QAAQ,GAAG,KAAK,EAAE,KAAK,IAAI,CAAC;AACvC;AAIO,SAAS,OAAO,MAAgB,KAAS,SAAiB;AAC/D,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,UAAU,IAAI;AAElB,MAAI,CAAC,OAAO,QAAQ,UAAU,QAAQ,YAAY,QAAQ,MAAM;AAC9D,OAAG;AAAA,MACD;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,IAAI;AAAA,IACb;AACA,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,YAAY;AACf,OAAG,MAAM,0CAA0C;AACnD,WAAO;AAAA,EACT;AAEA,MAAI,QAAQ,WAAW,uBAAuB,QAAW;AACvD,OAAG;AAAA,MACD,gCAAgC,kBAAkB;AAAA,IACpD;AACA,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,SAAS,WAAW,UAAU;AAEpC,QAAI,QAAQ,SAAS;AACnB,YAAM,MAAM,SAAS,WAAW,OAAO;AACvC,UAAI;AACF,kBAAU,QAAQ,EAAE,YAAY,OAAO,IAAI,CAAC;AAAA,MAC9C,SAAS,GAAG;AACV,YAAI,aAAa,gBAAgB;AAC/B,qBAAW,QAAQ,4BAA4B,GAAG,QAAQ,WAAW,GAAG;AACtE,eAAG,MAAM,IAAI;AAAA,UACf;AACA,iBAAO;AAAA,QACT;AACA,cAAM;AAAA,MACR;AACA,SAAG,IAAI,8BAAyB;AAChC,aAAO;AAAA,IACT;AAEA,QAAI,QAAQ,YAAY;AACtB,YAAM,MAAM,WAAW;AACvB,YAAM,IAAI,QAAQ;AAClB,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,OAAG,MAAM,oBAAoB,GAAG,EAAE;AAClC,WAAO;AAAA,EACT,SAAS,GAAG;AACV,OAAG,MAAM,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC;AACnD,WAAO;AAAA,EACT;AACF;","names":["dotenv","path","fs"]}