GitHub

Examples

Real-world examples and use cases for Lopos utility functions.

Examples
Use Cases
Practical
Example Categories

Form Validation

Validate user input with flexible testing

Configuration Management

Merge and manage application configs

Event Handling

Throttle events for better performance

Data Processing

Safe cloning and manipulation

Date Operations

Parse and format dates flexibly

Form Validation System

Build a comprehensive form validation system using Lopos test functions.

const { test, lopif } = require("lopos");

class FormValidator {
  constructor() {
    this.errors = [];
  }

  validateEmail(email) {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    
    return lopif(
      test("regexTest", email, emailRegex),
      () => true,
      () => {
        this.errors.push("Invalid email format");
        return false;
      }
    );
  }

  validatePassword(password) {
    const validations = [
      {
        test: () => test("lengthGreaterThan", password, 7),
        message: "Password must be at least 8 characters"
      },
      {
        test: () => test("regexTest", password, /[A-Z]/),
        message: "Password must contain uppercase letter"
      },
      {
        test: () => test("regexTest", password, /[0-9]/),
        message: "Password must contain a number"
      }
    ];

    return validations.every(validation => 
      lopif(
        validation.test(),
        () => true,
        () => {
          this.errors.push(validation.message);
          return false;
        }
      )
    );
  }

  validateAge(age) {
    return lopif(
      test("inRange", parseInt(age), [13, 120]),
      () => true,
      () => {
        this.errors.push("Age must be between 13 and 120");
        return false;
      }
    );
  }

  validateForm(formData) {
    this.errors = [];
    
    const isEmailValid = this.validateEmail(formData.email);
    const isPasswordValid = this.validatePassword(formData.password);
    const isAgeValid = this.validateAge(formData.age);
    
    return {
      isValid: isEmailValid && isPasswordValid && isAgeValid,
      errors: this.errors
    };
  }
}

// Usage
const validator = new FormValidator();
const result = validator.validateForm({
  email: "user@example.com",
  password: "SecurePass123",
  age: "25"
});

console.log(result.isValid); // true or false
console.log(result.errors); // Array of error messages
Configuration Management

Manage application configurations with environment-specific overrides.

const { deepMerge, test } = require("lopos");

class ConfigManager {
  constructor() {
    this.defaultConfig = {
      server: {
        port: 3000,
        host: "localhost",
        ssl: false
      },
      database: {
        host: "localhost",
        port: 5432,
        pool: {
          min: 2,
          max: 10
        }
      },
      cache: {
        ttl: 3600,
        maxSize: 1000
      },
      logging: {
        level: "info",
        format: "json"
      }
    };
  }

  loadConfig(environment = "development") {
    const envConfigs = {
      development: {
        server: { port: 3001 },
        logging: { level: "debug" }
      },
      production: {
        server: { 
          port: 80, 
          ssl: true,
          host: "0.0.0.0"
        },
        database: {
          pool: { min: 5, max: 50 }
        },
        cache: {
          ttl: 7200,
          maxSize: 10000
        },
        logging: { level: "error" }
      },
      testing: {
        database: {
          host: "test-db",
          pool: { min: 1, max: 5 }
        },
        cache: { ttl: 60 }
      }
    };

    const envConfig = envConfigs[environment] || {};
    return deepMerge(this.defaultConfig, envConfig);
  }

  validateConfig(config) {
    const validations = [
      test("isType", config.server.port, "number"),
      test("inRange", config.server.port, [1, 65535]),
      test("contains", ["info", "debug", "warn", "error"], config.logging.level),
      test("greaterThan", config.database.pool.max, config.database.pool.min)
    ];

    return validations.every(Boolean);
  }

  getConfig(environment, userOverrides = {}) {
    let config = this.loadConfig(environment);
    
    if (Object.keys(userOverrides).length > 0) {
      config = deepMerge(config, userOverrides);
    }

    if (!this.validateConfig(config)) {
      throw new Error("Invalid configuration");
    }

    return config;
  }
}

// Usage
const configManager = new ConfigManager();

// Development config
const devConfig = configManager.getConfig("development");

// Production with custom overrides
const prodConfig = configManager.getConfig("production", {
  server: { port: 8080 },
  database: { host: "prod-db.example.com" }
});

console.log("Dev port:", devConfig.server.port); // 3001
console.log("Prod port:", prodConfig.server.port); // 8080
Performance-Optimized Event Handling

Create responsive UIs with throttled event handlers and smart state management.

const { advancedThrottle, test, lopif } = require("lopos");

class UIController {
  constructor() {
    this.state = {
      scrollPosition: 0,
      windowWidth: window.innerWidth,
      searchQuery: "",
      isScrolling: false
    };

    this.setupEventHandlers();
  }

  setupEventHandlers() {
    // Throttled scroll handler
    this.handleScroll = advancedThrottle(() => {
      const scrollTop = window.pageYOffset;
      this.state.scrollPosition = scrollTop;
      
      // Update navigation visibility
      lopif(
        test("greaterThan", scrollTop, 100),
        () => this.showFloatingNav(),
        () => this.hideFloatingNav()
      );

      // Update scroll indicator
      this.updateScrollIndicator(scrollTop);
      
    }, 16, { leading: true, trailing: true }); // ~60fps

    // Throttled resize handler
    this.handleResize = advancedThrottle(() => {
      const newWidth = window.innerWidth;
      const oldWidth = this.state.windowWidth;
      this.state.windowWidth = newWidth;

      // Trigger layout changes only if significant resize
      lopif(
        test("greaterThan", Math.abs(newWidth - oldWidth), 100),
        () => this.handleLayoutChange(newWidth),
        () => console.log("Minor resize, ignoring")
      );
      
    }, 250, { leading: false, trailing: true });

    // Throttled search with debounce-like behavior
    this.handleSearch = advancedThrottle((query) => {
      lopif(
        test("lengthGreaterThan", query.trim(), 2),
        () => this.performSearch(query),
        () => this.clearSearchResults()
      );
    }, 300, { leading: false, trailing: true });

    // Attach event listeners
    window.addEventListener('scroll', this.handleScroll);
    window.addEventListener('resize', this.handleResize);
  }

  showFloatingNav() {
    const nav = document.getElementById('floating-nav');
    if (nav) nav.classList.add('visible');
  }

  hideFloatingNav() {
    const nav = document.getElementById('floating-nav');
    if (nav) nav.classList.remove('visible');
  }

  updateScrollIndicator(scrollTop) {
    const docHeight = document.documentElement.scrollHeight - window.innerHeight;
    const progress = (scrollTop / docHeight) * 100;
    
    const indicator = document.getElementById('scroll-indicator');
    if (indicator) {
      indicator.style.width = `${Math.min(progress, 100)}%`;
    }
  }

  handleLayoutChange(width) {
    lopif(
      test("lessThan", width, 768),
      () => this.enableMobileLayout(),
      () => this.enableDesktopLayout()
    );
  }

  enableMobileLayout() {
    document.body.classList.add('mobile-layout');
    document.body.classList.remove('desktop-layout');
  }

  enableDesktopLayout() {
    document.body.classList.add('desktop-layout');
    document.body.classList.remove('mobile-layout');
  }

  performSearch(query) {
    console.log(`Searching for: ${query}`);
    // Implement actual search logic
  }

  clearSearchResults() {
    console.log("Clearing search results");
    // Clear search results
  }

  // Cleanup method
  destroy() {
    this.handleScroll.cancel();
    this.handleResize.cancel();
    this.handleSearch.cancel();
    
    window.removeEventListener('scroll', this.handleScroll);
    window.removeEventListener('resize', this.handleResize);
  }
}

// Usage
const uiController = new UIController();

// Search input handler
const searchInput = document.getElementById('search');
if (searchInput) {
  searchInput.addEventListener('input', (e) => {
    uiController.handleSearch(e.target.value);
  });
}

// Cleanup on page unload
window.addEventListener('beforeunload', () => {
  uiController.destroy();
});
Safe Data Processing Pipeline

Process and transform data safely with cloning and validation.

const { deepClone, test, lopif, deepMerge } = require("lopos");

class DataProcessor {
  constructor() {
    this.processors = new Map();
    this.cache = new Map();
  }

  // Register data transformation functions
  registerProcessor(name, processorFn, validator = null) {
    this.processors.set(name, { fn: processorFn, validator });
  }

  // Safe data transformation with validation
  processData(data, processorName, options = {}) {
    const processor = this.processors.get(processorName);
    
    return lopif(
      test("isType", processor, "object"),
      () => {
        // Clone data to prevent mutation
        const clonedData = deepClone(data);
        
        // Validate input if validator exists
        const isValid = lopif(
          test("isType", processor.validator, "function"),
          () => processor.validator(clonedData),
          () => true // No validator, assume valid
        );

        return lopif(
          isValid,
          () => {
            try {
              const result = processor.fn(clonedData, options);
              
              // Cache result if caching is enabled
              lopif(
                options.cache === true,
                () => this.cacheResult(processorName, data, result),
                () => null
              );
              
              return result;
            } catch (error) {
              console.error(`Processing failed for ${processorName}:`, error);
              return { error: error.message, originalData: clonedData };
            }
          },
          () => ({ error: "Invalid input data", originalData: clonedData })
        );
      },
      () => ({ error: `Processor '${processorName}' not found` })
    );
  }

  cacheResult(processorName, input, result) {
    const cacheKey = `${processorName}_${JSON.stringify(input)}`;
    this.cache.set(cacheKey, {
      result,
      timestamp: Date.now()
    });
  }

  // Batch processing with error handling
  processBatch(dataArray, processorName, options = {}) {
    return dataArray.map((item, index) => {
      const result = this.processData(item, processorName, options);
      
      return lopif(
        test("containsKeys", result, ["error"]),
        () => ({ index, error: result.error, item }),
        () => ({ index, success: true, result, item })
      );
    });
  }

  // Pipeline processing
  processPipeline(data, processorNames, options = {}) {
    return processorNames.reduce((currentData, processorName) => {
      return lopif(
        test("containsKeys", currentData, ["error"]),
        () => currentData, // Stop pipeline on error
        () => this.processData(currentData, processorName, options)
      );
    }, data);
  }
}

// Example processors
const dataProcessor = new DataProcessor();

// User data normalization
dataProcessor.registerProcessor(
  'normalizeUser',
  (user) => ({
    id: user.id,
    name: (user.firstName + ' ' + user.lastName).trim(),
    email: user.email.toLowerCase(),
    age: parseInt(user.age),
    createdAt: new Date(user.createdAt),
    preferences: deepMerge({
      theme: 'light',
      notifications: true
    }, user.preferences || {})
  }),
  (user) => test("containsKeys", user, ["id", "firstName", "email"])
);

// Data aggregation
dataProcessor.registerProcessor(
  'aggregateStats',
  (users) => ({
    total: users.length,
    averageAge: users.reduce((sum, u) => sum + u.age, 0) / users.length,
    emailDomains: [...new Set(users.map(u => u.email.split('@')[1]))],
    ageGroups: {
      young: users.filter(u => u.age < 25).length,
      adult: users.filter(u => u.age >= 25 && u.age < 65).length,
      senior: users.filter(u => u.age >= 65).length
    }
  }),
  (users) => test("isArray", users) && users.length > 0
);

// Usage examples
const userData = [
  {
    id: 1,
    firstName: "John",
    lastName: "Doe",
    email: "JOHN@EXAMPLE.COM",
    age: "30",
    createdAt: "2023-01-01",
    preferences: { theme: "dark" }
  },
  {
    id: 2,
    firstName: "Jane",
    lastName: "Smith",
    email: "jane@test.org",
    age: "25",
    createdAt: "2023-02-01"
  }
];

// Single user processing
const normalizedUser = dataProcessor.processData(userData[0], 'normalizeUser');
console.log(normalizedUser);

// Batch processing
const batchResults = dataProcessor.processBatch(userData, 'normalizeUser');
console.log(batchResults);

// Pipeline processing
const pipelineResult = dataProcessor.processPipeline(
  userData,
  ['normalizeUser', 'aggregateStats'],
  { cache: true }
);
console.log(pipelineResult);
Advanced Date Operations

Handle complex date scenarios with flexible parsing and formatting.

const { flexibleDate, test, lopif } = require("lopos");

class DateManager {
  constructor(defaultTimezone = "local") {
    this.defaultTimezone = defaultTimezone;
    this.dateFormats = {
      short: (date) => date.toLocaleDateString(),
      long: (date) => date.toLocaleDateString('en-US', { 
        weekday: 'long', 
        year: 'numeric', 
        month: 'long', 
        day: 'numeric' 
      }),
      time: (date) => date.toLocaleTimeString(),
      iso: (date) => date.toISOString(),
      relative: true
    };
  }

  // Parse various date inputs
  parseDate(input, options = {}) {
    const config = {
      timezone: this.defaultTimezone,
      fallback: null,
      strict: false,
      ...options
    };

    return flexibleDate(input, config);
  }

  // Format date with multiple options
  formatDate(input, format = "short", options = {}) {
    const date = this.parseDate(input, options);
    
    return lopif(
      test("equals", date, null),
      () => "Invalid Date",
      () => {
        const formatFn = this.dateFormats[format];
        return lopif(
          test("isType", formatFn, "function"),
          () => formatFn(new Date(date)),
          () => flexibleDate(input, { 
            format: format === "relative" ? undefined : format,
            relative: format === "relative",
            ...options 
          })
        );
      }
    );
  }

  // Calculate date ranges
  getDateRange(startDate, endDate, options = {}) {
    const start = this.parseDate(startDate);
    const end = this.parseDate(endDate);
    
    return lopif(
      test("equals", start, null) || test("equals", end, null),
      () => ({ error: "Invalid date range" }),
      () => {
        const startTime = new Date(start).getTime();
        const endTime = new Date(end).getTime();
        const diffMs = endTime - startTime;
        
        return {
          start: this.formatDate(start, options.format || "iso"),
          end: this.formatDate(end, options.format || "iso"),
          duration: {
            milliseconds: diffMs,
            seconds: Math.floor(diffMs / 1000),
            minutes: Math.floor(diffMs / (1000 * 60)),
            hours: Math.floor(diffMs / (1000 * 60 * 60)),
            days: Math.floor(diffMs / (1000 * 60 * 60 * 24))
          },
          isValid: diffMs >= 0
        };
      }
    );
  }

  // Business day calculations
  addBusinessDays(startDate, days) {
    const date = new Date(this.parseDate(startDate));
    let addedDays = 0;
    
    while (addedDays < days) {
      date.setDate(date.getDate() + 1);
      
      // Skip weekends (Saturday = 6, Sunday = 0)
      lopif(
        test("contains", [0, 6], date.getDay()),
        () => null, // Weekend, don't count
        () => addedDays++ // Weekday, count it
      );
    }
    
    return this.formatDate(date, "iso");
  }

  // Event scheduling
  scheduleEvent(eventDate, reminderDays = [7, 1]) {
    const event = this.parseDate(eventDate);
    
    return lopif(
      test("equals", event, null),
      () => ({ error: "Invalid event date" }),
      () => {
        const eventTime = new Date(event).getTime();
        const now = Date.now();
        
        return {
          event: {
            date: this.formatDate(event, "long"),
            time: this.formatDate(event, "time"),
            relative: this.formatDate(event, "relative")
          },
          reminders: reminderDays.map(days => {
            const reminderDate = flexibleDate(event, { 
              adjustDays: -days,
              format: "iso"
            });
            
            return {
              days: days,
              date: this.formatDate(reminderDate, "long"),
              isPast: new Date(reminderDate).getTime() < now
            };
          }),
          status: lopif(
            test("lessThan", eventTime, now),
            () => "past",
            () => lopif(
              test("lessThan", eventTime - now, 24 * 60 * 60 * 1000),
              () => "today",
              () => "upcoming"
            )
          )
        };
      }
    );
  }

  // Time zone conversion
  convertTimezone(date, fromTz, toTz) {
    const baseDate = this.parseDate(date, { timezone: fromTz });
    
    return lopif(
      test("equals", baseDate, null),
      () => "Invalid Date",
      () => this.formatDate(baseDate, "iso", { timezone: toTz })
    );
  }
}

// Usage examples
const dateManager = new DateManager("utc");

// Parse various formats
console.log(dateManager.parseDate("2023-12-25")); // ISO string
console.log(dateManager.parseDate("December 25, 2023")); // Natural language
console.log(dateManager.parseDate(1703462400000)); // Timestamp

// Format dates
console.log(dateManager.formatDate("2023-12-25", "long"));
console.log(dateManager.formatDate("2023-12-25", "relative"));

// Date range calculations
const range = dateManager.getDateRange("2023-01-01", "2023-12-31");
console.log(`Duration: ${range.duration.days} days`);

// Business days
const businessDate = dateManager.addBusinessDays("2023-12-22", 5);
console.log("5 business days later:", businessDate);

// Event scheduling
const eventSchedule = dateManager.scheduleEvent("2024-01-15T10:00:00Z", [7, 3, 1]);
console.log("Event schedule:", eventSchedule);

// Timezone conversion
const converted = dateManager.convertTimezone(
  "2023-12-25T12:00:00Z", 
  "utc", 
  "+0300"
);
console.log("Converted time:", converted);