dotenvxjs
Version:
dotenvx is the official Node.js library for .envx files, offering advanced type validation, intelligent interpolation, and conditional logic. It makes environment management safer, more dynamic, and easier to maintain.
10 lines • 11.9 kB
JavaScript
;var commander=require('commander'),E=require('path'),url=require('url'),fs=require('fs'),S=require('fs/promises'),ie=require('readline');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var E__default=/*#__PURE__*/_interopDefault(E);var S__default=/*#__PURE__*/_interopDefault(S);var ie__default=/*#__PURE__*/_interopDefault(ie);var R={version:"0.0.102"};async function T(){let n=E__default.default.resolve(process.cwd(),"envx.config.js");if(fs.existsSync(n)){let t=await import(url.pathToFileURL(n).href);return t.default||t}return {}}var k={fileDoesNotExist:e=>`[envx:error] The specified file does not exist: ${e}`,unsupportedType:(e,n)=>`[envx:error] Line ${e+1}: Unsupported type "${n}".`,validator:{invalidNumber:(e,n)=>`Invalid value for "${e}": expected a number but received "${n}".`,invalidBoolean:(e,n)=>`Invalid boolean for "${e}": expected "true" or "false" but received "${n}".`,missingEnumValues:e=>`Enum values are not defined for "${e}". Please specify allowed values.`,invalidEnum:(e,n,r)=>`Invalid enum value for "${e}": expected one of [${r.join(", ")}] but received "${n}".`,invalidEmail:(e,n)=>`Invalid email format for "${e}": received "${n}". Please provide a valid email address.`,invalidUrl:(e,n)=>`Invalid URL format for "${e}": received "${n}". Please provide a valid URL.`,unsupportedType:(e,n)=>`Unsupported type "${n}" specified for "${e}".`,requiredMissing:e=>`Required environment variable "${e}" is missing and has no default value.`},resolver:{circularDependency:e=>`[envx:error] Circular dependency detected while resolving "${e}".
\u2192 Check for variables referencing each other in a loop.`,interpolationFailed:e=>`[envx:error] Failed to resolve variable "${e}". No value found for interpolation.`,requiredMissingInResolve:e=>`[envx:error] Environment variable "${e}" is not set and no default is defined.
\u2192 Define "${e}" in your .envx file or provide a default value in the schema.`},parser:{schemaBlockEmpty:e=>`[envx:error] Line ${e+1}: Schema block name cannot be empty.`,schemaKeyDuplicate:(e,n)=>`[envx:error] Line ${e+1}: Schema key "${n}" is already defined. Duplicate schema definitions are not allowed.`,typeAlreadyDefined:e=>`[envx:error] Line ${e+1}: "type" is already defined for this variable. You cannot redefine it.`,unknownSchemaProperty:(e,n)=>`[envx:error] Line ${e+1}: Unknown schema property "${n}".`,missingDelimiter:e=>`[envx:error] Line ${e+1}: Missing "=" delimiter in assignment.`,variableNameEmpty:e=>`[envx:error] Line ${e+1}: Variable name cannot be empty.`,typeRequiredBeforeDefault:e=>`[envx:error] Line ${e+1}: "type" must be defined before "default".`,defaultMustBeNumber:e=>`[envx:error] Line ${e+1}: Default value must be a valid number.`,defaultMustBeBoolean:e=>`[envx:error] Line ${e+1}: Default value must be "true" or "false".`,defaultNotInEnum:(e,n)=>`[envx:error] Line ${e+1}: Default "${n}" is not in enum values.`,invalidValuesJson:e=>`[envx:error] Line ${e+1}: "values" must be a valid JSON string array.`}};var c={lib:k};var M=["string","number","boolean","enum","email","url"],L={};var a=class extends Error{constructor(n){super(n),this.name="EnvError";}};function y(e){let n=e.split(/\r?\n/),r=[],t={},o=null,i=null,s=[];for(let l=0;l<n.length;l++){let p=n[l],u=p.trim();if(!u||u.startsWith("#"))continue;if(i){u.endsWith('"""')?(s.push(u.slice(0,-3)),r.push({key:i,value:s.join(`
`)}),i=null,s=[]):s.push(p);continue}if(Q(u)){o=W(u,l,t);continue}if(o){z(u,l,t[o]);continue}let{key:d,value:f,isMultilineStart:g}=X(u,l);g?(i=d,s.push(f)):r.push({key:d,value:f});}return {env:r,schema:t}}function W(e,n,r){let t=e.slice(1,-1).trim();if(!t)throw new a(c.lib.parser.schemaBlockEmpty(n));if(r[t])throw new a(c.lib.parser.schemaKeyDuplicate(n,t));return r[t]=r[t]??{},t}function z(e,n,r){let[t,o]=I(e,n),i=t.trim(),s=O(o.trim());switch(i){case "required":r.required=s==="true";break;case "type":if(r.type!==void 0)throw new a(c.lib.parser.typeAlreadyDefined(n));if(!M.includes(s))throw new a(c.lib.unsupportedType(n,s));r.type=s;break;case "default":Y(s,n,r);break;case "values":try{let l=JSON.parse(s);if(!Array.isArray(l)||!l.every(p=>typeof p=="string"))throw new a(`[envx:error] Line ${n+1}: The parsed "values" field must be an array of strings. Please ensure the JSON array contains only string elements.`);r.values=l;}catch{throw new a(c.lib.parser.invalidValuesJson(n))}break;case "deprecated":r.deprecated=s;break;case "description":r.description=s;break;default:throw new a(c.lib.parser.unknownSchemaProperty(n,i))}}function Q(e){return /^\[.*\]$/.test(e)}function Y(e,n,r){let{type:t,values:o}=r;if(!t)throw new a(c.lib.parser.typeRequiredBeforeDefault(n));switch(t){case "number":let i=Number(e);if(isNaN(i))throw new a(c.lib.parser.defaultMustBeNumber(n));r.default=i;break;case "boolean":if(e!=="true"&&e!=="false")throw new a(c.lib.parser.defaultMustBeBoolean(n));r.default=e==="true";break;case "enum":if(!o||!o.includes(e))throw new a(c.lib.parser.defaultNotInEnum(n,e));r.default=e;break;default:r.default=e;}}function X(e,n){let[r,t]=I(e,n),o=r.trim();if(!o)throw new a(c.lib.parser.variableNameEmpty(n));let i=t.trim();return i.startsWith('"""')?{key:o,value:i.slice(3),isMultilineStart:true}:{key:o,value:O(i),isMultilineStart:false}}function I(e,n){let r=e.indexOf("=");if(r===-1)throw new a(c.lib.parser.missingDelimiter(n));return [e.slice(0,r),e.slice(r+1)]}function O(e){let n=e[0],r=e[e.length-1];return n==='"'&&r==='"'||n==="'"&&r==="'"?e.slice(1,-1):e}function F(e){if(typeof e=="boolean")return e;if(typeof e=="string"){if(e.toLowerCase()==="true")return true;if(e.toLowerCase()==="false")return false}return typeof e=="number"?e===1:false}var B=e=>/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e);function Z(e){return typeof e=="boolean"?"boolean":!isNaN(Number(e))&&e!==""&&e!==null?"number":"string"}function h(e,n){let r={...L,...n};return e.forEach(({key:t,value:o})=>{r[t]||(r[t]={type:Z(o),required:false});}),r}function P(e,n,r,t){switch(r){case "string":return n;case "number":{let o=Number(n);if(isNaN(o))throw new a(c.lib.validator.invalidNumber(e,n));return o}case "boolean":{let o=n.trim().toLowerCase();if(o==="true")return true;if(o==="false")return false;throw new a(c.lib.validator.invalidBoolean(e,n))}case "enum":{if(!t?.length)throw new a(c.lib.validator.missingEnumValues(e));if(!t.includes(n))throw new a(c.lib.validator.invalidEnum(e,n,t));return n}case "email":{if(!B(n))throw new a(c.lib.validator.invalidEmail(e,n));return n}case "url":try{return new URL(n),n}catch{throw new a(c.lib.validator.invalidUrl(e,n))}default:throw new a(c.lib.validator.unsupportedType(e,r))}}function V(e,n){let r={},t=new Map(e.map(({key:o,value:i})=>[o,i]));for(let o in n){let{type:i,required:s,default:l,values:p}=n[o],u=t.get(o);if(u!==void 0){r[o]=P(o,u,i,i==="enum"?p:void 0);continue}if(l!==void 0){r[o]=P(o,String(l),i,i==="enum"?p:void 0);continue}if(s)throw new a(c.lib.validator.requiredMissing(o))}for(let[o,i]of t.entries())o in r||(r[o]=i);return r}function j(e,n){let r={},t={};for(let i of e)r[i.key]=i.value;if(n)for(let i in n)r[i]===void 0&&n[i].default!==void 0&&(r[i]=n[i].default);let o=new Set;for(let i of Object.keys(r))t[i]=x(r[i],r,t,o,i);if(n){for(let i in n)if(n[i].required&&r[i]===void 0)throw new a(c.lib.resolver.requiredMissingInResolve(i))}return t}function x(e,n,r,t,o){if(typeof e!="string")return e;if(t.has(o))throw new a(c.lib.resolver.circularDependency(o));return t.add(o),re(e)&&(e=te(e,n,r,t)),ee(e)&&(e=ne(e,n,r,t)),t.delete(o),e}function ee(e){return typeof e=="string"&&e.includes("${")}function ne(e,n,r,t){return e.replace(/\${([^}]+)}/g,(o,i)=>{let s=i.trim();if(r[s]!==void 0)return String(r[s]);if(n[s]!==void 0)return String(x(n[s],n,r,t,s));throw new a(c.lib.resolver.interpolationFailed(s))})}function re(e){return /^\s*\${[^}]+}(?:\s*(==|!=)\s*"[^"]*")?\s*\?\s*"[^"]*"\s*:\s*"[^"]*"\s*$/.test(e.trim())}function te(e,n,r,t){let i=e.trim().match(/^\s*\${([^}]+)}(?:\s*(==|!=)\s*"([^"]*)")?\s*\?\s*"([^"]*)"\s*:\s*"([^"]*)"\s*$/);if(!i)return e;let[,s,l,p,u,d]=i,f=s.trim(),g=r[f]!==void 0?r[f]:x(n[f],n,r,t,f),b;if(l==="=="||l==="!="){let $=String(g)===p;b=l==="=="?$:!$;}else b=F(g);return b?u:d}function v(e,n){let{env:r,schema:t}=y(e),o=h(r,t),i=Object.keys(o).length>0?o:void 0,s=j(r,i);return i?{result:V(Object.entries(s).map(([p,u])=>({key:p,value:u})),i),schema:i}:{result:s,schema:i}}async function oe(e){return new Promise(n=>{let r=ie__default.default.createInterface({input:process.stdin,output:process.stdout,terminal:true});r.question(`\u26A0\uFE0F "${e}" exists. Overwrite? (y/N): `,t=>{r.close(),n(t.trim().toLowerCase()==="y");});})}async function N(e){let n=E__default.default.resolve(process.cwd(),e.input),r=E__default.default.resolve(process.cwd(),e.output),t=E__default.default.relative(process.cwd(),r);!e.overwrite&&fs.existsSync(r)&&(await oe(t)||(console.log("[envx:info] \u2716 Operation cancelled."),process.exit(0)));let i=await S__default.default.readFile(n,"utf-8"),s=v(i),l=Object.entries(s.result).map(([u,d])=>`${u}="${String(d).replace(/\n/g,"\\n")}"`).join(`
`),p=E__default.default.dirname(r);fs.existsSync(p)||await S__default.default.mkdir(p,{recursive:true}),await S__default.default.writeFile(r,l),console.log(`[envx:success] \u2714 .env file generated at: ${t}`);}async function q(e){try{let n=E__default.default.resolve(process.cwd(),e.input),r=await S__default.default.readFile(n,"utf-8"),t=v(r);console.log("[envx:success] \u2714 No validation errors found in .envx file.");}catch(n){console.error("[envx:error] \u2716 Error reading or validating .envx:",n.message||n),process.exit(1);}}async function A(e){try{let n=E__default.default.resolve(process.cwd(),e.input),r=await S__default.default.readFile(n,"utf-8"),t=v(r);console.log(JSON.stringify(t.result,null,2));}catch(n){console.error("[envx:error] \u2716 Error reading .envx file:",n.message||n),process.exit(1);}}function ue(e,n){switch(e){case "string":case "email":case "url":return "string";case "number":return "number";case "boolean":return "boolean";case "enum":return n.values&&n.values.length>1?n.values.map(r=>`"${r}"`).join(" | "):"string";default:return "any"}}function U(e){let n=[];n.push(`// AUTO GENERATED FILE - DO NOT EDIT
`),n.push("export interface Envx {");for(let r in e){let{type:t="string",required:o}=e[r],i=ue(t,e[r]),s=o?"":"?";n.push(` ${r}${s}: ${i};`);}return n.push(`}
`),n.join(`
`)}async function _(e){try{let n=E__default.default.resolve(process.cwd(),e.input),r=E__default.default.resolve(process.cwd(),e.output),t=E__default.default.relative(process.cwd(),r),o=await S__default.default.readFile(n,"utf-8"),{env:i,schema:s}=y(o),l=h(i,s),p=U(l);await S__default.default.writeFile(r,p),console.log(`[envx:sucess] \u2714 TypeScript definitions generated at: ${t}`);}catch(n){console.error("[envx:error] \u2716 Error generating types:",n.message||n),process.exit(1);}}async function me(){let e=new commander.Command,n=await T();e.name("dotenvx").description("Enhanced CLI for .envx - Manage .envx files effortlessly").version(R.version),e.command("build").description("Build .env file from .envx").option("-i, --input <file>","Input .envx file",n.input||".envx").option("-o, --output <file>","Output .env file",n.output?.env||".env").option("--overwrite","Overwrite output",n.overwrite||false).action(N),e.command("check").description("Validate .envx against its schema").option("-i, --input <file>","Input .envx file",n.input||".envx").action(q),e.command("print").description("Print parsed .envx as JSON").option("-i, --input <file>","Input .envx file",n.input||".envx").action(A),e.command("types").description("Generate TypeScript definitions from schema").option("-i, --input <file>","Input .envx file",n.input||".envx").option("-o, --output <file>","Output .ts file",n.output?.types||"envx.ts").action(_),e.parse();}me();//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map