{"version":3,"file":"index.mjs","names":["info: T","options?: Options","errors: EnvError[]","config: Record<string, unknown>"],"sources":["../src/index.ts"],"sourcesContent":["interface ArgInfoType {\n  type: 'number' | 'string' | 'array' | 'boolean';\n}\n\ninterface ArgInfoParser {\n  parser: (input: string) => unknown;\n}\n\ninterface ArgInfoOptional {\n  optional?: boolean;\n}\n\ninterface ArgInfoDefault {\n  default?: unknown;\n}\n\ninterface ArgInfoChoices {\n  choices?: readonly unknown[];\n}\n\ntype ArgInfo = (ArgInfoType | ArgInfoParser) & ArgInfoOptional & ArgInfoDefault & ArgInfoChoices;\n\ninterface MappedArgType<Choice> {\n  string: Choice extends (infer U)[] ? U : string;\n  number: Choice extends (infer U)[] ? U : number;\n  boolean: boolean;\n  array: string[];\n}\n\ntype Mutable<T> = { -readonly [P in keyof T]: T[P] };\n\ntype GetArgTypeInner<T extends ArgInfo> = T extends ArgInfoParser\n  ? ReturnType<T['parser']>\n  : T extends ArgInfoType\n    ? MappedArgType<Mutable<T['choices']>>[T['type']]\n    : never;\n\ntype GetArgTypeOptional<T extends ArgInfo> = T extends ArgInfoDefault ? T['default'] : undefined;\n\ntype GetArgType<T extends ArgInfo> = T extends ArgInfoOptional\n  ? GetArgTypeInner<T> | GetArgTypeOptional<T>\n  : GetArgTypeInner<T>;\n\ntype ArgReturnType<T extends Record<string, ArgInfo>> = {\n  [K in keyof T]: GetArgType<T[K]>;\n};\n\nexport interface Options {\n  env?: Record<string, string> | NodeJS.ProcessEnv;\n}\n\nexport type Config = Record<string, ArgInfo>;\n\ninterface CustomEnvError {\n  key: string;\n  value: string;\n  error: unknown;\n  kind: 'custom';\n}\n\ninterface ChoiceEnvError {\n  key: string;\n  value: string;\n  expected: readonly unknown[];\n  kind: 'choice';\n}\n\ninterface NumberEnvError {\n  key: string;\n  value: string;\n  kind: 'number';\n}\n\ninterface MissingEnvError {\n  key: string;\n  kind: 'missing';\n}\n\ntype EnvError = CustomEnvError | ChoiceEnvError | NumberEnvError | MissingEnvError;\n\nexport function createEnv<const T extends Config>(info: T, options?: Options): ArgReturnType<T> {\n  const env = options?.env ?? (typeof process !== 'undefined' ? process.env : null);\n\n  if (!env) {\n    throw new TypeError('No env specified');\n  }\n\n  const errors: EnvError[] = [];\n  const config: Record<string, unknown> = {};\n\n  for (const [key, argInfo] of Object.entries(info)) {\n    const value = env[key];\n\n    if (!value) {\n      if ('default' in argInfo) {\n        config[key] = argInfo.default;\n      } else if (!argInfo.optional) {\n        errors.push({ key, kind: 'missing' });\n      }\n\n      continue;\n    }\n\n    if ('parser' in argInfo) {\n      try {\n        config[key] = argInfo.parser(value);\n      } catch (error) {\n        errors.push({ key, value, kind: 'custom', error });\n      }\n\n      continue;\n    }\n\n    if (argInfo.choices && !argInfo.choices.includes(value)) {\n      errors.push({ key, value, kind: 'choice', expected: argInfo.choices });\n      continue;\n    }\n\n    switch (argInfo.type) {\n      case 'string':\n        config[key] = value;\n        break;\n      case 'number': {\n        const numberValue = Number(value);\n        if (Number.isNaN(numberValue)) {\n          errors.push({ key, value, kind: 'number' });\n          continue;\n        }\n        config[key] = numberValue;\n        break;\n      }\n      case 'boolean':\n        config[key] = value.toLowerCase() === 'true' || value === '1';\n        break;\n      case 'array':\n        config[key] = value.split(/, ?/gu);\n        break;\n    }\n  }\n\n  if (errors.length !== 0) {\n    let message = 'The following environment variables are invalid:\\n';\n\n    for (const error of errors) {\n      switch (error.kind) {\n        case 'missing':\n          message += `  ${error.key} (missing)\\n`;\n          break;\n        case 'number':\n          message += `  ${error.key}: ${error.value} (expected number)\\n`;\n          break;\n        case 'choice':\n          message += `  ${error.key}: ${error.value} (expected one of ${error.expected.join(', ')})\\n`;\n          break;\n        case 'custom':\n          message += `  ${error.key}: ${error.value} (${error.error})\\n`;\n          break;\n      }\n    }\n    throw new TypeError(message);\n  }\n\n  return config as ArgReturnType<T>;\n}\n"],"mappings":";AAgFA,SAAgB,UAAkCA,MAASC,SAAqC;CAC9F,MAAM,MAAM,SAAS,eAAe,YAAY,cAAc,QAAQ,MAAM;AAE5E,MAAK,IACH,OAAM,IAAI,UAAU;CAGtB,MAAMC,SAAqB,CAAE;CAC7B,MAAMC,SAAkC,CAAE;AAE1C,MAAK,MAAM,CAAC,KAAK,QAAQ,IAAI,OAAO,QAAQ,KAAK,EAAE;EACjD,MAAM,QAAQ,IAAI;AAElB,OAAK,OAAO;AACV,OAAI,aAAa,QACf,QAAO,OAAO,QAAQ;aACZ,QAAQ,SAClB,QAAO,KAAK;IAAE;IAAK,MAAM;GAAW,EAAC;AAGvC;EACD;AAED,MAAI,YAAY,SAAS;AACvB,OAAI;AACF,WAAO,OAAO,QAAQ,OAAO,MAAM;GACpC,SAAQ,OAAO;AACd,WAAO,KAAK;KAAE;KAAK;KAAO,MAAM;KAAU;IAAO,EAAC;GACnD;AAED;EACD;AAED,MAAI,QAAQ,YAAY,QAAQ,QAAQ,SAAS,MAAM,EAAE;AACvD,UAAO,KAAK;IAAE;IAAK;IAAO,MAAM;IAAU,UAAU,QAAQ;GAAS,EAAC;AACtE;EACD;AAED,UAAQ,QAAQ,MAAhB;GACE,KAAK;AACH,WAAO,OAAO;AACd;GACF,KAAK,UAAU;IACb,MAAM,cAAc,OAAO,MAAM;AACjC,QAAI,OAAO,MAAM,YAAY,EAAE;AAC7B,YAAO,KAAK;MAAE;MAAK;MAAO,MAAM;KAAU,EAAC;AAC3C;IACD;AACD,WAAO,OAAO;AACd;GACD;GACD,KAAK;AACH,WAAO,OAAO,MAAM,aAAa,KAAK,UAAU,UAAU;AAC1D;GACF,KAAK;AACH,WAAO,OAAO,MAAM,MAAM,QAAQ;AAClC;EACH;CACF;AAED,KAAI,OAAO,WAAW,GAAG;EACvB,IAAI,UAAU;AAEd,OAAK,MAAM,SAAS,OAClB,SAAQ,MAAM,MAAd;GACE,KAAK;AACH,gBAAY,IAAI,MAAM,IAAI;AAC1B;GACF,KAAK;AACH,gBAAY,IAAI,MAAM,IAAI,IAAI,MAAM,MAAM;AAC1C;GACF,KAAK;AACH,gBAAY,IAAI,MAAM,IAAI,IAAI,MAAM,MAAM,oBAAoB,MAAM,SAAS,KAAK,KAAK,CAAC;AACxF;GACF,KAAK;AACH,gBAAY,IAAI,MAAM,IAAI,IAAI,MAAM,MAAM,IAAI,MAAM,MAAM;AAC1D;EACH;AAEH,QAAM,IAAI,UAAU;CACrB;AAED,QAAO;AACR"}