UNPKG

create-envexample

Version:

A simple CLI tool to create .env.example files from your .env files, making it easier to share environment variable structures without exposing sensitive data

170 lines (150 loc) 5.49 kB
#!/usr/bin/env node import { time } from "console"; import * as fs from "fs/promises"; import * as path from "path"; import { fileURLToPath } from 'url'; // Parse command-line arguments const parseArgs = (args) => { const options = { sort: false, preserveComments: true, noComments: false, outputPath: path.join(process.cwd(), ".env.example"), delimiter: "=", verbose: false, }; for (let i = 2; i < args.length; i++) { const arg = args[i]; switch (arg) { case '-o': case '--output': options.outputPath = args[++i]; break; case '--sort': options.sort = true; options.preserveComments = false; break; case '--no-comments': options.noComments = true; break; case '--delimiter': options.delimiter = args[++i] || "="; break; case '--verbose': options.verbose = true; break; case '-h': case '--help': showHelp(); process.exit(0); } } return options; }; // Display help information const showHelp = () => { console.log(` Usage: create-envexample [options] Options: -o, --output <path> Specify output file path (default: .env.example) --sort Sort both variables and comments --no-comments Remove all comments from output --delimiter <char> Specify custom delimiter (default: =) --verbose Enable verbose mode for debugging -h, --help Show help information Examples: $ create-envexample $ create-envexample -o custom.env.example $ create-envexample --sort $ create-envexample --no-comments $ create-envexample --delimiter : `); }; // Create .env.example file const createEnvExample = async (options = {}) => { try { const envFilePath = path.join(process.cwd(), ".env"); const outputPath = options.outputPath; // Check if .env file exists try { await fs.access(envFilePath); } catch { throw new Error(".env file not found in current directory"); } // Read .env file content const data = await fs.readFile(envFilePath, "utf8"); if (!data.trim()) { throw new Error(".env file is empty"); } // Process each line const lines = data.split("\n"); const processedLines = []; const ignoredKeys = await loadIgnoredKeys(); for (const line of lines) { const trimmedLine = line.trim(); // Handle comments if (trimmedLine.startsWith("#")) { if (!options.noComments) { processedLines.push(line); } continue; } // Handle key-value pairs if (trimmedLine && !ignoredKeys.has(trimmedLine.split(options.delimiter)[0]?.trim())) { const [key] = line.split(options.delimiter); if (key && key.trim()) { processedLines.push(`${key.trim()}${options.delimiter}`); } } } // Sort lines if required const sortedLines = options.sort ? processedLines.sort((a, b) => { const aIsComment = a.trim().startsWith("#"); const bIsComment = b.trim().startsWith("#"); if (!options.preserveComments) { return a.localeCompare(b); } if (aIsComment && !bIsComment) return -1; if (!aIsComment && bIsComment) return 1; if (aIsComment && bIsComment) return 0; return a.localeCompare(b); }) : processedLines; // Add timestamp header const timestamp = new Date().toUTCString("en-US", { timeZone: "UTC" }); const content = [ ...sortedLines, options.noComments ? '' : `# Generated on: ${timestamp} by create-envexample`, ] .filter(Boolean) .join("\n"); // Write to output file await fs.writeFile(outputPath, content); console.log(`Environment example file created successfully at ${outputPath}`); } catch (err) { console.error(`Error: ${err.message}`); process.exit(1); } }; // Load ignored keys from .envignore file const loadIgnoredKeys = async () => { const ignoreFilePath = path.join(process.cwd(), ".envignore"); try { await fs.access(ignoreFilePath); const data = await fs.readFile(ignoreFilePath, "utf8"); return new Set(data.split("\n").map((line) => line.trim()).filter(Boolean)); } catch { return new Set(); // No .envignore file found } }; // Replace the CommonJS-style module check with ES modules version const isMainModule = process.argv[1] === fileURLToPath(import.meta.url); if (isMainModule) { const options = parseArgs(process.argv); if (options.verbose) { console.log("Options:", options); } createEnvExample(options).catch(console.error); } export { createEnvExample };