JSPM

@bernierllc/validators-image-asset

0.1.0
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 6
  • Score
    100M100P100Q58181F
  • License UNLICENSED

Image asset validation for the BernierLLC validators ecosystem - validates alt text, formats, sizes, and optimization

Package Exports

  • @bernierllc/validators-image-asset
  • @bernierllc/validators-image-asset/dist/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@bernierllc/validators-image-asset) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

@bernierllc/validators-image-asset

Image asset validation for the BernierLLC validators ecosystem - validates accessibility, performance, and optimization.

Installation

npm install @bernierllc/validators-image-asset

Features

  • Accessibility: Validates alt text presence for screen readers
  • Performance: Checks file sizes and image dimensions
  • Optimization: Recommends modern formats (WebP, AVIF) and responsive images
  • Responsive: Validates srcset usage for large images
  • Type-Safe: Full TypeScript support with detailed interfaces

Usage

Basic Validation

import { validateImageAsset } from '@bernierllc/validators-image-asset';

const imageData = {
  src: 'example.jpg',
  alt: 'A beautiful sunset',
  format: 'jpg',
  size: 150000, // bytes
  width: 1920,
  height: 1080
};

const problems = await validateImageAsset(imageData);

problems.forEach(problem => {
  console.log(`${problem.severity}: ${problem.message}`);
  if (problem.suggestion) {
    console.log(`  Suggestion: ${problem.suggestion}`);
  }
});

Using Individual Rules

import {
  missingAltText,
  inefficientFormat,
  excessiveFileSize
} from '@bernierllc/validators-image-asset';
import { createRuleContext } from '@bernierllc/validators-core';
import { createSharedUtils } from '@bernierllc/validators-utils';

const imageData = {
  src: 'example.png',
  alt: 'Example image',
  format: 'png',
  size: 250000
};

const sharedUtils = createSharedUtils();
const context = createRuleContext('image-asset', imageData, sharedUtils);

// Run specific rule
const check = missingAltText.create(context);
check(imageData);

const problems = context.getProblems();

Integration with Validator Runner

import { imageAssetValidator } from '@bernierllc/validators-image-asset';
import { createRuleContext } from '@bernierllc/validators-core';
import { createSharedUtils } from '@bernierllc/validators-utils';

const imageData = {
  src: 'hero.webp',
  alt: 'Hero image',
  format: 'webp',
  size: 180000,
  width: 1920,
  height: 1080,
  srcset: 'hero-320w.webp 320w, hero-640w.webp 640w, hero.webp 1920w'
};

const sharedUtils = createSharedUtils();
const context = createRuleContext('image-asset', imageData, sharedUtils);

const problems = await imageAssetValidator.validate(imageData, context);

API Reference

validateImageAsset(imageData, utils?)

Validates image assets for accessibility, performance, and optimization.

Parameters:

  • imageData: ImageAssetData - The image data to validate
  • utils?: SharedUtils - Optional shared utilities (created automatically if not provided)

Returns: Promise<Problem[]> - Array of validation problems

ImageAssetData

interface ImageAssetData {
  src: string;           // Image source URL (required)
  alt?: string;          // Alt text for accessibility
  title?: string;        // Optional title attribute
  format?: string;       // Image format (jpg, png, webp, avif, svg, etc.)
  size?: number;         // File size in bytes
  width?: number;        // Image width in pixels
  height?: number;       // Image height in pixels
  srcset?: string;       // Responsive image srcset
}

Validation Rules

1. Missing Alt Text (image-asset/missing-alt-text)

Severity: Error Description: All images must have descriptive alt text for accessibility

// ❌ Invalid - Missing alt text
const invalid = {
  src: 'example.jpg'
};

// ✅ Valid - Has alt text
const valid = {
  src: 'example.jpg',
  alt: 'A beautiful mountain landscape'
};

2. Inefficient Format (image-asset/inefficient-format)

Severity: Error (legacy formats), Warning (acceptable formats) Description: Images should use modern formats like WebP or AVIF

// ❌ Error - Legacy format
const legacy = {
  src: 'example.bmp',
  alt: 'Example',
  format: 'bmp'
};

// ⚠️ Warning - Acceptable but not optimal
const acceptable = {
  src: 'example.jpg',
  alt: 'Example',
  format: 'jpg'
};

// ✅ Valid - Modern format
const modern = {
  src: 'example.webp',
  alt: 'Example',
  format: 'webp'
};

Format Categories:

  • Modern (no warning): WebP, AVIF, SVG
  • Acceptable (warning): PNG, JPG, JPEG, GIF
  • Legacy (error): BMP, TIFF, TIF

3. Excessive File Size (image-asset/excessive-file-size)

Severity: Error (>1MB), Warning (>500KB), Info (>200KB) Description: Image files should be compressed to reduce load time

// ❌ Error - Too large (>1MB)
const tooLarge = {
  src: 'example.jpg',
  alt: 'Example',
  size: 1.5 * 1024 * 1024
};

// ⚠️ Warning - Large (>500KB)
const large = {
  src: 'example.jpg',
  alt: 'Example',
  size: 600 * 1024
};

// ℹ️ Info - Could be optimized (>200KB)
const moderate = {
  src: 'example.jpg',
  alt: 'Example',
  size: 250 * 1024
};

// ✅ Valid - Optimized (<200KB)
const optimized = {
  src: 'example.webp',
  alt: 'Example',
  size: 150 * 1024
};

Size Thresholds:

  • Recommended: < 200KB
  • Maximum: < 500KB
  • Critical: < 1MB

4. Excessive Dimensions (image-asset/excessive-dimensions)

Severity: Error (>4096x2160), Warning (>2560x1440) Description: Image dimensions should match display requirements

// ❌ Error - Excessive dimensions
const excessive = {
  src: 'example.jpg',
  alt: 'Example',
  width: 5000,
  height: 3000
};

// ⚠️ Warning - Large dimensions
const large = {
  src: 'example.jpg',
  alt: 'Example',
  width: 3000,
  height: 1600
};

// ✅ Valid - Reasonable dimensions
const reasonable = {
  src: 'example.jpg',
  alt: 'Example',
  width: 1920,
  height: 1080
};

Dimension Thresholds:

  • Recommended: ≤ 2560x1440 (4K displays)
  • Critical: ≤ 4096x2160

5. Missing Srcset (image-asset/missing-srcset)

Severity: Warning Description: Large images should provide multiple sizes via srcset

// ⚠️ Warning - Large image without srcset
const noSrcset = {
  src: 'example.jpg',
  alt: 'Example',
  width: 1920,
  height: 1080
};

// ✅ Valid - Has responsive srcset
const withSrcset = {
  src: 'example.jpg',
  alt: 'Example',
  width: 1920,
  height: 1080,
  srcset: 'example-320w.jpg 320w, example-640w.jpg 640w, example.jpg 1920w',
  sizes: '(max-width: 640px) 100vw, 640px'
};

// ✅ Valid - Small image doesn't need srcset
const smallImage = {
  src: 'icon.png',
  alt: 'Icon',
  width: 64,
  height: 64
};

Thresholds:

  • Width > 800px OR Height > 600px: srcset recommended

Examples

Optimal Web Image

const optimalImage = {
  src: 'hero.webp',
  alt: 'Hero section showing our product dashboard',
  format: 'webp',
  size: 180 * 1024, // 180KB
  width: 1920,
  height: 1080,
  srcset: 'hero-320w.webp 320w, hero-640w.webp 640w, hero-1280w.webp 1280w, hero.webp 1920w',
  sizes: '(max-width: 768px) 100vw, (max-width: 1200px) 80vw, 1200px'
};

const problems = await validateImageAsset(optimalImage);
// Result: [] (no problems)

Email-Safe Image

const emailImage = {
  src: 'newsletter-banner.jpg',
  alt: 'Monthly newsletter banner',
  format: 'jpg',
  size: 120 * 1024, // 120KB
  width: 600,
  height: 200
};

const problems = await validateImageAsset(emailImage);
// Result: [{ severity: 'warning', message: '...not optimal format...' }]
// JPG acceptable for email compatibility

Icon/Thumbnail

const icon = {
  src: 'user-avatar.webp',
  alt: 'User profile picture',
  format: 'webp',
  size: 8 * 1024, // 8KB
  width: 150,
  height: 150
};

const problems = await validateImageAsset(icon);
// Result: [] (no problems - small images don't need srcset)

Integration Status

  • Logger: Not applicable (primitive validator)
  • Docs-Suite: Ready - Markdown documentation with code examples
  • NeverHub: Not applicable (primitive validator)

Best Practices

1. Always Provide Alt Text

// ❌ Bad
<img src="product.jpg" />

// ✅ Good
<img src="product.jpg" alt="Red running shoes with white soles" />

2. Use Modern Formats with Fallbacks

<picture>
  <source srcset="image.avif" type="image/avif">
  <source srcset="image.webp" type="image/webp">
  <img src="image.jpg" alt="Fallback for older browsers">
</picture>

3. Implement Responsive Images

<img
  src="large.jpg"
  srcset="small.jpg 320w, medium.jpg 640w, large.jpg 1280w"
  sizes="(max-width: 640px) 100vw, 50vw"
  alt="Responsive image example"
/>

4. Optimize File Sizes

  • Use compression tools (ImageOptim, Squoosh, Sharp)
  • Target < 200KB for web images
  • Use progressive JPEG for large photos
  • Consider lazy loading for below-fold images

5. Match Dimensions to Display

  • Don't serve 4K images for mobile devices
  • Use srcset to provide appropriate sizes
  • Consider device pixel ratio (2x, 3x for retina)

Testing

# Run tests
npm test

# Run tests with coverage
npm run test:coverage

# Run tests once (CI)
npm run test:run

Development

# Build the package
npm run build

# Watch mode for development
npm run dev

# Lint code
npm run lint

# Fix linting issues
npm run lint:fix

# Clean build artifacts
npm run clean

License

Copyright (c) 2025 Bernier LLC. All rights reserved.

See Also