import path from 'path'; import * as fs from 'fs'; /** * Environment type enum */ export enum EnvironmentType { DEVELOPMENT = 'development', PRODUCTION = 'production' } /** * Environment configuration interface */ export interface IEnvironmentConfig { /** * Get the current environment type * @returns {EnvironmentType} The current environment */ getEnvironment(): EnvironmentType; /** * Check if running in development mode * @returns {boolean} True if in development mode */ isDevelopment(): boolean; /** * Check if running in production mode * @returns {boolean} True if in production mode */ isProduction(): boolean; } /** * Environment configuration class that detects the current environment * @class EnvironmentConfig * @implements {IEnvironmentConfig} * * @description * This class provides environment detection based on multiple indicators: * 1. NODE_ENV environment variable * 2. Presence of workspace structure (workspaces field in package.json) * 3. Module resolution capability (can resolve published packages) * * @example * ```typescript * const envConfig = new EnvironmentConfig(); * if (envConfig.isDevelopment()) { * console.log('Running in development mode'); * } * ``` */ export class EnvironmentConfig implements IEnvironmentConfig { private environment: EnvironmentType; constructor() { this.environment = this.detectEnvironment(); } /** * Detects the current environment based on various indicators * @returns {EnvironmentType} The detected environment type * @private */ private detectEnvironment(): EnvironmentType { // Check NODE_ENV first const nodeEnv = process.env['NODE_ENV']?.toLowerCase(); if (nodeEnv === 'production') { return EnvironmentType.PRODUCTION; } if (nodeEnv === 'development') { return EnvironmentType.DEVELOPMENT; } // If NODE_ENV is not set, detect based on workspace structure // In development, we should be in a monorepo with workspaces // In production, packages are published and installed independently try { const currentDir = __dirname; const projectRoot = this.findProjectRoot(currentDir); if (projectRoot) { const packageJsonPath = path.join(projectRoot, 'package.json'); if (fs.existsSync(packageJsonPath)) { const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); // If workspaces field exists, we're in development if (packageJson.workspaces) { return EnvironmentType.DEVELOPMENT; } } } } catch (error) { // If we can't find workspace structure, assume production } // Default to production if we can't determine return EnvironmentType.PRODUCTION; } /** * Finds the project root by traversing up the directory tree * @param {string} startDir - Directory to start searching from * @returns {string | null} Path to project root or null if not found * @private */ private findProjectRoot(startDir: string): string | null { let currentDir = startDir; const root = path.parse(currentDir).root; while (currentDir !== root) { const packageJsonPath = path.join(currentDir, 'package.json'); if (fs.existsSync(packageJsonPath)) { return currentDir; } currentDir = path.dirname(currentDir); } return null; } /** * Gets the current environment type * @returns {EnvironmentType} The current environment */ public getEnvironment(): EnvironmentType { return this.environment; } /** * Checks if running in development mode * @returns {boolean} True if in development mode */ public isDevelopment(): boolean { return this.environment === EnvironmentType.DEVELOPMENT; } /** * Checks if running in production mode * @returns {boolean} True if in production mode */ public isProduction(): boolean { return this.environment === EnvironmentType.PRODUCTION; } }