{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import fs from 'fs'\nimport path from 'path'\n\ntype EnvSchema = {\n  name: string\n  constraints: {\n    optional: boolean\n    number: boolean\n  }\n}[]\n\ntype EnvVariable = {\n  name: string\n  value: string | undefined\n}\n\ntype EnvVariables = EnvVariable[]\n\ntype dotenvErrorsCode = 'empty' | 'invalid_type' | 'file_not_found' | 'missing'\n\ntype dotenvErrors = {\n  code?: dotenvErrorsCode\n  variable?: string\n  expected?: string\n}\n\ntype dotenvResult = {\n  errors: dotenvErrors[]\n  success: boolean\n}\nexport const validateEnv = (config?: {\n  dotenvPath?: string\n  schemaPath?: string\n}): dotenvResult => {\n  const appRoot = process.cwd()\n  let envFile: string\n  let envSchemaFile: string\n\n  try {\n    envFile = fs.readFileSync(\n      path.join(appRoot, config?.dotenvPath ?? '.env'),\n      'utf8'\n    )\n    envSchemaFile = fs.readFileSync(\n      path.join(appRoot, config?.schemaPath ?? '.env.schema'),\n      'utf8'\n    )\n  } catch (error) {\n    return {\n      errors: [\n        {\n          code: 'file_not_found',\n        },\n      ],\n      success: false,\n    }\n  }\n\n  const envVariables: EnvVariables = extractEnvVariables(envFile)\n  const envSchema = extractEnvSchema(envSchemaFile)\n\n  const result = checkConstraints(envVariables, envSchema)\n\n  return {\n    errors: result,\n    success: result.length === 0,\n  }\n}\n\nconst extractEnvVariables = (dotenvFile: string) => {\n  const envVariables: EnvVariables = []\n  for (const line of dotenvFile.split('\\n')) {\n    if (line.includes('=')) {\n      const [name, value] = line.split('=')\n      envVariables.push({ name, value })\n    }\n  }\n  return envVariables\n}\n\nconst extractEnvSchema = (schemaFile: string) => {\n  const schema: EnvSchema = []\n  for (const line of schemaFile.split('\\n')) {\n    if (line.includes('=')) {\n      const name = line.split('=')[0]\n      const optional = line.includes('#optional')\n      const number = line.includes('#number')\n      schema.push({ name, constraints: { optional, number } })\n    }\n  }\n  return schema\n}\n\nconst checkConstraints = (envVariables: EnvVariables, envSchema: EnvSchema) => {\n  const errors: dotenvErrors[] = []\n  for (const { name, constraints } of envSchema) {\n    const envVariable = envVariables.find((v) => v.name === name)\n    if (!envVariable && !constraints.optional) {\n      errors.push({\n        variable: name,\n        code: 'missing',\n      })\n    } else if (envVariable) {\n      if (constraints.number) {\n        const result = isNumber(envVariable)\n        if (result !== true) {\n          errors.push(result)\n        }\n      }\n      if (!constraints.optional) {\n        const result = isRequired(envVariable)\n        if (result !== true) {\n          errors.push(result)\n        }\n      }\n    }\n  }\n  return errors\n}\n\nconst isRequired = (envVariable: EnvVariable): dotenvErrors | true => {\n  if (!envVariable.value) {\n    return {\n      variable: envVariable.name,\n      code: 'empty',\n    }\n  }\n  return true\n}\n\nconst isNumber = (envVariable: EnvVariable): dotenvErrors | true => {\n  if (envVariable.value && isNaN(Number(envVariable.value))) {\n    return {\n      variable: envVariable.name,\n      code: 'invalid_type',\n      expected: 'number',\n    }\n  }\n  return true\n}\n\nexport default {\n  validateEnv,\n}\n"],"mappings":";AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AA6BV,IAAM,cAAc,CAAC,WAGR;AAjCpB;AAkCE,QAAM,UAAU,QAAQ,IAAI;AAC5B,MAAI;AACJ,MAAI;AAEJ,MAAI;AACF,cAAU,GAAG;AAAA,MACX,KAAK,KAAK,UAAS,sCAAQ,eAAR,YAAsB,MAAM;AAAA,MAC/C;AAAA,IACF;AACA,oBAAgB,GAAG;AAAA,MACjB,KAAK,KAAK,UAAS,sCAAQ,eAAR,YAAsB,aAAa;AAAA,MACtD;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,WAAO;AAAA,MACL,QAAQ;AAAA,QACN;AAAA,UACE,MAAM;AAAA,QACR;AAAA,MACF;AAAA,MACA,SAAS;AAAA,IACX;AAAA,EACF;AAEA,QAAM,eAA6B,oBAAoB,OAAO;AAC9D,QAAM,YAAY,iBAAiB,aAAa;AAEhD,QAAM,SAAS,iBAAiB,cAAc,SAAS;AAEvD,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,SAAS,OAAO,WAAW;AAAA,EAC7B;AACF;AAEA,IAAM,sBAAsB,CAAC,eAAuB;AAClD,QAAM,eAA6B,CAAC;AACpC,aAAW,QAAQ,WAAW,MAAM,IAAI,GAAG;AACzC,QAAI,KAAK,SAAS,GAAG,GAAG;AACtB,YAAM,CAAC,MAAM,KAAK,IAAI,KAAK,MAAM,GAAG;AACpC,mBAAa,KAAK,EAAE,MAAM,MAAM,CAAC;AAAA,IACnC;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAM,mBAAmB,CAAC,eAAuB;AAC/C,QAAM,SAAoB,CAAC;AAC3B,aAAW,QAAQ,WAAW,MAAM,IAAI,GAAG;AACzC,QAAI,KAAK,SAAS,GAAG,GAAG;AACtB,YAAM,OAAO,KAAK,MAAM,GAAG,EAAE,CAAC;AAC9B,YAAM,WAAW,KAAK,SAAS,WAAW;AAC1C,YAAM,SAAS,KAAK,SAAS,SAAS;AACtC,aAAO,KAAK,EAAE,MAAM,aAAa,EAAE,UAAU,OAAO,EAAE,CAAC;AAAA,IACzD;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAM,mBAAmB,CAAC,cAA4B,cAAyB;AAC7E,QAAM,SAAyB,CAAC;AAChC,aAAW,EAAE,MAAM,YAAY,KAAK,WAAW;AAC7C,UAAM,cAAc,aAAa,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAC5D,QAAI,CAAC,eAAe,CAAC,YAAY,UAAU;AACzC,aAAO,KAAK;AAAA,QACV,UAAU;AAAA,QACV,MAAM;AAAA,MACR,CAAC;AAAA,IACH,WAAW,aAAa;AACtB,UAAI,YAAY,QAAQ;AACtB,cAAM,SAAS,SAAS,WAAW;AACnC,YAAI,WAAW,MAAM;AACnB,iBAAO,KAAK,MAAM;AAAA,QACpB;AAAA,MACF;AACA,UAAI,CAAC,YAAY,UAAU;AACzB,cAAM,SAAS,WAAW,WAAW;AACrC,YAAI,WAAW,MAAM;AACnB,iBAAO,KAAK,MAAM;AAAA,QACpB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAM,aAAa,CAAC,gBAAkD;AACpE,MAAI,CAAC,YAAY,OAAO;AACtB,WAAO;AAAA,MACL,UAAU,YAAY;AAAA,MACtB,MAAM;AAAA,IACR;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAM,WAAW,CAAC,gBAAkD;AAClE,MAAI,YAAY,SAAS,MAAM,OAAO,YAAY,KAAK,CAAC,GAAG;AACzD,WAAO;AAAA,MACL,UAAU,YAAY;AAAA,MACtB,MAAM;AAAA,MACN,UAAU;AAAA,IACZ;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAO,gBAAQ;AAAA,EACb;AACF;","names":[]}