npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

path-normalizer

v1.0.3

Published

A flexible path normalization utility for mapping backend error paths to frontend form fields

Readme

Path Normalizer

Transform any path format into any other format - the ultimate path mapping utility for JavaScript/TypeScript applications.

Perfect for handling API responses, form validation errors, configuration mapping, and any scenario where you need to convert between different path structures.

Why You Need This

Ever struggled with these common problems?

  • API returns: user[0].email but your form expects users.0.emailAddress
  • Backend errors: text_templates['en'].title but frontend needs localization[0].fields.title
  • Config mapping: api.users.profile needs to become internal.userData.profile

Path Normalizer solves all of these with simple, powerful rules.

Installation

npm install path-normalizer

Quick Examples

Basic Path Conversion

import { PathNormalizer } from 'path-normalizer';

const normalizer = new PathNormalizer();

// Convert bracket notation to dot notation
normalizer.normalizePath("test[0].path"); 
// → "test.0.path"

// Map specific paths
normalizer.addRule(['user', 'email'], () => 'profile.email');
normalizer.normalizePath('user.email'); 
// → "profile.email"

Wildcard Matching

// Match any user ID
normalizer.addRule(['users', '*', 'email'], (_, context) => {
  const userId = context.segments[1];
  return `user_${userId}_email`;
});

normalizer.normalizePath('users.123.email'); 
// → "user_123_email"

Real-World Form Validation

// Backend: "text_templates['en'].title"
// Frontend: "localization[0].fields.title"

const locales = ['en', 'fr', 'de'];
normalizer.addRule(['text_templates', (s) => locales.includes(s), '*'], (_, context) => {
  const locale = context.segments[1];
  const field = context.segments[2];
  const index = locales.indexOf(locale);
  return `localization[${index}].fields.${field}`;
});

normalizer.normalizePath("text_templates['en'].title");
// → "localization[0].fields.title"

Key Features

  • ⚡ Zero Config: Works out of the box with sensible defaults
  • 🎯 Smart Matching: Wildcards, regex, and custom matchers
  • 🔄 Flexible Transform: Convert any path to any other format
  • 📦 TypeScript: Full type safety and IntelliSense
  • 🚀 Performance: Priority-based rule evaluation
  • 🔧 Universal: Works with any framework or library

Common Use Cases

1. API Response Mapping

// API returns: "user[0].profile.email"
// Your app expects: "users.0.emailAddress"

normalizer.addRule(['user', '*', 'profile', 'email'], (_, context) => {
  const userId = context.segments[1];
  return `users.${userId}.emailAddress`;
});

2. Form Validation Error Mapping

// Backend error: "form_data['contact'].email"
// React Hook Form field: "contact.email"

normalizer.addRule(['form_data', '*', 'email'], (_, context) => {
  const section = context.segments[1];
  return `${section}.email`;
});

3. Configuration Normalization

// Config file: "api.users.profile.settings"
// Internal structure: "userConfig.profile"

normalizer.addRule(['api', 'users', 'profile', '**'], () => 'userConfig.profile');

4. Multi-language Content Mapping

// CMS path: "content['en'].sections[0].title"
// App path: "localization.en.sections.0.title"

normalizer.addRule(['content', '*', 'sections', '*', '*'], (_, context) => {
  const lang = context.segments[1];
  const sectionIndex = context.segments[3];
  const field = context.segments[4];
  return `localization.${lang}.sections.${sectionIndex}.${field}`;
});

Framework Integration

React Hook Form

import { useEffect } from 'react';
import { UseFormReturn } from 'react-hook-form';
import { PathNormalizer } from 'path-normalizer';

export function useNormalizedFormErrors({ 
  methods, 
  backendErrors,
  normalizer 
}) {
  const { setError, clearErrors } = methods;

  useEffect(() => {
    if (!backendErrors) return;

    clearErrors();

    Object.entries(backendErrors).forEach(([path, message]) => {
      const result = normalizer.normalizePath(path);
      
      if (result.matched && result.normalized) {
        setError(result.normalized, {
          type: 'manual',
          message
        });
      }
    });
  }, [backendErrors, normalizer, setError, clearErrors]);
}

Formik

import { FormikErrors } from 'formik';
import { PathNormalizer } from 'path-normalizer';

const normalizeFormErrors = (errors: Record<string, string>, normalizer: PathNormalizer) => {
  const normalized: FormikErrors<any> = {};
  
  Object.entries(errors).forEach(([path, message]) => {
    const result = normalizer.normalizePath(path);
    if (result.matched && result.normalized) {
      normalized[result.normalized] = message;
    }
  });
  
  return normalized;
};

API Reference

Core Methods

// Create normalizer
const normalizer = new PathNormalizer({
  delimiter: '.',           // Path separator (default: '.')
  caseInsensitive: false,   // Case-sensitive matching (default: false)
  throwOnUnmatched: false   // Don't throw on unmatched paths (default: false)
});

// Add rules
normalizer.addRule(['user', 'email'], () => 'profile.email');
normalizer.addRule(['users', '*', 'email'], (_, context) => {
  const userId = context.segments[1];
  return `user_${userId}_email`;
});

// Normalize paths
const result = normalizer.normalizePath('user.email');
// result.normalized = 'profile.email'
// result.matched = true
// result.original = 'user.email'

// Normalize multiple paths
const results = normalizer.normalizePaths(['user.email', 'users.123.email']);

Pattern Types

// Exact match
['user', 'email']

// Wildcard (any single segment)
['users', '*', 'email']

// Deep wildcard (any remaining segments)
['api', '**']

// Regex
[/^user_\d+$/, 'email']

// Custom matcher function
['items', (seg) => !isNaN(Number(seg)), 'value']

// Mixed patterns
['data', '*', /^(name|email)$/, '**']

Advanced Features

// Priority-based rules (higher number = higher priority)
normalizer.addRule(['user', '*'], () => 'low-priority', 1);
normalizer.addRule(['user', 'email'], () => 'high-priority', 10);

// Builder pattern for complex rules
import { PathRuleBuilder } from 'path-normalizer';

const rule = PathRuleBuilder.create()
  .exact('text_templates')
  .oneOf(['en', 'fr', 'de'])
  .deepWildcard()
  .transform((matched, context) => {
    const locale = context.segments[1];
    const index = ['en', 'fr', 'de'].indexOf(locale);
    return `localization[${index}].${context.segments.slice(2).join('.')}`;
  })
  .setPriority(10)
  .build();

normalizer.addRules([rule]);

Why Choose Path Normalizer?

✅ Built for Real Problems

  • Solves actual pain points developers face daily
  • Handles complex API-to-frontend path mapping
  • Works with any form library or framework

✅ Powerful Yet Simple

  • Zero configuration needed to get started
  • Intuitive API that scales from simple to complex
  • Full TypeScript support with excellent IntelliSense

✅ Performance First

  • Priority-based rule evaluation
  • Optimized for high-frequency path transformations
  • Minimal bundle size impact

✅ Battle Tested

  • Comprehensive test coverage
  • Used in production applications
  • Active maintenance and updates

Get Started Today

npm install path-normalizer

Perfect for:

  • Form validation error mapping
  • API response transformation
  • Configuration normalization
  • Multi-language content mapping
  • Any path-to-path conversion needs

📖 Full Documentation: GitHub Repository
🐛 Report Issues: GitHub Issues
📝 Changelog: CHANGELOG.md