@xlameiro/env-typegen 0.1.6 → 0.1.7

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/index.cjs CHANGED
@@ -252,6 +252,27 @@ function buildParsedVar(params, commentBlock, options) {
252
252
  }
253
253
  return parsedVar;
254
254
  }
255
+ function deduplicateVars(vars) {
256
+ const seenKeys = /* @__PURE__ */ new Set();
257
+ const deduped = [];
258
+ const warnings = [];
259
+ for (let i = vars.length - 1; i >= 0; i--) {
260
+ const variable = vars[i];
261
+ if (variable === void 0) continue;
262
+ if (seenKeys.has(variable.key)) {
263
+ warnings.push({
264
+ code: "ENV_DUPLICATE_KEY",
265
+ message: `Duplicate key "${variable.key}" at line ${variable.lineNumber} \u2014 last occurrence wins.`,
266
+ line: variable.lineNumber,
267
+ key: variable.key
268
+ });
269
+ } else {
270
+ seenKeys.add(variable.key);
271
+ deduped.unshift(variable);
272
+ }
273
+ }
274
+ return { deduped, warnings };
275
+ }
255
276
  function parseEnvFileContent(content, filePath, options) {
256
277
  const lines = content.split("\n");
257
278
  const vars = [];
@@ -294,16 +315,13 @@ function parseEnvFileContent(content, filePath, options) {
294
315
  );
295
316
  commentBlock = [];
296
317
  }
297
- const seenKeys = /* @__PURE__ */ new Set();
298
- const deduped = [];
299
- for (let i = vars.length - 1; i >= 0; i--) {
300
- const variable = vars[i];
301
- if (variable !== void 0 && !seenKeys.has(variable.key)) {
302
- seenKeys.add(variable.key);
303
- deduped.unshift(variable);
304
- }
305
- }
306
- return { filePath, vars: deduped, groups };
318
+ const { deduped, warnings } = deduplicateVars(vars);
319
+ return {
320
+ filePath,
321
+ vars: deduped,
322
+ groups,
323
+ ...warnings.length > 0 && { warnings }
324
+ };
307
325
  }
308
326
  function parseEnvFile(filePath) {
309
327
  const content = fs.readFileSync(filePath, "utf8");
@@ -566,7 +584,8 @@ async function readEnvFile(filePath) {
566
584
  return await promises.readFile(resolved, "utf8");
567
585
  } catch (err) {
568
586
  if (err instanceof Error && err.code === "ENOENT") {
569
- throw new Error(`File not found: ${filePath}`);
587
+ const displayPath = path6__default.default.isAbsolute(filePath) ? filePath : `${filePath} (resolved: ${resolved})`;
588
+ throw new Error(`File not found: ${displayPath}`);
570
589
  }
571
590
  throw err;
572
591
  }
@@ -620,7 +639,8 @@ function deriveOutputPath(base, generator, isSingle) {
620
639
  function deriveOutputBaseForInput(output, inputPath) {
621
640
  const dir = path6__default.default.dirname(output);
622
641
  const ext = path6__default.default.extname(output);
623
- const stem = path6__default.default.basename(inputPath, path6__default.default.extname(inputPath));
642
+ const rawBasename = path6__default.default.basename(inputPath);
643
+ const stem = rawBasename.startsWith(".") ? rawBasename.slice(1).replaceAll(".", "-") : path6__default.default.basename(inputPath, path6__default.default.extname(inputPath));
624
644
  return path6__default.default.join(dir, `${stem}${ext}`);
625
645
  }
626
646
  function buildOutput(generator, parsed) {
@@ -657,6 +677,12 @@ async function persistOutput(params) {
657
677
  success(`Generated ${outputPath}`);
658
678
  }
659
679
  }
680
+ function emitParserWarnings(parsed) {
681
+ if (parsed.warnings === void 0) return;
682
+ for (const w of parsed.warnings) {
683
+ warn(`[${w.code}] ${w.message}`);
684
+ }
685
+ }
660
686
  async function runGenerate(options) {
661
687
  const {
662
688
  input,
@@ -679,6 +705,7 @@ async function runGenerate(options) {
679
705
  inputPath,
680
706
  inferenceRules2 === void 0 ? void 0 : { inferenceRules: inferenceRules2 }
681
707
  );
708
+ emitParserWarnings(parsed);
682
709
  for (const generator of generators) {
683
710
  let generated = buildOutput(generator, parsed);
684
711
  if (shouldFormat && !dryRun) {
@@ -982,6 +1009,11 @@ function outputHuman(result) {
982
1009
  async function runCheck(opts) {
983
1010
  const contract = await resolveContract(opts.contract, opts.cwd);
984
1011
  const parsed = parseEnvFile(opts.input);
1012
+ if (parsed.warnings !== void 0) {
1013
+ for (const w of parsed.warnings) {
1014
+ warn(`[${w.code}] ${w.message}`);
1015
+ }
1016
+ }
985
1017
  const validatorOpts = {};
986
1018
  if (opts.environment !== void 0) validatorOpts.environment = opts.environment;
987
1019
  if (opts.strict !== void 0) validatorOpts.strict = opts.strict;
@@ -1066,7 +1098,8 @@ async function loadCloudSource(options) {
1066
1098
  raw = await promises.readFile(resolvedPath, "utf8");
1067
1099
  } catch (err) {
1068
1100
  if (err instanceof Error && err.code === "ENOENT") {
1069
- throw new Error(`File not found: ${options.filePath}`);
1101
+ const displayPath = path6__default.default.isAbsolute(options.filePath) ? options.filePath : `${options.filePath} (resolved: ${resolvedPath})`;
1102
+ throw new Error(`File not found: ${displayPath}`);
1070
1103
  }
1071
1104
  throw err;
1072
1105
  }
@@ -1898,7 +1931,8 @@ async function loadCommandConfig(configPath) {
1898
1931
  }
1899
1932
  const resolvedPath = path6__default.default.resolve(configPath);
1900
1933
  if (!fs.existsSync(resolvedPath)) {
1901
- throw new Error(`Config file not found: ${configPath}`);
1934
+ const displayPath = path6__default.default.isAbsolute(configPath) ? configPath : `${configPath} (resolved: ${resolvedPath})`;
1935
+ throw new Error(`Config file not found: ${displayPath}`);
1902
1936
  }
1903
1937
  const configDir = path6__default.default.dirname(resolvedPath);
1904
1938
  const moduleValue = await import(url.pathToFileURL(resolvedPath).href);