UNPKG

env-sentinel

Version:

Zero-dependency tool that auto-validates .env files against schema.env, with optional fallback and secure warnings.

104 lines (103 loc) 4.03 kB
export function generateDocsMarkdown(sections) { const lines = []; lines.push('# Environment Variables Configuration'); lines.push(''); lines.push('This document describes all environment variables used in this application.'); lines.push(''); if (sections.length === 0) { lines.push('No documented variables found.'); return lines.join('\n'); } const hasMultipleSections = sections.length > 1 || (sections.length === 1 && sections[0].name !== 'General'); if (hasMultipleSections) { lines.push('## Table of Contents'); lines.push(''); sections.forEach(section => { const anchor = section.name.toLowerCase().replace(/\s+/g, '-'); lines.push(`- [${section.name}](#${anchor})`); }); lines.push(''); lines.push('---'); lines.push(''); } sections.forEach(section => { lines.push(...generateSectionMarkdown(section, hasMultipleSections)); }); return lines.join('\n'); } function generateSectionMarkdown(section, showSectionHeader) { const lines = []; if (showSectionHeader) { lines.push(`## ${section.name}`); lines.push(''); if (section.description) { lines.push(section.description); lines.push(''); } } if (section.variables.length === 0) { if (showSectionHeader) { lines.push('*No variables in this section.*'); lines.push(''); } return lines; } const hasDescriptions = section.variables.some(v => v.description); if (hasDescriptions) { lines.push('| Variable | Description | Type | Required | Default | Constraints |'); lines.push('|----------|-------------|------|----------|---------|-------------|'); } else { lines.push('| Variable | Type | Required | Default | Constraints |'); lines.push('|----------|------|----------|---------|-------------|'); } section.variables.forEach(variable => { lines.push(generateVariableTableRow(variable, hasDescriptions)); }); lines.push(''); return lines; } function generateVariableTableRow(variable, includeDescription) { const isRequired = variable.rules.some(r => r.name === 'required'); const isSecure = variable.rules.some(r => r.name === 'secure'); const name = isSecure ? `🔒 \`${variable.key}\`` : `\`${variable.key}\``; const type = getVariableType(variable.rules); const typeFormatted = `\`${type}\``; const required = isRequired ? 'Yes' : 'No'; const defaultValue = variable.default ? `\`${variable.default}\`` : '-'; const constraints = getConstraints(variable.rules); const constraintsText = constraints.length > 0 ? constraints.join('<br>') : '-'; if (includeDescription) { const description = variable.description ? variable.description.replace(/\n/g, '<br>') : '-'; return `| ${name} | ${description} | ${typeFormatted} | ${required} | ${defaultValue} | ${constraintsText} |`; } else { return `| ${name} | ${typeFormatted} | ${required} | ${defaultValue} | ${constraintsText} |`; } } function getVariableType(rules) { const typeRule = rules.find(r => ['number', 'boolean', 'string'].includes(r.name)); if (typeRule) { return typeRule.name; } if (rules.some(r => r.name === 'enum')) { return 'enum'; } return 'string'; } function getConstraints(rules) { const constraints = []; const minRule = rules.find(r => r.name === 'min'); if (minRule && minRule.args.length > 0) { constraints.push(`Min: ${minRule.args[0]}`); } const maxRule = rules.find(r => r.name === 'max'); if (maxRule && maxRule.args.length > 0) { constraints.push(`Max: ${maxRule.args[0]}`); } const enumRule = rules.find(r => r.name === 'enum'); if (enumRule && enumRule.args.length > 0) { constraints.push(`Allowed: ${enumRule.args.join(', ')}`); } return constraints; }