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

ak-zod-form-kit

v1.0.5

Published

A powerful utility library for processing, transforming, and validating form data with Zod.

Readme

🚀 AK Zod Form Kit

Une librairie TypeScript moderne qui transforme vos formulaires en APIs typées sans effort ! ✨

AK Zod Form Kit simplifie drastiquement le traitement, la transformation et la validation des données de formulaire en utilisant la puissance de Zod. Fini les validations manuelles fastidieuses et les casse-têtes de typage – transformez vos données brutes en objets typés et validés en une seule ligne !


🎯 Pourquoi AK Zod Form Kit ?

En tant que développeurs, nous passons une part significative de notre temps à gérer des formulaires et à préparer des données pour nos APIs. Ce processus est souvent répétitif, sujet aux erreurs et peut transformer un simple formulaire en un cauchemar de typage. AK Zod Form Kit est né de ce constat pour vous offrir une solution robuste, élégante et amusante.

Imaginez :

  • Vous recevez des données d'un formulaire HTML (FormData) avec des noms de champs non standard (user_first_name, email_address_input).
  • Vous devez nettoyer ces données (trimmer les espaces, mettre en minuscules).
  • Vous avez des champs optionnels, des champs qui doivent être supprimés, ou des champs supplémentaires que votre API peut ignorer.
  • Vous devez fusionner ces données avec des informations de session ou d'autres sources (un userId, une date de création).
  • Et bien sûr, tout cela doit être rigoureusement validé selon un schéma précis, avec des messages d'erreur clairs pour l'utilisateur.

AK Zod Form Kit transforme ce défi en une brise !

// ❌ Avant : Code verbeux et répétitif, source d'erreurs de typage

function handleForm(formData: FormData) {
  const data: any = {}; // Adieu la sécurité des types !
  const errors: any = {};

  const name = formData.get('name');
  if (!name || String(name).length < 2) {
    errors.name = 'Nom requis (min 2 caractères)';
  }
  data.name = String(name || '').trim(); // Transformation manuelle

  const email = formData.get('email');
  if (!email || !String(email).includes('@')) { // Simplifié pour l'exemple
    errors.email = 'Email invalide';
  }
  data.email = String(email || '').toLowerCase(); // Transformation manuelle

  // ... répéter pour chaque champ 😴 et gérer les erreurs manuellement
  if (Object.keys(errors).length > 0) {
    console.error("Validation failed", errors);
    return;
  }
  console.log("Data ready", data);
}

// ✅ Après : Simple, typé et élégant, avec une API unifiée

import { z } from 'zod';
import { processAndValidateFormData } from 'ak-zod-form-kit'; // Votre package !

const UserSchema = z.object({
  name: z.string().min(2, 'Nom requis (min 2 caractères)'),
  email: z.string().email('Email invalide').transform(v => v.toLowerCase()),
  age: z.coerce.number().min(18, 'Majorité requise'), // z.coerce.number gère '25' -> 25
  termsAccepted: z.coerce.boolean().default(false),
});

function handleSubmit(event: Event) {
  event.preventDefault();
  const formData = new FormData(event.target as HTMLFormElement);

  const result = processAndValidateFormData(UserSchema, formData, {
    // Applique des transformations personnalisées avant la validation Zod
    transformations: { name: (v: unknown) => (typeof v === 'string' ? v.trim() : v) },
    // Fusionne des données qui ne viennent pas du formulaire (ex: ID d'utilisateur, timestamp)
    additionalData: { userId: 'abc-123', timestamp: new Date() },
    // Renomme les champs du formulaire pour correspondre au schéma
    keyTransforms: { 'user_full_name': 'name', 'user_email_address': 'email' },
    // Autorise les champs non définis dans le schéma (ou 'removeExtraFields', 'strict', etc.)
    validationStrategy: 'allowExtraFields',
    // Si vous voulez fusionner avec d'autres schémas (ex: pour valider une union de types)
    // schemaModification: 'mergeWithOr',
    // additionalSchemas: [z.object({ adminId: z.string() })]
  });

  if (result.success) {
    // result.data est 100% typé et prêt pour votre API ! 🎉
    console.log("Données validées et prêtes:", result.data);
    // console.log(result.data.name); // TypeScript sait que c'est un string
    // console.log(result.data.email); // TypeScript sait que c'est un string
    // console.log(result.data.age);   // TypeScript sait que c'est un number
    // await sendToAPI(result.data);
  } else {
    // Erreurs formatées pour votre UI
    console.error("Échec de la validation !");
    console.log("Erreurs par champ:", result.errors);         // { name: "Nom requis...", email: "Email invalide" }
    console.log("Erreurs en tableau:", result.errorsInArray); // [{ key: 'name', message: '...' }]
    console.log("Erreurs en chaîne:", result.errorsInString); // "Nom requis...\nEmail invalide..."
  }
}

🚀 Installation

npm install ak-zod-form-kit zod
# ou
yarn add ak-zod-form-kit zod
# ou
pnpm add ak-zod-form-kit zod

⚡ Démarrage rapide

Commencez à valider vos formulaires en quelques étapes simples :

import { z } from 'zod';
import { processAndValidateFormData } from 'ak-zod-form-kit';

// 1️⃣ Définir votre schéma Zod - la source de vérité pour vos données
const ContactSchema = z.object({
  name: z.string().min(2, "Nom requis"),
  email: z.string().email("Email invalide"),
  message: z.string().min(10, "Message trop court"),
  newsletter: z.coerce.boolean().default(false) // Gère 'true'/'false' des checkbox ou '1'/'0'
});

// 2️⃣ Traiter le formulaire dans votre gestionnaire de soumission
// (Compatible React, Vue, Angular, ou Vanilla JS)
async function handleSubmit(event: React.FormEvent<HTMLFormElement>) { // Exemple React
  event.preventDefault();
  const formData = new FormData(event.currentTarget);

  const result = processAndValidateFormData(ContactSchema, formData);

  if (result.success) {
    // ✅ Données validées et typées ! Prêtes pour votre API.
    console.log("Données à envoyer:", result.data);
    // Type: { name: string, email: string, message: string, newsletter: boolean }
    // await fetch('/api/contact', {
    //   method: 'POST',
    //   headers: { 'Content-Type': 'application/json' },
    //   body: JSON.stringify(result.data)
    // });
    console.log('Message envoyé !');
  } else {
    // ❌ Erreurs prêtes pour l'affichage dans votre UI
    console.error("Erreurs de validation:", result.errors);
    // setErrors(result.errors); // Ex: pour mettre à jour l'état d'un formulaire React
  }
}

// Exemple d'attachement pour Vanilla JS:
// document.getElementById('my-contact-form').addEventListener('submit', handleSubmit);

🌟 Fonctionnalités principales

AK Zod Form Kit est conçu pour être votre couteau suisse pour la gestion des données de formulaire.

🧠 Stratégies de Validation Intelligentes

Contrôlez précisément comment Zod gère les champs non déclarés ou l'optionalité des champs grâce à la validationStrategy.

  • 'strict' (Défaut) : Seuls les champs définis dans votre schéma sont acceptés. Tout champ supplémentaire déclenchera une erreur. Idéal pour des APIs strictes.

    const StrictSchema = z.object({ id: z.string() });
    // { id: "123", extra: "value" } ➡️ Échec (extra non reconnu)
  • 'allowExtraFields' : Accepte tous les champs supplémentaires non définis dans le schéma comme unknown. Parfait pour les APIs flexibles ou les formulaires qui peuvent contenir des données inattendues.

    const AllowExtraSchema = z.object({ id: z.string() });
    // { id: "123", extra: "value" } ➡️ Succès (extra est inclus)
  • 'removeExtraFields' : Supprime silencieusement tous les champs non définis dans le schéma. Utile pour nettoyer les données avant l'envoi à une API qui n'attend que des champs spécifiques.

    const RemoveExtraSchema = z.object({ id: z.string() });
    // { id: "123", extra: "value" } ➡️ Succès (extra est supprimé)
  • 'partial-strict' : Rend tous les champs de niveau racine du schéma optionnels, mais rejette tout champ supplémentaire non défini. Idéal pour les mises à jour partielles où la structure des données doit rester contrôlée.

    const PartialStrictSchema = z.object({ name: z.string(), email: z.string() });
    // { name: "Alice" } ➡️ Succès (email est optionnel)
    // { name: "Alice", extra: "value" } ➡️ Échec (extra non reconnu)
  • 'partial' : Rend tous les champs de niveau racine du schéma optionnels et autorise les champs supplémentaires. La stratégie la plus permissive pour les mises à jour partielles.

    const PartialSchema = z.object({ name: z.string(), email: z.string() });
    // { name: "Alice", extra: "value" } ➡️ Succès (email est optionnel, extra est inclus)

🧩 Modifications Structurelles du Schéma (schemaModification)

Adaptez la forme de votre schéma de base en le combinant avec d'autres schémas.

  • 'default' (Défaut) : Aucune modification. Le schéma de base est utilisé tel quel.

  • 'mergeWithAnd' : Combine votre schéma de base avec un ou plusieurs additionalSchemas en utilisant une logique ET. Les données doivent satisfaire tous les schémas fusionnés. Idéal pour composer des schémas complexes à partir de modules plus petits.

    const UserBase = z.object({ id: z.string() });
    const UserDetails = z.object({ name: z.string(), email: z.string().email() });
    const UserRole = z.object({ role: z.string() });
    
    // Le schéma résultant attendra { id, name, email, role }
    const mergedSchema = processAndValidateFormData(UserBase, { /* data */ }, {
      schemaModification: 'mergeWithAnd',
      additionalSchemas: [UserDetails, UserRole]
    });
  • 'mergeWithOr' : Crée une union entre votre schéma de base et un ou plusieurs additionalSchemas en utilisant une logique OU. Les données doivent satisfaire au moins un des schémas fournis. Parfait pour les champs polymorphiques ou les types de données alternatifs.

    const ArticleSchema = z.object({ type: z.literal('article'), title: z.string() });
    const VideoSchema = z.object({ type: z.literal('video'), url: z.string().url() });
    
    // Le schéma résultant validera soit un article, soit une vidéo
    const unionSchema = processAndValidateFormData(ArticleSchema, { /* data */ }, {
      schemaModification: 'mergeWithOr',
      additionalSchemas: [VideoSchema]
    });

🔄 Transformations Puissantes

Appliquez des logiques de transformation complexes à vos données après l'extraction mais avant la validation Zod finale. Cela complète les capacités de .transform() et .coerce de Zod, vous permettant des manipulations ad-hoc.

const MySchema = z.object({
  email: z.string().email(),
  tags: z.array(z.string()),
  price: z.number(),
});

const rawData = {
  email: '    [email protected]    ',
  tags: 'tag1, tag2 , tag3',
  price: '123.45'
};

const result = processAndValidateFormData(MySchema, rawData, {
  transformations: {
    email: (value: unknown) => (typeof value === 'string' ? value.toLowerCase().trim() : value), // Nettoyage
    tags: (value: unknown) => (typeof value === 'string' ? value.split(',').map(tag => tag.trim()) : value), // Chaîne à tableau
    price: (value: unknown) => (typeof value === 'string' ? parseFloat(value) : value) // Chaîne à nombre
  }
});

if (result.success) {
  console.log(result.data);
  // { email: '[email protected]', tags: ['tag1', 'tag2', 'tag3'], price: 123.45 }
}

📎 Support Complet des Fichiers et FormData

Gérez les File et Blob directement dans votre schéma et préparez les données pour les envois multipart/form-data.

import { z } from 'zod';
import { processAndValidateFormData } from 'ak-zod-form-kit';

const FileUploadSchema = z.object({
  title: z.string().min(1, "Titre requis"),
  document: z.instanceof(File).refine(file => file.size < 5_000_000, "Le fichier doit être inférieur à 5MB."),
  category: z.enum(['image', 'document', 'video']),
});

// Imaginez que `formData` provient d'un <form> avec un input type="file"
const formData = new FormData();
formData.append('title', 'Mon rapport annuel');
formData.append('document', new File(['contenu test'], 'rapport.pdf', { type: 'application/pdf' }));
formData.append('category', 'document');

const result = processAndValidateFormData(FileUploadSchema, formData, {
  outputFormat: 'formData' // Prêt pour `fetch` avec `multipart/form-data` !
});

if (result.success) {
  // `result.data` est un objet `FormData`
  console.log("FormData prêt pour l'upload:", result.data);
  // await fetch('/api/upload-document', {
  //   method: 'POST',
  //   body: result.data // Envoyez directement le FormData !
  // });
} else {
  console.error("Erreurs d'upload:", result.errors);
}

🎛️ Extraction Flexible et Données Additionnelles

Contrôlez précisément quels champs sont extraits, renommés, inclus ou exclus, et fusionnez des données provenant d'autres sources.

const UserProfileSchema = z.object({
  firstName: z.string(),
  lastName: z.string(),
  email: z.string().email(),
  userId: z.string(), // Champ provenant de `additionalData`
  createdAt: z.date(), // Champ provenant de `additionalData`
});

const rawFormData = {
  'user_firstname': 'Jean', // Nom d'input HTML
  'user_lastname': 'Dupont',
  'email_address': '[email protected]',
  'csrf_token': 'abc123xyz' // Champ à exclure
};

const result = processAndValidateFormData(UserProfileSchema, rawFormData, {
  keyTransforms: {
    'user_firstname': 'firstName',
    'user_lastname': 'lastName',
    'email_address': 'email'
  }, // Renommage des clés HTML vers les noms du schéma
  excludeFields: ['csrf_token'], // Exclusion de champs non pertinents
  includeFields: ['firstName', 'lastName', 'email'], // Inclusion sélective (si souhaité)
  additionalData: {
    userId: 'user-12345', // Données backend ou session
    createdAt: new Date('2023-01-15T10:00:00Z')
  }
});

if (result.success) {
  console.log(result.data);
  /*
  {
    firstName: 'Jean',
    lastName: 'Dupont',
    email: '[email protected]',
    userId: 'user-12345',
    createdAt: Date('2023-01-15T10:00:00Z')
  }
  */
}

📚 Exemples d'usage

🔐 Formulaire d'inscription avancé

Un cas d'usage classique, avec des validations croisées et des transformations.

import { z } from 'zod';
import { processAndValidateFormData } from 'ak-zod-form-kit';

const RegisterSchema = z.object({
  username: z.string().min(3, "Nom d'utilisateur minimum 3 caractères").max(20, "Nom d'utilisateur maximum 20 caractères"),
  email: z.string().email("Adresse email invalide"),
  password: z.string().min(8, "Le mot de passe doit contenir au moins 8 caractères"),
  confirmPassword: z.string(),
  acceptTerms: z.coerce.boolean().refine(val => val, "Vous devez accepter les conditions d'utilisation"),
}).refine(data => data.password === data.confirmPassword, {
  message: "Les mots de passe ne correspondent pas",
  path: ["confirmPassword"]
});

async function handleRegisterSubmit(event: React.FormEvent<HTMLFormElement>) {
  event.preventDefault();
  const formData = new FormData(event.currentTarget);

  const result = processAndValidateFormData(RegisterSchema, formData, {
    additionalData: { source: 'web', registeredAt: new Date() }, // Ajout de métadonnées
    transformations: {
      username: (v: unknown) => (typeof v === 'string' ? v.toLowerCase().trim() : v), // Nettoyage automatique
      email: (v: unknown) => (typeof v === 'string' ? v.toLowerCase() : v) // Email en minuscules
    }
  });

  if (result.success) {
    console.log("Utilisateur enregistré:", result.data);
    // Envoyer à l'API
  } else {
    console.error("Erreurs d'inscription:", result.errors);
  }
}

⚛️ Intégration avec React Hook Form (ou autres)

Zod Form Kit peut travailler de concert avec d'autres librairies de formulaires, bien que souvent il puisse les remplacer pour la logique de validation et transformation. Ici, nous montrons comment l'utiliser pour des transformations ou l'ajout de données après la validation initiale de RHF.

import React, { useState } from 'react';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod'; // Pour intégrer Zod avec RHF
import { z } from 'zod';
import { processAndValidateFormData } from 'ak-zod-form-kit';

const MyFormSchema = z.object({
  name: z.string().min(1, "Nom est requis"),
  email: z.string().email("Email invalide"),
});

function MyForm() {
  // `useForm` gère l'état des inputs et la soumission
  const { register, handleSubmit, formState: { errors }, setError } = useForm({
    resolver: zodResolver(MyFormSchema) // Utilise zodResolver pour valider avec MyFormSchema
  });

  const [loading, setLoading] = useState(false);

  // `onSubmit` est appelé par React Hook Form si la validation de `MyFormSchema` est réussie
  const onSubmit = async (data: z.infer<typeof MyFormSchema>) => {
    setLoading(true);
    // Ici, `data` est déjà validé par `zodResolver`.
    // Zod Form Kit peut être utilisé pour des transformations ou l'ajout de données additionnelles
    // AVANT l'envoi, ou si vous n'utilisez PAS `zodResolver` et voulez gérer toute la logique.

    // Si vous voulez appliquer des transformations *supplémentaires* ou `additionalData`
    // avant l'envoi, Zod Form Kit reste utile :
    const finalResult = processAndValidateFormData(MyFormSchema, data, {
      outputFormat: 'object',
      additionalData: { timestamp: new Date().toISOString() } // Exemple d'ajout
    });

    if (finalResult.success) {
      console.log("Données prêtes pour l'API:", finalResult.data);
      // await apiCall(finalResult.data);
      console.log('Formulaire envoyé avec succès !');
    } else {
      // Si des erreurs surviennent à cause de `additionalData` ou `transformations`
      // qui invalideraient le schéma après ces étapes
      Object.entries(finalResult.errors).forEach(([field, message]) => {
        setError(field as any, { message });
      });
      console.error('Erreur lors du traitement final.');
    }
    setLoading(false);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <label htmlFor="name">Nom:</label>
        <input id="name" {...register('name')} placeholder="Votre nom" />
        {errors.name && <span style={{ color: 'red' }}>{errors.name.message}</span>}
      </div>

      <div>
        <label htmlFor="email">Email:</label>
        <input id="email" type="email" {...register('email')} placeholder="Email" />
        {errors.email && <span style={{ color: 'red' }}>{errors.email.message}</span>}
      </div>

      <button type="submit" disabled={loading}>
        {loading ? 'Envoi...' : 'Envoyer'}
      </button>
    </form>
  );
}

export default MyForm; // Pour l'utiliser dans votre application React

🎨 Gestion d'erreurs dans l'UI

Intégrez facilement les erreurs formatées dans votre interface utilisateur pour un feedback instantané.

import React, { useState } from 'react';
import { z } from 'zod';
import { processAndValidateFormData } from 'ak-zod-form-kit';

const ContactSchema = z.object({
  name: z.string().min(2, "Votre nom est requis (min 2 caractères)"),
  email: z.string().email("Veuillez saisir une adresse email valide"),
  message: z.string().min(10, "Votre message est trop court (min 10 caractères)")
});

function ContactForm() {
  const [errors, setErrors] = useState<Record<string, string>>({});
  const [loading, setLoading] = useState(false);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setLoading(true);

    const formData = new FormData(e.currentTarget as HTMLFormElement);
    const result = processAndValidateFormData(ContactSchema, formData);

    if (result.success) {
      setErrors({}); // Nettoie les erreurs précédentes
      console.log("Message à envoyer:", result.data);
      // await sendMessage(result.data); // Ex: Appel API
      console.log('Message envoyé avec succès !');
    } else {
      setErrors(result.errors); // Met à jour l'état avec les nouvelles erreurs
      // Optionnel : focus sur le premier champ en erreur pour améliorer l'UX
      const firstError = result.errorsInArray[0];
      if (firstError) {
        document.querySelector(`[name="${firstError.key}"]`)?.focus();
      }
    }

    setLoading(false);
  };

  return (
    <form onSubmit={handleSubmit} style={{ display: 'flex', flexDirection: 'column', gap: '15px', maxWidth: '400px', margin: 'auto' }}>
      <div>
        <label htmlFor="name">Nom:</label>
        <input id="name" name="name" placeholder="Votre nom" style={{ width: '100%', padding: '8px' }} />
        {errors.name && <span style={{ color: 'red', fontSize: '0.8em' }}>{errors.name}</span>}
      </div>

      <div>
        <label htmlFor="email">Email:</label>
        <input id="email" name="email" type="email" placeholder="Email" style={{ width: '100%', padding: '8px' }} />
        {errors.email && <span style={{ color: 'red', fontSize: '0.8em' }}>{errors.email}</span>}
      </div>

      <div>
        <label htmlFor="message">Message:</label>
        <textarea id="message" name="message" placeholder="Votre message" rows={5} style={{ width: '100%', padding: '8px' }}></textarea>
        {errors.message && <span style={{ color: 'red', fontSize: '0.8em' }}>{errors.message}</span>}
      </div>

      <button type="submit" disabled={loading} style={{ padding: '10px 15px', cursor: 'pointer' }}>
        {loading ? 'Envoi...' : 'Envoyer'}
      </button>
    </form>
  );
}

export default ContactForm; // Pour l'utiliser dans votre application React

🔧 API Reference

processAndValidateFormData<T extends z.ZodRawShape>(schema: z.ZodObject<T>, inputData: FormData | Record<string, unknown>, options?: FormDataProcessingOptions<T>): ProcessedFormDataResult<T>

La fonction principale qui orchestre le traitement, la transformation et la validation de vos données.

  • schema: Votre schéma Zod principal définissant la structure et les règles de validation attendues.
  • inputData: Les données brutes à traiter, qui peuvent être un objet FormData (directement issu d'un formulaire HTML) ou un objet JavaScript (Record<string, unknown>).
  • options?: Un objet de configuration optionnel pour personnaliser le pipeline de traitement. Voir FormDataProcessingOptions ci-dessous.

Retourne un objet de type ProcessedFormDataResult<T>.

FormDataProcessingOptions<T extends z.ZodRawShape>

Étend l'interface FormDataExtractionOptions.

  • validationStrategy?: ValidationStrategy; (par défaut: 'strict') La stratégie de validation à utiliser pour contrôler le comportement des champs du schéma dynamique. Détermine comment Zod gère les champs non déclarés (les autorise, les supprime, ou les rejette) et définit l'optionalité des champs. Voir la section "Stratégies de Validation Intelligentes" pour plus de détails.

  • schemaModification?: SchemaModification; (par défaut: 'default') La modification structurelle à appliquer au schéma de base avant toute validation. Permet de combiner le schéma principal avec d'autres schémas via des logiques de fusion (AND) ou d'union (OR). Voir la section "Modifications Structurelles du Schéma" pour plus de détails.

  • additionalSchemas?: z.ZodTypeAny[]; Un tableau de schémas Zod supplémentaires à utiliser en conjonction avec la schemaModification. Si schemaModification est défini sur 'mergeWithAnd', ces schémas seront fusionnés (logique ET) avec le schéma de base. Si c'est 'mergeWithOr', une union (logique OU) sera créée entre tous les schémas.

  • transformations?: { [K in keyof T]?: T[K] extends z.ZodTypeAny ? (value: SchemaFieldType<T[K]>) => SchemaFieldType<T[K]> : never; }; Un objet de fonctions de transformation personnalisées à appliquer aux champs après l'extraction mais avant la validation Zod finale. Ces transformations sont utiles pour des logiques spécifiques non gérées par .transform() ou .coerce de Zod.

  • outputFormat?: 'object' | 'formData'; (par défaut: 'object') Spécifie le format des données retournées dans la propriété data en cas de succès de la validation. object retourne un objet JavaScript typé ; formData retourne un objet FormData.

  • additionalData?: Record<string, unknown>; Un objet contenant des données supplémentaires à fusionner avec les données extraites du formulaire. Ces données sont fusionnées avant la validation Zod, permettant de valider un ensemble complet de données (formulaire + ajoutées).

FormDataExtractionOptions

  • keyTransforms?: Record<string, string>; Un objet de mappage pour renommer les clés des champs extraits. Utile si les noms de vos inputs HTML diffèrent des noms de propriétés de votre schéma. Ex: { 'user_email_input': 'email' }.

  • excludeFields?: string[]; Un tableau de noms de champs à ignorer complètement lors de l'extraction. Ex: ['_csrf_token', 'password_confirm'].

  • includeFields?: string[]; Un tableau de noms de champs à inclure exclusivement. Si cette option est spécifiée, seuls les champs listés ici seront extraits. excludeFields prime si un champ est présent dans les deux listes.

ProcessedFormDataResult<T extends z.ZodRawShape>

Le type de retour de la fonction processAndValidateFormData.

En cas de succès (success: true):

{
  success: true;
  data: z.infer<z.ZodObject<T>> | FormData; // Les données validées, typées, soit en objet, soit en FormData
}

En cas d'échec (success: false):

{
  success: false;
  data: Record<string, unknown>; // Les données (brutes/transformées) ayant échoué la validation, pour le débogage/affichage
  errors: Record<string, string>; // Erreurs formatées en objet (chemin du champ -> message)
  errorsInArray: { key: string; message: string }[]; // Erreurs formatées en tableau d'objets ({ key: 'champ', message: '...' })
  errorsInString: string; // Erreurs formatées en chaîne de caractères (chaque erreur sur une nouvelle ligne)
}

Fonctions utilitaires exportées

Ces fonctions sont les briques de base utilisées par processAndValidateFormData et peuvent être importées et utilisées indépendamment si vous avez besoin d'une logique plus granulaire.

  • extractDataFromFormData(data: FormData | Record<string, unknown>, options?: FormDataExtractionOptions): Record<string, unknown> Extrait et organise les données d'un objet FormData ou Record<string, unknown> avec des options de transformation de clés, inclusion/exclusion.

  • applyDataTransformations(data: Record<string, unknown>, transformations: Record<string, (value: unknown) => unknown>): Record<string, unknown> Applique un ensemble de fonctions de transformation à des champs spécifiques d'un objet de données.

  • convertObjectToFormData(inputObject: Record<string, unknown>): FormData Convertit un objet JavaScript standard en un objet FormData, gérant les types complexes (fichiers, blobs, dates, tableaux, objets imbriqués).

  • createDynamicZodSchema<T extends z.ZodRawShape>(baseSchema: z.ZodObject<T>, inputData: Record<string, unknown>, validationStrategy?: ValidationStrategy, schemaModification?: SchemaModification, additionalSchemas?: z.ZodTypeAny[]): z.ZodTypeAny Construit un schéma Zod dynamique basé sur un schéma de base, la structure des données d'entrée, et les stratégies de validation/modification spécifiées.

  • validateDataWithDynamicSchema<T extends z.ZodRawShape>(baseSchema: z.ZodObject<T>, data: Record<string, unknown>, validationStrategy?: ValidationStrategy, schemaModification?: SchemaModification, additionalSchemas?: z.ZodTypeAny[]): z.ZodSafeParseResult<z.infer<ReturnType<typeof createDynamicZodSchema<T>>>> Valide un objet de données en utilisant un schéma Zod dynamique créé à partir du baseSchema, data et des options de stratégie/modification.

  • formatZodErrorsAsObject(validationResult: z.ZodSafeParseResult<any>): { [key: string]: string } Convertit les erreurs détaillées d'un résultat de validation Zod en un objet plat (chemin du champ -> message).

  • formatZodErrorsAsArray(validationResult: z.ZodSafeParseResult<any>): { key: string; message: string }[] Convertit les erreurs détaillées d'un résultat de validation Zod en un tableau d'objets ({ key: string; message: string }).


🎯 Cas d'usage recommandés

AK Zod Form Kit est une solution idéale pour :

  • ✅ Les formulaires complexes avec des validations métier spécifiques.
  • ✅ L'upload de fichiers accompagnés de métadonnées.
  • ✅ La gestion des APIs hybrides nécessitant à la fois du JSON et du multipart/form-data.
  • ✅ La transformation de données brutes avant leur envoi à un backend.
  • ✅ Les applications construites avec React, Vue, Angular, ou tout autre framework JavaScript.
  • ✅ La mise en place d'une validation côté client robuste et typée.
  • ✅ Les scénarios d'intégration de données où les formats d'entrée peuvent varier ou nécessitent un nettoyage.

⚠️ Éviter pour :

  • Les formulaires très simples où l'overhead de la bibliothèque serait inutile.
  • Les scénarios de performance ultra-critique où une validation native ou manuelle très minimaliste serait préférée (bien que Zod soit déjà très performant).
  • Les projets sans TypeScript, car une grande partie des avantages de typage et de sécurité serait perdue.

📊 Comparaison (vs. Validation manuelle, Formik, React Hook Form)

| Fonctionnalité | AK Zod Form Kit | Formik | React Hook Form | Validation manuelle | | :------------------------- | :-------------------- | :------------------------- | :------------------------- | :------------------------ | | Validation Zod Intégrée | ✅ | ⚠️ (avec yup) | ✅ (avec zodResolver) | ❌ | | Transformation automatique | ✅ (via transformations et Zod) | ❌ | ❌ | ❌ | | Support FormData natif | ✅ | ❌ (nécessite Formik-persist ou équivalent) | ⚠️ (nécessite adapter) | ✅ (natif) | | Framework agnostic | ✅ | ❌ (principalement React) | ❌ (principalement React) | ✅ | | API simple et unifiée | ✅ | ⚠️ | ⚠️ | ❌ | | Bundle size | 📦 Léger (~10KB gzipped) | 📦 Moyen | 📦 Léger | 📦 Aucun | | Typage TypeScript | ✅ (fort) | ✅ | ✅ | ❌ |


🚀 Roadmap

Votre avis est précieux pour orienter les futures évolutions !

  • [ ] v1.1 : Support amélioré des schémas imbriqués complexes et des tableaux d'objets.
  • [ ] v1.2 : Plugins de transformation courants (gestion des dates, monnaie, etc.).
  • [ ] v1.3 : Intégrations officielles avec des librairies de formulaires populaires (Formik, React Hook Form, Final Form) pour des scénarios hybrides.
  • [ ] v1.4 : Gestion native des arrays de fichiers multiples via FormData.
  • [ ] v2.0 : Architecture de middleware extensible pour des traitements encore plus personnalisés.

🤝 Contribution

Les contributions sont les bienvenues ! N'hésitez pas à proposer des améliorations, des corrections de bugs ou de nouvelles fonctionnalités.

  1. Fork le projet.
  2. Créez une branche pour votre fonctionnalité (git checkout -b feature/ma-super-feature).
  3. Commitez vos changements (git commit -m 'Ajout d'une super fonctionnalité').
  4. Poussez vers votre branche (git push origin feature/ma-super-feature).
  5. Ouvrez une Pull Request.

Développement local

git clone https://github.com/AndersonKouadio/ak-zod-form-kit.git
cd ak-zod-form-kit
npm install

# Lancer les tests

npm test
npm run test:watch
npm run test:coverage

# Compiler le projet

npm run build

# Linter le code (et corriger automatiquement)

npm run lint
npm run lint:fix

📄 Licence

Ce projet est sous licence MIT.


🙏 Remerciements

  • Zod pour son excellence en matière de validation TypeScript.
  • TypeScript pour la sécurité et la robustesse des types.
  • La communauté open source pour l'inspiration et les outils.

<div align="center"> Fait avec ❤️ pour les développeurs qui aiment les formulaires typés. <br> ⭐ Star ce repo • 🐦 Suivre <a href="https://x.com/andy_jojo01">sur X</a> • 📖 Lire la doc (ce README !) </div>