Skip to main content

Scripts helpers

This directory contains reusable utility functions and helpers for the application. All helpers are designed to be type-safe and well-tested.

Centralised Imports

All helpers are available through a central index file, allowing for clean imports:

// Import multiple helpers from the index
import { devLog, safeString, formatDate } from '#src/scripts/helpers/index.js';

// Instead of importing from individual files
import { devLog } from '#src/scripts/helpers/devLogger.js';
import { safeString } from '#src/scripts/helpers/dataTransformers.js';
import { formatDate } from '#src/scripts/helpers/dateFormatter.js';

Available Helpers

๐Ÿ“ Development Logging (devLogger.ts)

Environment-aware logging utilities that only output to console in development mode, keeping production logs clean.

Functions

  • devLog(message: string) - Development-only console.log
  • devWarn(message: string) - Development-only console.warn
  • devError(message: string) - Development-only console.error
  • devDebug(message: string) - Development-only console.debug
  • isDevelopment(): boolean - Check if running in development mode

Usage

import { devLog, devWarn, devError, isDevelopment } from '#src/scripts/helpers/index.js';

// These will only appear in development mode
devLog('Initializing component...');
devWarn('Deprecated feature used');
devError('Failed to load data');

// Conditional logic based on environment
if (isDevelopment()) {
  // Development-only code
}

Environment Detection

Logs appear when:

  • NODE_ENV === 'development'
  • NODE_ENV is undefined (default development behaviour)

Logs are suppressed when:

  • NODE_ENV === 'production'
  • NODE_ENV === 'test'

๐Ÿ”ง Data Transformers (dataTransformers.ts)

Type-safe utilities for transforming and validating data from JSON fixtures and API responses.

Functions

  • safeString(value: unknown): string - Safely convert unknown value to string
  • safeOptionalString(value: unknown): string | undefined - Safely convert to optional string
  • isRecord(value: unknown): value is Record<string, unknown> - Type guard for object records
  • safeStringFromRecord(obj: unknown, key: string): string | null - Safely extract string from record
  • hasProperty(obj: unknown, key: string): obj is Record<string, unknown> - Check if object has property

Usage

import { 
  safeString, 
  safeOptionalString, 
  isRecord,
  safeStringFromRecord,
  hasProperty
} from '#src/scripts/helpers/index.js';

// Transform API data safely
function transformCaseData(rawData: unknown) {
  if (!isRecord(rawData)) {
    throw new Error('Invalid data format');
  }

  return {
    name: safeString(rawData.name),
    description: safeOptionalString(rawData.description),
    dateOfBirth: safeString(rawData.dateOfBirth)
  };
}

Type Safety

All functions handle null, undefined, and unexpected types gracefully, returning sensible defaults or typed guards.


๐Ÿ“… Date Formatter (dateFormatter.ts)

Consistent date formatting utilities for UI components and tables.

Functions

  • formatDate(dateString: string): string - Format ISO date string to “DD MMM YYYY” format

Usage

import { formatDate } from '#src/scripts/helpers/index.js';

// Format dates for display
const displayDate = formatDate('2023-01-06T00:00:00.000Z');
// Returns: "06 Jan 2023"

// Use in Nunjucks templates via filter
// {{ dateReceived | formatDate }}

Format

  • Input: ISO date string ("2023-01-06T00:00:00.000Z")
  • Output: Human-readable format ("06 Jan 2023")
  • Locale: British English (en-GB)
  • Fallback: Returns original string if parsing fails

โš ๏ธ Error Handler (errorHandler.ts)

Comprehensive error handling utilities for API requests and network operations, providing user-friendly error messages and structured logging.

Functions

  • extractErrorMessage(error: unknown): string - Extract user-friendly error message from various error types
  • createProcessedError(error: unknown, context: string): Error - Create processed error with user-friendly message for global handler
  • extractAndLogError(error: unknown, context: string): string - Extract error message and log it with context (for API services)
  • isHttpError(error: unknown, status: number): boolean - Check if error is a specific HTTP status code
  • isAuthError(error: unknown): boolean - Check if error is authentication failure (401)
  • isForbiddenError(error: unknown): boolean - Check if error is forbidden access (403)
  • isNotFoundError(error: unknown): boolean - Check if error is not found (404)
  • isServerError(error: unknown): boolean - Check if error is server error (5xx)

Usage

import { 
  extractErrorMessage, 
  createProcessedError,
  extractAndLogError,
  isAuthError, 
  isServerError 
} from '#src/scripts/helpers/index.js';

// For route handlers - create processed errors for global handler
try {
  await loadUserData();
} catch (error) {
  const processedError = createProcessedError(error, 'loading user data');
  next(processedError); // Pass to global error handler
}

// For API services - extract and log errors for service responses
try {
  const response = await externalApiCall();
  return { data: response, status: 'success' };
} catch (error) {
  const errorMessage = extractAndLogError(error, 'External API error');
  return { data: null, status: 'error', message: errorMessage };
}

// Basic error message extraction
try {
  await apiCall();
} catch (error) {
  const userMessage = extractErrorMessage(error);
  // Returns: "Authentication failed. Please log in again." for 401 errors

  // Handle specific error types
  if (isAuthError(error)) {
    // Redirect to login
  } else if (isServerError(error)) {
    // Show retry option
  }
}

Error Types

HTTP Status Codes:

  • 400 โ†’ “Invalid request. Please check your input and try again.”
  • 401 โ†’ “Authentication failed. Please log in again.”
  • 403 โ†’ “You do not have permission to access this resource.”
  • 404 โ†’ “The requested information could not be found.”
  • 500 โ†’ “Internal server error. Please try again later.”
  • 502/503 โ†’ “Service temporarily unavailable. Please try again later.”

Network Errors:

  • ECONNREFUSED โ†’ “Unable to connect to the service. Please try again later.”
  • ETIMEDOUT โ†’ “Request timed out. Please try again.”
  • ENOTFOUND โ†’ “Service not found. Please check your connection and try again.”

Features:

  • Extracts custom error messages from API responses
  • Provides fallback messages for unknown errors
  • Includes structured logging for debugging
  • Type-safe error detection with proper type guards

๐Ÿ”ง Error Handling Function Selection Guide

Choose the appropriate error handling function based on your use case:

Use extractAndLogError()

  • When: In service layer methods that make API calls
  • Purpose: Process errors and return detailed information for further handling
  • Example Use Cases:
    • apiService.getCases() - needs to process and return error details
    • authService.validateToken() - requires structured error information
    • Any service method that needs to handle errors and pass details to caller

Use createProcessedError()

  • When: In route handlers or middleware that need to return errors to client
  • Purpose: Create user-friendly error objects ready for HTTP responses
  • Example Use Cases:
    • Express route handlers returning errors to frontend
    • Middleware that processes errors for API responses
    • Any endpoint that needs to send formatted errors to client

Use extractErrorMessage()

  • When: You only need the error message string without additional processing
  • Purpose: Extract clean, user-friendly error messages from various error types
  • Example Use Cases:
    • Simple error logging without structured information
    • Template rendering where only message text is needed
    • Basic error display in UI components

๐Ÿ“‹ Error Handling Pattern Examples

// Service Layer Pattern
export async function getCases(params: CaseApiParams) {
  try {
    const response = await axiosWrapper.get<ApiResponse<CaseData>>(endpoint, { params });
    return response.data;
  } catch (error) {
    const { message, statusCode } = extractAndLogError(error, 'getCases');
    throw new Error(message); // Re-throw with processed message
  }
}
// Route Handler Pattern
router.get('/cases', async (req, res, next) => {
  try {
    const cases = await apiService.getCases(req.query);
    res.json(cases);
  } catch (error) {
    const processedError = createProcessedError(error, 'GET /cases');
    next(processedError); // Pass to error middleware
  }
});
// Simple Message Extraction
function displayError(error: unknown) {
  const message = extractErrorMessage(error);
  console.log(`Error: ${message}`);
}

Implementation Guidelines

๐ŸŽฏ Best Practices

Use the centralised index import

   // โœ… Correct - Import from index
   import { devLog, safeString, formatDate } from '#src/scripts/helpers/index.js';

   // โŒ Avoid individual file imports
   import { devLog } from '#src/scripts/helpers/devLogger.js';
   import { safeString } from '#src/scripts/helpers/dataTransformers.js';

Use TypeScript path aliases

   // โœ… Use alias
   import { safeString } from '#src/scripts/helpers/index.js';

   // โŒ Avoid relative paths
   import { safeString } from '../../helpers/dataTransformers.js';

Prefer specific imports

   // โœ… Import only what you need
   import { devLog, devError } from '#src/scripts/helpers/index.js';

   // โŒ Avoid namespace imports
   import * as helpers from '#src/scripts/helpers/index.js';

๐Ÿ”„ Usage Patterns

Replacing Console Calls

When refactoring existing code:

// Before
console.log('Debug message');
console.warn('Warning message');
console.error('Error message');

// After
import { devLog, devWarn, devError } from '#src/scripts/helpers/index.js';

devLog('Debug message');
devWarn('Warning message');
devError('Error message');

Data Validation

When working with API responses or JSON data:

import { isRecord, safeString } from '#src/scripts/helpers/index.js';

function processApiResponse(data: unknown) {
  if (!isRecord(data)) {
    throw new Error('Invalid response format');
  }

  return {
    id: safeString(data.id),
    name: safeString(data.name),
    // ... other fields
  };
}

Error Handling

When making API calls or handling errors:

import { extractErrorMessage, isAuthError, isServerError } from '#src/scripts/helpers/index.js';

async function fetchUserData() {
  try {
    const response = await apiCall();
    return response;
  } catch (error) {
    const userMessage = extractErrorMessage(error);

    // Handle specific error types
    if (isAuthError(error)) {
      // Redirect to login page
      window.location.href = '/login';
    } else if (isServerError(error)) {
      // Show retry option
      showRetryDialog(userMessage);
    } else {
      // Show general error message
      showErrorMessage(userMessage);
    }

    throw error; // Re-throw for caller to handle
  }
}

๐Ÿงช Testing

All helpers should be thoroughly tested:

  • Unit tests in tests/unit/src/scripts/helpers/
  • Test files follow pattern {helperName}.spec.ts
  • Use Chai assertions and Sinon for mocking
  • Include edge cases and error conditions

๐Ÿ“ File Organization

src/scripts/helpers/
โ”œโ”€โ”€ index.ts                  # Central export file
โ”œโ”€โ”€ dataTransformers.ts       # Data validation and transformation
โ”œโ”€โ”€ dateFormatter.ts          # Date formatting utilities
โ”œโ”€โ”€ devLogger.ts             # Development logging
โ”œโ”€โ”€ errorHandler.ts          # Error handling and user-friendly messages
โ””โ”€โ”€ [future-helper].ts       # Additional helpers as needed

๐Ÿš€ Adding New Helpers

When creating new helpers:

  1. Create the helper file with clear JSDoc comments
  2. Add comprehensive unit tests in the test directory
  3. Update this README with documentation
  4. Follow existing patterns for imports and exports
  5. Consider environment awareness (development vs production)

Template for New Helper

/**
 * [Helper Name]
 *
 * Brief description of what this helper does.
 */

/**
 * Function description
 * @param {Type} param Parameter description
 * @returns {ReturnType} Return value description
 */
export function helperFunction(param: Type): ReturnType {
  // Implementation
}

Quick Reference

Helper Purpose Key Functions
devLogger Development logging devLog, devWarn, devError
dataTransformers Data validation/transformation safeString, isRecord, safeStringFromRecord
dateFormatter Date formatting formatDate
errorHandler Error handling/user-friendly messages extractErrorMessage, createProcessedError, extractAndLogError, isAuthError, isServerError

Import any helper with:

import { functionName } from '#src/scripts/helpers/index.js';
This page was last reviewed on 2 October 2025. It needs to be reviewed again on 13 November 2025 .