dotenv-constraint
Version:
A lightweight package to enforce constraints on environment variables in JavaScript, ensuring required variables are defined and match expected types.
1 lines • 5.43 kB
Source Map (JSON)
{"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":[]}