CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-fbjs

A collection of utility libraries used by other Facebook JS projects including React and Relay

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

development-utilities.mddocs/

Development Utilities

Development aids including assertion utilities, error handling, debugging tools, and data type utilities.

Capabilities

Assertion Utilities

Runtime assertion and validation utilities for development and debugging.

const invariant = require('fbjs/lib/invariant');
const warning = require('fbjs/lib/warning');

/**
 * Assertion utility that throws error if condition is false
 * Supports sprintf-style formatting with %s placeholders
 * @param condition - Condition to assert (truthy values pass)
 * @param format - Error message format string with %s placeholders
 * @param args - Values to substitute into format string
 * @throws Error with formatted message if condition is false
 */
function invariant(condition: any, format: string, ...args: Array<any>): void;

/**
 * Development warning utility (no-op in production builds)
 * Logs warning to console if condition is false
 * @param condition - Condition to check (false triggers warning)
 * @param format - Warning message format string with %s placeholders
 * @param args - Values to substitute into format string
 */
function warning(condition: boolean, format: string, ...args: Array<any>): void;

Usage Examples:

const invariant = require('fbjs/lib/invariant');
const warning = require('fbjs/lib/warning');

// Basic assertions
function processUser(user) {
  invariant(user, 'User object is required');
  invariant(user.id, 'User must have an ID');
  invariant(typeof user.name === 'string', 'User name must be a string');
  
  // Process user...
}

// Assertions with formatted messages
function transfer(fromAccount, toAccount, amount) {
  invariant(fromAccount, 'Source account is required');
  invariant(toAccount, 'Destination account is required');
  invariant(amount > 0, 'Transfer amount must be positive, got %s', amount);
  invariant(fromAccount.balance >= amount, 
    'Insufficient funds: need %s, have %s', amount, fromAccount.balance);
  
  // Perform transfer...
}

// Array validation
function processArray(items) {
  invariant(Array.isArray(items), 'Expected array, got %s', typeof items);
  invariant(items.length > 0, 'Array cannot be empty');
  
  items.forEach((item, index) => {
    invariant(item != null, 'Item at index %s cannot be null', index);
  });
}

// API parameter validation
function createUser(userData) {
  invariant(userData, 'User data is required');
  invariant(userData.email, 'Email is required');
  invariant(userData.email.includes('@'), 'Invalid email format: %s', userData.email);
  
  warning(userData.name, 'User name not provided, using email as display name');
  warning(userData.phone, 'Phone number not provided');
  
  return {
    id: generateId(),
    email: userData.email,
    name: userData.name || userData.email,
    phone: userData.phone || null
  };
}

// State validation
class Counter {
  constructor(initialValue = 0) {
    invariant(typeof initialValue === 'number', 
      'Initial value must be a number, got %s', typeof initialValue);
    this.value = initialValue;
  }
  
  increment(step = 1) {
    invariant(typeof step === 'number', 'Step must be a number');
    invariant(step > 0, 'Step must be positive, got %s', step);
    
    this.value += step;
    warning(this.value <= 1000, 'Counter value is getting large: %s', this.value);
  }
  
  decrement(step = 1) {
    invariant(typeof step === 'number', 'Step must be a number');
    invariant(step > 0, 'Step must be positive, got %s', step);
    invariant(this.value >= step, 'Cannot decrement below zero: %s - %s', this.value, step);
    
    this.value -= step;
  }
}

// Configuration validation
function initializeApp(config) {
  invariant(config, 'Configuration object is required');
  invariant(config.apiUrl, 'API URL is required');
  invariant(typeof config.timeout === 'number', 
    'Timeout must be a number, got %s', typeof config.timeout);
  
  warning(config.timeout >= 5000, 
    'Timeout is very short (%s ms), consider increasing it', config.timeout);
  warning(config.apiUrl.startsWith('https://'), 
    'API URL should use HTTPS: %s', config.apiUrl);
  
  // Initialize app with validated config
}

// Error boundaries with detailed messages
function parseJSON(jsonString) {
  invariant(typeof jsonString === 'string', 
    'JSON input must be string, got %s', typeof jsonString);
  invariant(jsonString.length > 0, 'JSON string cannot be empty');
  
  try {
    return JSON.parse(jsonString);
  } catch (error) {
    invariant(false, 'Invalid JSON: %s', error.message);
  }
}

Type Checking Utilities

Utilities for runtime type checking and null safety.

const nullthrows = require('fbjs/lib/nullthrows');

/**
 * Throws error if value is null or undefined, returns value otherwise
 * Provides type narrowing in TypeScript/Flow
 * @param value - Value to check for null/undefined
 * @param message - Optional error message
 * @returns The value if not null/undefined
 * @throws Error if value is null or undefined
 */
function nullthrows<T>(value: ?T, message?: string): T;

Usage Examples:

const nullthrows = require('fbjs/lib/nullthrows');

// Basic null checking
function processElement(elementId) {
  const element = document.getElementById(elementId);
  const safeElement = nullthrows(element, `Element not found: ${elementId}`);
  
  // Now we know element is not null
  safeElement.addEventListener('click', handleClick);
  return safeElement;
}

// API response validation
function processUserData(response) {
  const user = nullthrows(response.user, 'User data missing from response');
  const profile = nullthrows(user.profile, 'User profile missing');
  
  return {
    id: nullthrows(user.id, 'User ID missing'),
    name: nullthrows(profile.name, 'Profile name missing'),
    email: nullthrows(profile.email, 'Profile email missing')
  };
}

// Array processing with null safety
function processItems(items) {
  return items.map((item, index) => {
    const safeItem = nullthrows(item, `Item at index ${index} is null`);
    return {
      id: nullthrows(safeItem.id, `Item ${index} missing ID`),
      name: nullthrows(safeItem.name, `Item ${index} missing name`)
    };
  });
}

// Optional chaining alternative
function getNestedValue(obj) {
  const level1 = nullthrows(obj.level1, 'Level 1 missing');
  const level2 = nullthrows(level1.level2, 'Level 2 missing');
  return nullthrows(level2.value, 'Final value missing');
}

// Function parameter validation
function calculateArea(shape) {
  const width = nullthrows(shape.width, 'Shape width is required');
  const height = nullthrows(shape.height, 'Shape height is required');
  
  return width * height;
}

// Configuration validation
function loadConfig(configData) {
  return {
    apiKey: nullthrows(configData.apiKey, 'API key is required'),
    baseUrl: nullthrows(configData.baseUrl, 'Base URL is required'),
    timeout: configData.timeout || 5000, // Optional with default
    retries: configData.retries || 3      // Optional with default
  };
}

Key Mirror Utilities

Utilities for creating objects where keys equal their values, useful for constants and enums.

const keyMirror = require('fbjs/lib/keyMirror');
const keyMirrorRecursive = require('fbjs/lib/keyMirrorRecursive');
const keyOf = require('fbjs/lib/keyOf');

/**
 * Creates object where keys equal their values
 * Useful for creating constant enums that are minification-safe
 * Validates that input is an object and not an array using invariant
 * @param obj - Object with keys to mirror (values are ignored)
 * @returns Object where each key equals its string value
 * @throws Error if obj is not an object or is an array
 */
function keyMirror<T: {}>(obj: T): $ObjMapi<T, <K>(K) => K>;

/**
 * Recursive version of keyMirror for nested objects
 * @param obj - Object with nested structure to mirror
 * @returns Object with mirrored keys at all levels
 */
function keyMirrorRecursive(obj: Object): Object;

/**
 * Gets minification-safe property key name
 * Useful for accessing object properties in a way that survives minification
 * @param oneKeyObj - Object with single property
 * @returns String key name
 */
function keyOf(oneKeyObj: Object): string;

Usage Examples:

const keyMirror = require('fbjs/lib/keyMirror');
const keyMirrorRecursive = require('fbjs/lib/keyMirrorRecursive');
const keyOf = require('fbjs/lib/keyOf');

// Basic enum creation
const ActionTypes = keyMirror({
  USER_LOGIN: null,
  USER_LOGOUT: null,
  LOAD_DATA: null,
  SAVE_DATA: null,
  SHOW_ERROR: null
});

console.log(ActionTypes);
// {
//   USER_LOGIN: 'USER_LOGIN',
//   USER_LOGOUT: 'USER_LOGOUT',
//   LOAD_DATA: 'LOAD_DATA',
//   SAVE_DATA: 'SAVE_DATA',
//   SHOW_ERROR: 'SHOW_ERROR'
// }

// Error handling - keyMirror validates input with invariant
try {
  const invalidEnum = keyMirror(['not', 'an', 'object']); // Throws Error
} catch (error) {
  console.error('keyMirror failed:', error.message);
  // Output: "keyMirror(...): Argument must be an object."
}

try {
  const arrayEnum = keyMirror([1, 2, 3]); // Throws Error - arrays not allowed
} catch (error) {
  console.error('keyMirror failed:', error.message);
  // Output: "keyMirror(...): Argument must be an object."
}

// Safe keyMirror wrapper
function safeKeyMirror(obj, defaultValue = {}) {
  try {
    if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
      console.warn('Invalid input for keyMirror, using default');
      return defaultValue;
    }
    return keyMirror(obj);
  } catch (error) {
    console.error('keyMirror error:', error.message);
    return defaultValue;
  }
}

// Usage in Redux actions
function loginUser(credentials) {
  return {
    type: ActionTypes.USER_LOGIN,
    payload: credentials
  };
}

// API endpoints enum
const API_ENDPOINTS = keyMirror({
  USERS: null,
  PRODUCTS: null,
  ORDERS: null,
  ANALYTICS: null
});

function makeRequest(endpoint, data) {
  const url = `https://api.example.com/${endpoint.toLowerCase()}`;
  // Safe to use endpoint as it equals its string value
}

// Status constants
const Status = keyMirror({
  PENDING: null,
  SUCCESS: null,
  ERROR: null,
  CANCELLED: null
});

class AsyncOperation {
  constructor() {
    this.status = Status.PENDING;
  }
  
  complete() {
    this.status = Status.SUCCESS;
  }
  
  fail() {
    this.status = Status.ERROR;
  }
}

// Recursive mirroring for nested constants
const CONFIG_KEYS = keyMirrorRecursive({
  API: {
    BASE_URL: null,
    TIMEOUT: null,
    RETRIES: null
  },
  UI: {
    THEME: null,
    LANGUAGE: null,
    ANIMATIONS: {
      DURATION: null,
      EASING: null
    }
  },
  FEATURES: {
    ANALYTICS: null,
    NOTIFICATIONS: null
  }
});

console.log(CONFIG_KEYS);
// {
//   API: {
//     BASE_URL: 'BASE_URL',
//     TIMEOUT: 'TIMEOUT', 
//     RETRIES: 'RETRIES'
//   },
//   UI: {
//     THEME: 'THEME',
//     LANGUAGE: 'LANGUAGE',
//     ANIMATIONS: {
//       DURATION: 'DURATION',
//       EASING: 'EASING'
//     }
//   },
//   FEATURES: {
//     ANALYTICS: 'ANALYTICS',
//     NOTIFICATIONS: 'NOTIFICATIONS'
//   }
// }

// Minification-safe property access
const user = { name: 'Alice', age: 30, email: 'alice@example.com' };

// Instead of 'name' (which gets minified)
const nameKey = keyOf({ name: null }); // 'name'
const userName = user[nameKey];

// Safer for property validation
function validateUser(user) {
  const requiredFields = [
    keyOf({ name: null }),
    keyOf({ email: null }),
    keyOf({ age: null })
  ];
  
  requiredFields.forEach(field => {
    if (!user[field]) {
      throw new Error(`Missing required field: ${field}`);
    }
  });
}

// Form field names
const FORM_FIELDS = keyMirror({
  USERNAME: null,
  PASSWORD: null,
  EMAIL: null,
  CONFIRM_PASSWORD: null
});

function createForm() {
  return {
    [FORM_FIELDS.USERNAME]: '',
    [FORM_FIELDS.PASSWORD]: '',
    [FORM_FIELDS.EMAIL]: '',
    [FORM_FIELDS.CONFIRM_PASSWORD]: ''
  };
}

// Event types for event emitter
const EVENTS = keyMirror({
  CONNECT: null,
  DISCONNECT: null,
  MESSAGE: null,
  ERROR: null,
  RECONNECT: null
});

class EventEmitter {
  constructor() {
    this.listeners = {};
  }
  
  on(event, callback) {
    // Event names are guaranteed to be strings
    if (!this.listeners[event]) {
      this.listeners[event] = [];
    }
    this.listeners[event].push(callback);
  }
  
  emit(event, data) {
    if (this.listeners[event]) {
      this.listeners[event].forEach(callback => callback(data));
    }
  }
}

// Usage
const emitter = new EventEmitter();
emitter.on(EVENTS.CONNECT, () => console.log('Connected'));
emitter.emit(EVENTS.CONNECT);

Path and Phone Number Utilities

Utilities for object property access and phone number validation.

const getByPath = require('fbjs/lib/getByPath');
const isInternationalPhoneNumber = require('fbjs/lib/isInternationalPhoneNumber');

/**
 * Gets nested property by dot-notation path string
 * @param object - Object to traverse
 * @param path - Dot-notation path (e.g., 'user.profile.name')
 * @returns Value at path or undefined if path doesn't exist
 */
function getByPath(object: Object, path: string): any;

/**
 * Validates international phone number format
 * @param number - Phone number string to validate
 * @returns True if number appears to be valid international format
 */
function isInternationalPhoneNumber(number: string): boolean;

Usage Examples:

const getByPath = require('fbjs/lib/getByPath');
const isInternationalPhoneNumber = require('fbjs/lib/isInternationalPhoneNumber');

// Nested object property access
const user = {
  id: 123,
  profile: {
    personal: {
      name: 'Alice Johnson',
      age: 30
    },
    contact: {
      email: 'alice@example.com',
      phone: '+1-555-123-4567',
      address: {
        street: '123 Main St',
        city: 'Springfield',
        country: 'USA'
      }
    }
  },
  preferences: {
    theme: 'dark',
    notifications: {
      email: true,
      sms: false,
      push: true
    }
  }
};

// Get nested values safely
const name = getByPath(user, 'profile.personal.name'); // 'Alice Johnson'
const email = getByPath(user, 'profile.contact.email'); // 'alice@example.com'
const city = getByPath(user, 'profile.contact.address.city'); // 'Springfield'
const theme = getByPath(user, 'preferences.theme'); // 'dark'

// Handle missing paths gracefully
const missing = getByPath(user, 'profile.social.twitter'); // undefined
const invalid = getByPath(user, 'invalid.path.here'); // undefined

// Dynamic path building
function getUserProperty(user, category, field) {
  const path = `profile.${category}.${field}`;
  return getByPath(user, path);
}

const userEmail = getUserProperty(user, 'contact', 'email');
const userAge = getUserProperty(user, 'personal', 'age');

// Form data extraction
const formPaths = [
  'profile.personal.name',
  'profile.contact.email',
  'profile.contact.phone',
  'preferences.notifications.email'
];

const formData = {};
formPaths.forEach(path => {
  const value = getByPath(user, path);
  if (value !== undefined) {
    formData[path] = value;
  }
});

// Configuration access
const config = {
  api: {
    endpoints: {
      users: '/api/users',
      products: '/api/products'
    },
    timeout: 5000,
    retries: 3
  },
  ui: {
    theme: {
      primary: '#007bff',
      secondary: '#6c757d'
    }
  }
};

const usersEndpoint = getByPath(config, 'api.endpoints.users');
const primaryColor = getByPath(config, 'ui.theme.primary');

// Phone number validation
const phoneNumbers = [
  '+1-555-123-4567',    // US format
  '+44-20-7946-0958',   // UK format  
  '+33-1-23-45-67-89',  // France format
  '+81-3-1234-5678',    // Japan format
  '555-123-4567',       // Invalid (no country code)
  '+1234567890123456',  // Invalid (too long)
  'not-a-phone'         // Invalid (not a number)
];

phoneNumbers.forEach(number => {
  const isValid = isInternationalPhoneNumber(number);
  console.log(`${number}: ${isValid ? 'Valid' : 'Invalid'}`);
});

// User registration validation
function validateRegistration(userData) {
  const errors = [];
  
  const name = getByPath(userData, 'personal.name');
  if (!name) {
    errors.push('Name is required');
  }
  
  const email = getByPath(userData, 'contact.email');
  if (!email || !email.includes('@')) {
    errors.push('Valid email is required');
  }
  
  const phone = getByPath(userData, 'contact.phone');
  if (phone && !isInternationalPhoneNumber(phone)) {
    errors.push('Phone number must be in international format');
  }
  
  return {
    isValid: errors.length === 0,
    errors: errors
  };
}

// API response processing
function processAPIResponse(response) {
  return {
    id: getByPath(response, 'data.user.id'),
    name: getByPath(response, 'data.user.profile.displayName'),
    avatar: getByPath(response, 'data.user.profile.avatar.url'),
    isActive: getByPath(response, 'data.user.status.isActive'),
    lastLogin: getByPath(response, 'data.user.activity.lastLoginDate'),
    permissions: getByPath(response, 'data.user.permissions') || []
  };
}

// Settings management
class Settings {
  constructor(data) {
    this.data = data;
  }
  
  get(path, defaultValue = null) {
    const value = getByPath(this.data, path);
    return value !== undefined ? value : defaultValue;
  }
  
  set(path, value) {
    // Simple path setting (would need more complex logic for real implementation)
    const keys = path.split('.');
    let current = this.data;
    
    for (let i = 0; i < keys.length - 1; i++) {
      if (!current[keys[i]]) {
        current[keys[i]] = {};
      }
      current = current[keys[i]];
    }
    
    current[keys[keys.length - 1]] = value;
  }
}

Missing forks Utilities

Additional configuration and utility modules from Facebook's fork implementations.

const SiteData = require('fbjs/lib/SiteData');
const TokenizeUtil = require('fbjs/lib/TokenizeUtil');
const URI = require('fbjs/lib/URI');
const cssVar = require('fbjs/lib/cssVar');

/**
 * Site configuration data object
 * @type Object with site-specific configuration
 */
const SiteData: {
  is_rtl: boolean;  // Whether site uses right-to-left text direction
};

/**
 * Text tokenization utilities
 * @returns Punctuation regex pattern for tokenization
 */
function TokenizeUtil.getPunctuation(): string;

/**
 * Simple URI wrapper class
 * @constructor
 * @param uri - URI string to parse
 */
class URI {
  constructor(uri: string);
  toString(): string;
}

/**
 * CSS variable utility
 * Gets CSS variable value by name from fbjs-css-vars
 * @param name - CSS variable name
 * @returns CSS variable value
 * @throws Error via invariant if variable not found
 */
function cssVar(name: string): string;

/**
 * Development warning utility (from __forks__)
 * Logs warning to console if condition is false (no-op in production)
 * @param condition - Condition to check (false triggers warning)
 * @param format - Warning message format string with %s placeholders
 * @param args - Values to substitute into format string
 */
function warning(condition: boolean, format: string, ...args: Array<any>): void;

Usage Examples:

const SiteData = require('fbjs/lib/SiteData');
const TokenizeUtil = require('fbjs/lib/TokenizeUtil');
const URI = require('fbjs/lib/URI');
const cssVar = require('fbjs/lib/cssVar');
const warning = require('fbjs/lib/warning');

// Site configuration
if (SiteData.is_rtl) {
  document.body.dir = 'rtl';
  document.body.style.textAlign = 'right';
}

// Text tokenization
const punctuationPattern = TokenizeUtil.getPunctuation();
const tokenizer = new RegExp(punctuationPattern, 'g');
const tokens = text.split(tokenizer).filter(token => token.trim());

// URI handling
const uri = new URI('https://example.com/path?query=value#fragment');
const uriString = uri.toString(); // 'https://example.com/path?query=value#fragment'

// CSS variables
try {
  const primaryColor = cssVar('primary-color');
  element.style.color = primaryColor;
} catch (error) {
  console.error('CSS variable not found:', error.message);
}

// Development warnings
function validateUser(user) {
  warning(user.name, 'User name is missing, using ID as fallback');
  warning(user.email, 'User email not provided, notifications disabled');
  
  return {
    id: user.id,
    name: user.name || `User ${user.id}`,
    email: user.email || null
  };
}

Error Handling Utilities

Development error handling and event listener utilities.

const ErrorUtils = require('fbjs/lib/ErrorUtils');
const EventListener = require('fbjs/lib/EventListener');

/**
 * Error handling utilities for development and production
 */
const ErrorUtils: {
  /**
   * Global error handler registration
   * @param handler - Function to handle uncaught errors
   */
  setGlobalHandler(handler: (error: Error, isFatal: boolean) => void): void;
  
  /**
   * Reports error to error handling system
   * @param error - Error object or message
   * @param isFatal - Whether error is fatal to application
   */
  reportError(error: Error | string, isFatal?: boolean): void;
  
  /**
   * Wraps function to catch and report errors
   * @param fn - Function to wrap
   * @param context - Optional context for error reporting
   * @returns Wrapped function that catches errors
   */
  guard(fn: Function, context?: string): Function;
  
  /**
   * Creates error boundary for React-like error handling
   * @param component - Component or function to protect
   * @param fallback - Fallback to use when error occurs
   * @returns Protected component
   */
  applyWithGuard(component: Function, fallback?: Function): Function;
};

/**
 * Cross-browser event listener utilities
 */
const EventListener: {
  /**
   * Adds event listener with cross-browser compatibility
   * @param target - DOM element or event target
   * @param eventType - Event type string
   * @param listener - Event handler function
   * @param capture - Whether to use capture phase
   * @returns Object with remove() method
   */
  listen(
    target: EventTarget, 
    eventType: string, 
    listener: (event: Event) => void, 
    capture?: boolean
  ): { remove(): void };
  
  /**
   * Adds one-time event listener
   * @param target - DOM element or event target
   * @param eventType - Event type string
   * @param listener - Event handler function
   * @returns Object with remove() method
   */
  once(
    target: EventTarget,
    eventType: string,
    listener: (event: Event) => void
  ): { remove(): void };
  
  /**
   * Captures events during capture phase
   * @param target - DOM element or event target
   * @param eventType - Event type string
   * @param listener - Event handler function
   * @returns Object with remove() method
   */
  capture(
    target: EventTarget,
    eventType: string,
    listener: (event: Event) => void
  ): { remove(): void };
};

Usage Examples:

const ErrorUtils = require('fbjs/lib/ErrorUtils');
const EventListener = require('fbjs/lib/EventListener');

// Global error handling setup
ErrorUtils.setGlobalHandler((error, isFatal) => {
  console.error('Global error caught:', error);
  
  // Send to error reporting service
  if (typeof window !== 'undefined' && window.errorReportingService) {
    window.errorReportingService.report({
      message: error.message,
      stack: error.stack,
      isFatal: isFatal,
      timestamp: Date.now(),
      userAgent: navigator.userAgent,
      url: window.location.href
    });
  }
});

// Function wrapping for error safety
const safeAsyncFunction = ErrorUtils.guard(async function(userId) {
  const response = await fetch(`/api/users/${userId}`);
  const userData = await response.json();
  return userData;
}, 'user-data-fetch');

// Event listener management
class ComponentManager {
  constructor(element) {
    this.element = element;
    this.listeners = [];
  }
  
  addListener(eventType, handler) {
    const listener = EventListener.listen(this.element, eventType, handler);
    this.listeners.push(listener);
    return listener;
  }
  
  addOneTimeListener(eventType, handler) {
    const listener = EventListener.once(this.element, eventType, handler);
    this.listeners.push(listener);
    return listener;
  }
  
  destroy() {
    // Clean up all listeners
    this.listeners.forEach(listener => listener.remove());
    this.listeners = [];
  }
}

// Error boundary pattern
function createErrorBoundary(render, fallback) {
  return ErrorUtils.applyWithGuard(render, fallback || function(error) {
    return `<div class="error">Something went wrong: ${error.message}</div>`;
  });
}

// Safe API calls with error reporting
async function safeApiCall(endpoint, options = {}) {
  try {
    const response = await fetch(endpoint, options);
    
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }
    
    return await response.json();
  } catch (error) {
    ErrorUtils.reportError(error, false);
    throw error; // Re-throw for caller to handle
  }
}

// Form validation with error handling
const safeFormValidator = ErrorUtils.guard(function(formData) {
  const errors = [];
  
  if (!formData.email) {
    errors.push('Email is required');
  } else if (!formData.email.includes('@')) {
    errors.push('Invalid email format');
  }
  
  if (!formData.password) {
    errors.push('Password is required');
  } else if (formData.password.length < 8) {
    errors.push('Password must be at least 8 characters');
  }
  
  return {
    isValid: errors.length === 0,
    errors: errors
  };
}, 'form-validation');

// Event handling with cleanup
function setupPageEvents() {
  const cleanupCallbacks = [];
  
  // Navigation events
  const navListener = EventListener.listen(document, 'click', (event) => {
    if (event.target.matches('[data-nav]')) {
      event.preventDefault();
      const target = event.target.getAttribute('data-nav');
      navigateTo(target);
    }
  });
  cleanupCallbacks.push(() => navListener.remove());
  
  // Form submission
  const formListener = EventListener.listen(document, 'submit', (event) => {
    if (event.target.matches('form[data-ajax]')) {
      event.preventDefault();
      handleAjaxForm(event.target);
    }
  });
  cleanupCallbacks.push(() => formListener.remove());
  
  // Keyboard shortcuts
  const keyListener = EventListener.listen(document, 'keydown', (event) => {
    if (event.ctrlKey && event.key === 's') {
      event.preventDefault();
      saveCurrentState();
    }
  });
  cleanupCallbacks.push(() => keyListener.remove());
  
  // Return cleanup function
  return function cleanup() {
    cleanupCallbacks.forEach(fn => fn());
  };
}

// Error monitoring for critical sections
function monitorCriticalSection(name, fn) {
  return ErrorUtils.guard(function(...args) {
    const startTime = performance.now();
    
    try {
      const result = fn.apply(this, args);
      
      // If it's a promise, handle async errors
      if (result && typeof result.then === 'function') {
        return result.catch(error => {
          ErrorUtils.reportError(new Error(`Critical section '${name}' failed: ${error.message}`), true);
          throw error;
        });
      }
      
      return result;
    } catch (error) {
      const duration = performance.now() - startTime;
      ErrorUtils.reportError(new Error(`Critical section '${name}' failed after ${duration}ms: ${error.message}`), true);
      throw error;
    }
  }, `critical-${name}`);
}

docs

core-utilities.md

data-structures.md

development-utilities.md

dom-styling.md

functional-programming.md

index.md

network-fetch.md

performance-crypto.md

text-unicode.md

user-agent-browser.md

tile.json