coddyger
Version:
Coddyger est une bibliothèque JavaScript/TypeScript qui fournit des fonctions communes et des plugins pour la gestion des données, la communication entre services, et des utilitaires avancés pour le développement d'applications.
1,224 lines (1,223 loc) • 48.3 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const bcrypt = __importStar(require("bcrypt"));
const path = __importStar(require("path"));
const fs = __importStar(require("fs"));
const http = __importStar(require("http"));
const services_1 = require("./services");
const globals_1 = __importStar(require("./globals"));
const mongoose_1 = __importDefault(require("mongoose"));
const date_fns_1 = require("date-fns");
const locale_1 = require("date-fns/locale");
const libphonenumber_js_1 = require("libphonenumber-js");
const countries_json_1 = __importDefault(require("./data/countries.json"));
const coddyger = {
/**
* Gère les réponses API de manière standardisée
* @param context - Le contexte de la requête HTTP
* @param promise - La promesse à traiter
*/
api: (context, promise) => {
promise
.then((res) => {
let status = res.status;
let message = res.message;
let data = res.data;
let isFile = res.isFile;
// Extraire les champs supplémentaires (tout sauf status, message, data, isFile)
const { status: _, message: __, data: ___, isFile: ____ } = res, additionalFields = __rest(res, ["status", "message", "data", "isFile"]);
let response = Object.assign({ message: message, data: data !== undefined || true ? data : [] }, additionalFields // Inclure tous les champs supplémentaires
);
if (isFile) {
context.setHeader("Content-type", data.type);
context.sendFile(data.file);
}
else {
return context.status(status).send(response);
}
})
.catch((err) => {
console.log(err);
return context.status(500).send({});
})
.catch((err) => {
// console.log(err)
return context
.status(500)
.send({
error: true,
message: "une erreur interne s'est produite veuillez réssayer plutard",
});
});
},
/**
* Affiche des messages de log formatés avec horodatage et niveau de log
* @param msg - Le message à logger
* @param error - 1 pour erreur, 0 pour info
*/
konsole: (msg, error = 0) => {
let message = new Date().toISOString() +
"[" +
(error === 1 ? "error" : "info") +
"]" +
JSON.stringify(msg);
if (error === 1) {
console.error(message);
}
else {
console.log(message);
}
},
string: {
/**
* Vérifie si une valeur est vide
* @param value - La valeur à vérifier
* @returns true si la valeur est vide, null ou undefined
*/
isEmpty: function (value) {
return (value === undefined ||
value === null ||
value.length <= 0 ||
value === "");
},
/**
* Vérifie si une chaîne est une adresse email valide
* @param payload - L'email à vérifier
* @returns true si l'email est valide
*/
isEmailAddress: function (payload) {
const regexp = new RegExp(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/);
return regexp.test(payload);
},
/**
* Vérifie si une chaîne est un nombre valide
* @param payload - La chaîne à vérifier
* @returns true si la chaîne est un nombre
*/
isNumber: function (payload) {
return /^(?:-?\d+|-?\d{1, 3}(?:, \d{3})+)?(?:\.\d+)?$/.test(payload);
},
/**
* Vérifie si une chaîne est une date valide
* @param payload - La chaîne à vérifier
* @returns true si la chaîne est une date valide
*/
isDate: function (payload) {
const date = new Date(payload);
return !isNaN(date.getTime());
},
/**
* Vérifie si une chaîne est un ObjectId MongoDB valide
* @param payload - La chaîne à vérifier
* @returns true si la chaîne est un ObjectId valide
*/
isValidObjectId: (payload) => {
const objectIdRegex = /^[0-9a-fA-F]{24}$/;
return objectIdRegex.test(payload);
},
/**
* Génère un nouvel ObjectId MongoDB
* @returns Un nouvel ObjectId
*/
generateObjectId: () => {
try {
return new mongoose_1.default.Types.ObjectId();
}
catch (error) {
console.error(error);
return error;
}
},
/**
* Convertit une chaîne en ObjectId MongoDB
* @param value - La valeur à convertir
* @returns L'ObjectId correspondant
*/
toObjectId: (value) => {
try {
return new mongoose_1.default.Types.ObjectId(value);
}
catch (error) {
console.error("ERREUR::", error);
return error;
}
},
/**
* Chiffre un mot de passe
* @param payload - Le mot de passe à chiffrer
* @returns Le mot de passe chiffré
*/
encryptPassword: (payload) => __awaiter(void 0, void 0, void 0, function* () {
const saltRounds = 10;
const hashedPassword = yield bcrypt.hash(payload, saltRounds);
return hashedPassword;
}),
/**
* Vérifie un mot de passe par rapport à sa version chiffrée
* @param payload - Le mot de passe en clair
* @param hashedPayload - Le mot de passe chiffré
* @returns true si les mots de passe correspondent
*/
decryptPassword: (payload, hashedPayload) => __awaiter(void 0, void 0, void 0, function* () {
const result = yield bcrypt.compare(payload, hashedPayload);
return result;
}),
/**
* Met en majuscule la première lettre de chaque mot
* @param payload - Le texte à transformer
* @returns Le texte avec les premières lettres en majuscule
*/
capitalizeEachWord: (payload) => {
return payload
.split(" ")
.map((word) => {
const lowercasedWord = word.toLowerCase();
return (lowercasedWord.charAt(0).toUpperCase() + lowercasedWord.slice(1));
})
.join(" ");
},
/**
* Convertit un texte en vecteur numérique (vectorisation)
* @param text - Le texte à vectoriser
* @returns Un vecteur de fréquences des mots
*/
vectorizeText: (text) => {
// Convert text to lowercase and remove special characters
const cleanText = text.toLowerCase().replace(/[^a-z0-9\s]/g, "");
// Split into words and remove empty strings
const words = cleanText.split(/\s+/).filter((word) => word.length > 0);
// Create a vocabulary (unique words)
const vocabulary = Array.from(new Set(words));
// Create vector (word frequency)
const vector = vocabulary.map((term) => {
return words.filter((word) => word === term).length;
});
return vector;
},
/**
* Calcule la similarité cosinus entre deux vecteurs
* @param vector1 - Premier vecteur
* @param vector2 - Second vecteur
* @returns La similarité cosinus entre les deux vecteurs (entre 0 et 1)
*/
cosineSimilarity: (vector1, vector2) => {
if (vector1.length !== vector2.length) {
throw new Error("Vectors must have the same length");
}
const dotProduct = vector1.reduce((acc, val, i) => acc + val * vector2[i], 0);
const magnitude1 = Math.sqrt(vector1.reduce((acc, val) => acc + val * val, 0));
const magnitude2 = Math.sqrt(vector2.reduce((acc, val) => acc + val * val, 0));
if (magnitude1 === 0 || magnitude2 === 0) {
return 0;
}
return dotProduct / (magnitude1 * magnitude2);
},
/**
* Vérifie si une chaîne est un numéro de téléphone valide
* @param phoneNumber - Le numéro de téléphone à vérifier
* @param countryCode - Le code pays optionnel (ex: 'FR', 'US')
* @returns true si le numéro est valide
*/
isValidPhoneNumber: (phoneNumber, countryCode) => {
try {
const parsedNumber = (0, libphonenumber_js_1.parsePhoneNumberFromString)(phoneNumber, countryCode);
return parsedNumber ? parsedNumber.isValid() : false;
}
catch (error) {
return false;
}
},
/**
* Obtient le code pays à partir d'un préfixe téléphonique
* @param prefix - Le préfixe téléphonique (ex: +33, +1)
* @returns Le code pays correspondant ou null si non trouvé
*/
getCountryCodeFromPrefix: (prefix) => {
// Remove '+' if present
const cleanPrefix = prefix.replace('+', '');
return countries_json_1.default.prefixMap[cleanPrefix] || null;
},
/**
* Obtient la liste des pays avec leurs codes, noms et drapeaux
* @returns Un tableau d'objets pays
*/
getCountryList: () => {
return countries_json_1.default.countries;
},
/**
* Génère un mot de passe aléatoire sécurisé
* @param length - Longueur du mot de passe (défaut: 12)
* @param includeSymbols - Inclure des symboles spéciaux (défaut: true)
* @returns Un mot de passe aléatoire sécurisé
*/
generateSecurePassword: (length = 12, includeSymbols = true) => {
const lowercase = 'abcdefghijklmnopqrstuvwxyz';
const uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const numbers = '0123456789';
const symbols = '!@#$%^&*()_+-=[]{}|;:,.<>?';
let charset = lowercase + uppercase + numbers;
if (includeSymbols) {
charset += symbols;
}
let password = '';
// Garantir au moins un caractère de chaque type
password += lowercase[Math.floor(Math.random() * lowercase.length)];
password += uppercase[Math.floor(Math.random() * uppercase.length)];
password += numbers[Math.floor(Math.random() * numbers.length)];
if (includeSymbols) {
password += symbols[Math.floor(Math.random() * symbols.length)];
}
// Compléter avec des caractères aléatoires
for (let i = password.length; i < length; i++) {
password += charset[Math.floor(Math.random() * charset.length)];
}
// Mélanger le mot de passe
return password.split('').sort(() => Math.random() - 0.5).join('');
},
/**
* Génère un code PIN numérique aléatoire
* @param length - Longueur du code PIN (défaut: 6)
* @returns Un code PIN numérique
*/
generatePIN: (length = 6) => {
let pin = '';
for (let i = 0; i < length; i++) {
pin += Math.floor(Math.random() * 10).toString();
}
return pin;
},
/**
* Génère un token aléatoire alphanumérique
* @param length - Longueur du token (défaut: 32)
* @returns Un token aléatoire
*/
generateToken: (length = 32) => {
const charset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let token = '';
for (let i = 0; i < length; i++) {
token += charset[Math.floor(Math.random() * charset.length)];
}
return token;
},
/**
* Nettoie et normalise une chaîne de caractères
* @param text - Le texte à nettoyer
* @returns Le texte nettoyé
*/
cleanText: (text) => {
return text
.trim()
.replace(/\s+/g, ' ') // Remplace les espaces multiples par un seul
.replace(/[^\w\s\-_.@]/g, '') // Supprime les caractères spéciaux sauf quelques-uns
.toLowerCase();
},
/**
* Tronque un texte à une longueur spécifiée avec des points de suspension
* @param text - Le texte à tronquer
* @param maxLength - Longueur maximale (défaut: 100)
* @param suffix - Suffixe à ajouter (défaut: "...")
* @returns Le texte tronqué
*/
truncate: (text, maxLength = 100, suffix = "...") => {
if (text.length <= maxLength) {
return text;
}
return text.substring(0, maxLength - suffix.length) + suffix;
},
/**
* Convertit un texte en slug URL-friendly
* @param text - Le texte à convertir
* @returns Le slug généré
*/
slugify: (text) => {
return text
.toLowerCase()
.trim()
.replace(/[àáäâ]/g, 'a')
.replace(/[èéëê]/g, 'e')
.replace(/[ìíïî]/g, 'i')
.replace(/[òóöô]/g, 'o')
.replace(/[ùúüû]/g, 'u')
.replace(/[ñ]/g, 'n')
.replace(/[ç]/g, 'c')
.replace(/[^a-z0-9 -]/g, '')
.replace(/\s+/g, '-')
.replace(/-+/g, '-')
.replace(/^-+/, '')
.replace(/-+$/, '');
},
/**
* Masque partiellement une chaîne (utile pour emails, téléphones)
* @param text - Le texte à masquer
* @param visibleStart - Nombre de caractères visibles au début (défaut: 2)
* @param visibleEnd - Nombre de caractères visibles à la fin (défaut: 2)
* @param maskChar - Caractère de masquage (défaut: "*")
* @returns Le texte masqué
*/
maskString: (text, visibleStart = 2, visibleEnd = 2, maskChar = "*") => {
if (text.length <= visibleStart + visibleEnd) {
return text;
}
const start = text.substring(0, visibleStart);
const end = text.substring(text.length - visibleEnd);
const middle = maskChar.repeat(text.length - visibleStart - visibleEnd);
return start + middle + end;
},
},
array: {
/**
* Compare deux tableaux pour vérifier s'ils sont identiques
* @param array1 - Premier tableau
* @param array2 - Second tableau
* @returns true si les tableaux sont identiques
*/
compare: function (array1, array2) {
if (array1.length !== array2.length) {
return false;
}
for (let i = 0; i < array1.length; i++) {
if (array1[i] !== array2[i]) {
return false;
}
}
return true;
},
/**
* Vérifie si une valeur existe dans un tableau
* @param needle - La valeur à rechercher
* @param haystack - Le tableau dans lequel chercher
* @returns true si la valeur est trouvée
*/
inArray: function (needle, haystack) {
let length = haystack.length;
for (let i = 0; i < length; i++) {
if (haystack[i] === needle)
return true;
}
return false;
},
/**
* Supprime les doublons d'un tableau
* @param array - Le tableau à dédupliquer
* @returns Un nouveau tableau sans doublons
*/
unique: function (array) {
return [...new Set(array)];
},
/**
* Mélange aléatoirement les éléments d'un tableau
* @param array - Le tableau à mélanger
* @returns Un nouveau tableau mélangé
*/
shuffle: function (array) {
const shuffled = [...array];
for (let i = shuffled.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
}
return shuffled;
},
/**
* Divise un tableau en chunks de taille spécifiée
* @param array - Le tableau à diviser
* @param size - Taille de chaque chunk
* @returns Un tableau de chunks
*/
chunk: function (array, size) {
const chunks = [];
for (let i = 0; i < array.length; i += size) {
chunks.push(array.slice(i, i + size));
}
return chunks;
},
/**
* Trouve l'intersection de deux tableaux
* @param array1 - Premier tableau
* @param array2 - Second tableau
* @returns Les éléments communs aux deux tableaux
*/
intersection: function (array1, array2) {
return array1.filter(value => array2.includes(value));
},
/**
* Trouve la différence entre deux tableaux
* @param array1 - Premier tableau
* @param array2 - Second tableau
* @returns Les éléments du premier tableau qui ne sont pas dans le second
*/
difference: function (array1, array2) {
return array1.filter(value => !array2.includes(value));
},
},
object: {
/**
* Clone profondément un objet
* @param obj - L'objet à cloner
* @returns Une copie profonde de l'objet
*/
deepClone: function (obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
if (obj instanceof Date) {
return new Date(obj.getTime());
}
if (obj instanceof Array) {
return obj.map(item => this.deepClone(item));
}
if (typeof obj === 'object') {
const cloned = {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
cloned[key] = this.deepClone(obj[key]);
}
}
return cloned;
}
},
/**
* Fusionne deux objets profondément
* @param target - L'objet cible
* @param source - L'objet source
* @returns L'objet fusionné
*/
deepMerge: function (target, source) {
const result = Object.assign({}, target);
for (const key in source) {
if (source.hasOwnProperty(key)) {
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
result[key] = this.deepMerge(result[key] || {}, source[key]);
}
else {
result[key] = source[key];
}
}
}
return result;
},
/**
* Obtient une valeur dans un objet par un chemin de propriétés
* @param obj - L'objet source
* @param path - Le chemin vers la propriété (ex: "user.profile.name")
* @param defaultValue - Valeur par défaut si la propriété n'existe pas
* @returns La valeur trouvée ou la valeur par défaut
*/
get: function (obj, path, defaultValue = undefined) {
const keys = path.split('.');
let result = obj;
for (const key of keys) {
if (result === null || result === undefined || !(key in result)) {
return defaultValue;
}
result = result[key];
}
return result;
},
/**
* Définit une valeur dans un objet par un chemin de propriétés
* @param obj - L'objet cible
* @param path - Le chemin vers la propriété (ex: "user.profile.name")
* @param value - La valeur à définir
* @returns L'objet modifié
*/
set: function (obj, path, value) {
const keys = path.split('.');
let current = obj;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
if (!(key in current) || typeof current[key] !== 'object') {
current[key] = {};
}
current = current[key];
}
current[keys[keys.length - 1]] = value;
return obj;
},
/**
* Supprime les propriétés avec des valeurs nulles ou undefined
* @param obj - L'objet à nettoyer
* @returns L'objet nettoyé
*/
removeNullish: function (obj) {
const cleaned = {};
for (const key in obj) {
if (obj.hasOwnProperty(key) && obj[key] !== null && obj[key] !== undefined) {
if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
cleaned[key] = this.removeNullish(obj[key]);
}
else {
cleaned[key] = obj[key];
}
}
}
return cleaned;
},
},
number: {
/**
* Formate un nombre avec des séparateurs de milliers
* @param num - Le nombre à formater
* @param locale - La locale à utiliser (défaut: 'fr-FR')
* @returns Le nombre formaté
*/
format: function (num, locale = 'fr-FR') {
return new Intl.NumberFormat(locale).format(num);
},
/**
* Formate un nombre en devise
* @param num - Le nombre à formater
* @param currency - La devise (défaut: 'EUR')
* @param locale - La locale à utiliser (défaut: 'fr-FR')
* @returns Le nombre formaté en devise
*/
formatCurrency: function (num, currency = 'EUR', locale = 'fr-FR') {
return new Intl.NumberFormat(locale, {
style: 'currency',
currency: currency
}).format(num);
},
/**
* Génère un nombre aléatoire entre min et max (inclus)
* @param min - Valeur minimale
* @param max - Valeur maximale
* @returns Un nombre aléatoire
*/
random: function (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
},
/**
* Arrondit un nombre à un nombre spécifié de décimales
* @param num - Le nombre à arrondir
* @param decimals - Nombre de décimales (défaut: 2)
* @returns Le nombre arrondi
*/
round: function (num, decimals = 2) {
return Math.round(num * Math.pow(10, decimals)) / Math.pow(10, decimals);
},
/**
* Convertit des octets en format lisible (KB, MB, GB, etc.)
* @param bytes - Nombre d'octets
* @param decimals - Nombre de décimales (défaut: 2)
* @returns La taille formatée
*/
formatBytes: function (bytes, decimals = 2) {
if (bytes === 0)
return '0 Bytes';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
},
/**
* Calcule le pourcentage d'une valeur par rapport à un total
* @param value - La valeur
* @param total - Le total
* @param decimals - Nombre de décimales (défaut: 2)
* @returns Le pourcentage
*/
percentage: function (value, total, decimals = 2) {
if (total === 0)
return 0;
return this.round((value / total) * 100, decimals);
},
},
url: {
/**
* Vérifie si une chaîne est une URL valide
* @param url - L'URL à vérifier
* @returns true si l'URL est valide
*/
isValid: function (url) {
try {
new URL(url);
return true;
}
catch (_a) {
return false;
}
},
/**
* Extrait le domaine d'une URL
* @param url - L'URL source
* @returns Le domaine ou null si invalide
*/
getDomain: function (url) {
try {
return new URL(url).hostname;
}
catch (_a) {
return null;
}
},
/**
* Construit une URL avec des paramètres de requête
* @param baseUrl - L'URL de base
* @param params - Les paramètres à ajouter
* @returns L'URL complète avec paramètres
*/
buildWithParams: function (baseUrl, params) {
const url = new URL(baseUrl);
Object.keys(params).forEach(key => {
if (params[key] !== null && params[key] !== undefined) {
url.searchParams.set(key, params[key].toString());
}
});
return url.toString();
},
/**
* Parse les paramètres de requête d'une URL
* @param url - L'URL à parser
* @returns Un objet avec les paramètres
*/
parseParams: function (url) {
try {
const urlObj = new URL(url);
const params = {};
urlObj.searchParams.forEach((value, key) => {
params[key] = value;
});
return params;
}
catch (_a) {
return {};
}
},
},
validation: {
/**
* Vérifie si une valeur est un JSON valide
* @param str - La chaîne à vérifier
* @returns true si c'est un JSON valide
*/
isValidJSON: function (str) {
try {
JSON.parse(str);
return true;
}
catch (_a) {
return false;
}
},
/**
* Vérifie la force d'un mot de passe
* @param password - Le mot de passe à vérifier
* @returns Un objet avec le score et les détails
*/
passwordStrength: function (password) {
let score = 0;
const feedback = [];
// Longueur
if (password.length >= 8)
score += 1;
else
feedback.push('Au moins 8 caractères');
if (password.length >= 12)
score += 1;
// Minuscules
if (/[a-z]/.test(password))
score += 1;
else
feedback.push('Au moins une minuscule');
// Majuscules
if (/[A-Z]/.test(password))
score += 1;
else
feedback.push('Au moins une majuscule');
// Chiffres
if (/\d/.test(password))
score += 1;
else
feedback.push('Au moins un chiffre');
// Caractères spéciaux
if (/[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/.test(password))
score += 1;
else
feedback.push('Au moins un caractère spécial');
let strength = 'Très faible';
if (score >= 2)
strength = 'Faible';
if (score >= 4)
strength = 'Moyen';
if (score >= 5)
strength = 'Fort';
if (score >= 6)
strength = 'Très fort';
return { score, strength, feedback };
},
/**
* Vérifie si une chaîne contient uniquement des caractères alphanumériques
* @param str - La chaîne à vérifier
* @returns true si alphanumérique uniquement
*/
isAlphanumeric: function (str) {
return /^[a-zA-Z0-9]+$/.test(str);
},
/**
* Vérifie si une chaîne est un code postal français valide
* @param postalCode - Le code postal à vérifier
* @returns true si valide
*/
isFrenchPostalCode: function (postalCode) {
return /^[0-9]{5}$/.test(postalCode);
},
/**
* Vérifie si une chaîne est un numéro SIRET français valide
* @param siret - Le numéro SIRET à vérifier
* @returns true si valide
*/
isSIRET: function (siret) {
if (!/^\d{14}$/.test(siret))
return false;
// Algorithme de validation SIRET
let sum = 0;
for (let i = 0; i < 14; i++) {
let digit = parseInt(siret[i]);
if (i % 2 === 1) {
digit *= 2;
if (digit > 9)
digit -= 9;
}
sum += digit;
}
return sum % 10 === 0;
},
/**
* Vérifie si une chaîne est un IBAN valide
* @param iban - L'IBAN à vérifier
* @returns true si valide
*/
isIBAN: function (iban) {
// Supprime les espaces et met en majuscules
const cleanIban = iban.replace(/\s/g, '').toUpperCase();
// Vérifie le format de base
if (!/^[A-Z]{2}[0-9]{2}[A-Z0-9]+$/.test(cleanIban))
return false;
// Réorganise l'IBAN pour la validation
const rearranged = cleanIban.slice(4) + cleanIban.slice(0, 4);
// Convertit les lettres en nombres
const numericString = rearranged.replace(/[A-Z]/g, (char) => (char.charCodeAt(0) - 55).toString());
// Calcule le modulo 97
let remainder = 0;
for (let i = 0; i < numericString.length; i++) {
remainder = (remainder * 10 + parseInt(numericString[i])) % 97;
}
return remainder === 1;
},
},
/**
* Construit un objet d'erreur API standardisé
* @param payload - Les données d'erreur
* @returns L'objet d'erreur formaté
*/
buildApiError: (payload) => {
let error = {
errors: {
value: coddyger.string.isEmpty(payload.value) ? "" : payload.value,
msg: payload.msg,
param: coddyger.string.isEmpty(payload.param) ? "" : payload.param,
location: coddyger.string.isEmpty(payload.location)
? ""
: payload.location,
},
};
return error;
},
/**
* Obtient la date courante ou la formate
* @param type - 'string' pour format chaîne, sinon objet Date
* @returns La date formatée
*/
getDate: (type = "") => {
var d = new Date(), month = "" + (d.getMonth() + 1), day = "" + d.getDate(), year = d.getFullYear();
if (month.length < 2)
month = "0" + month;
if (day.length < 2)
day = "0" + day;
return type === "string"
? [year, month, day].join("-")
: new Date([year, month, day].join("-"));
},
file: {
/**
* Supprime un fichier
* @param filePath - Chemin du fichier à supprimer
*/
remove: function (filePath) {
return fs.unlinkSync(filePath);
},
/**
* Récupère l'extension d'un fichier
* @param filename - Nom du fichier
* @returns L'extension en minuscules
*/
extension: function (filename) {
return path.extname(filename).toLowerCase();
},
/**
* Convertit un fichier en Base64
* @param filename - Nom du fichier
* @returns Le contenu du fichier en Base64
*/
toBase64: (filename) => {
return fs.readFileSync(filename, { encoding: "base64" });
},
/**
* Vérifie si un fichier existe
* @param filePath - Chemin du fichier
* @returns true si le fichier existe
*/
exists: (filePath) => {
return fs.existsSync(filePath);
},
/**
* Télécharge un fichier depuis une URL
* @param url - URL du fichier
* @param filename - Nom du fichier de destination
* @returns Une promesse résolue quand le téléchargement est terminé
*/
download: (url, filename) => {
return new Promise((resolve, reject) => {
let file = fs.createWriteStream(coddyger.root() + process.env.DOWNLOAD_PATH + "/" + filename);
http.get(url, function (response) {
response.pipe(file);
file.on("finish", function () {
resolve(file);
file.close();
});
});
}).catch((e) => {
return { error: true, data: e, messsage: "" };
});
},
},
/**
* Calcule le nombre de jours entre une date et aujourd'hui
* @param startDate - Date de début
* @returns Nombre de jours écoulés
*/
calculateDaysBetween(startDate) {
const startDateObj = startDate;
const currentDateObj = new Date();
// Calculate the time difference in milliseconds
const timeDifference = currentDateObj.getTime() - startDateObj.getTime();
// Convert milliseconds to days
const daysDifference = Math.floor(timeDifference / (1000 * 60 * 60 * 24));
return daysDifference;
},
/**
* Génère un slug unique avec préfixe et date
* @param prefix - Préfixe du slug
* @param lastReference - Dernière référence utilisée
* @returns Le nouveau slug généré
*/
buildSlug(prefix, lastReference) {
let newIndex = 1;
if (lastReference) {
const lastCodeParts = lastReference.split("-");
const lastCodeIndex = parseInt(lastCodeParts[lastCodeParts.length - 1], 10);
if (!isNaN(lastCodeIndex)) {
newIndex = lastCodeIndex + 1;
}
else {
throw new Error("Invalid reference format. Cannot extract index.");
}
}
const currentDate = new Date();
const year = currentDate.getFullYear().toString().slice(-2);
const month = ("0" + (currentDate.getMonth() + 1)).slice(-2);
const day = ("0" + currentDate.getDate()).slice(-2);
const newIndexStr = ("000" + newIndex).slice(-3);
let uniq = new mongoose_1.default.Types.ObjectId();
uniq = uniq.toString();
uniq = uniq.substring(uniq.length - 12);
const code = `${prefix}-${year}${month}${day}-${uniq}-${newIndexStr}`;
return code;
},
/**
* Obtient le nombre de jours dans un mois donné
* @param month - Numéro du mois (1-12)
* @param year - Année
* @returns Nombre de jours dans le mois
*/
getDaysInMonth: (month, year) => {
// Validate the month number (1-12)
if (month < 1 || month > 12) {
throw new Error("Invalid month number. Month number should be between 1 and 12.");
}
const date = new Date(year, month - 1, 1); // On utilise month - 1 car les mois commencent à partir de 0 dans JavaScript
const days = [];
while (date.getMonth() === month - 1) {
const day = date.getDate();
days.push(day);
date.setDate(day + 1);
}
return days;
},
/**
* Obtient les semaines d'un mois donné
* @param month - Numéro du mois (1-12)
* @param year - Année
* @returns Tableau des semaines avec leurs dates de début et fin
*/
getWeeksInMonth: (month, year) => {
const weeks = [];
const firstDay = new Date(year, month - 1, 1);
const lastDay = new Date(year, month, 0);
const daysInMonth = lastDay.getDate();
// Initialiser les variables pour suivre le début et la fin d'une semaine
let start = 1;
let dayOfWeek = firstDay.getDay();
// Si le premier jour du mois n'est pas un lundi, ajuster le début de la première semaine
if (dayOfWeek !== 1) {
start = 1;
}
for (let i = 1; i <= daysInMonth; i++) {
dayOfWeek = new Date(year, month - 1, i).getDay();
// Si le jour est un dimanche (dernier jour de la semaine) ou le dernier jour du mois, c'est la fin de la semaine
if (dayOfWeek === 0 || i === daysInMonth) {
const end = i;
// Ajouter la semaine au tableau
weeks.push({ start, end });
// Le début de la nouvelle semaine est le jour suivant
start = i + 1;
}
}
return weeks;
},
/**
* Formate une date en format YYYY-MM-DD
* @param date - La date à formater
* @returns La date formatée en chaîne YYYY-MM-DD
*/
dateOnlyFormat: (date) => {
const dateObj = typeof date === 'string' ? new Date(date) : date;
return (0, date_fns_1.format)(dateObj, 'yyyy-MM-dd');
},
dates: {
/**
* Formate une date selon un format spécifique
* @param date - La date à formater
* @param formatStr - Le format désiré (ex: 'dd/MM/yyyy')
* @param locale - La locale à utiliser (par défaut: fr)
* @returns La date formatée selon le format spécifié
*/
format: (date, formatStr = 'dd/MM/yyyy', locale = locale_1.fr) => {
const dateObj = typeof date === 'string' ? (0, date_fns_1.parseISO)(date) : date;
return (0, date_fns_1.format)(dateObj, formatStr, { locale });
},
/**
* Vérifie si une date est valide
* @param date - La date à vérifier
* @returns true si la date est valide
*/
isValid: (date) => {
const dateObj = typeof date === 'string' ? (0, date_fns_1.parseISO)(date) : date;
return (0, date_fns_1.isValid)(dateObj);
},
/**
* Ajoute un nombre de jours à une date
* @param date - La date de départ
* @param days - Nombre de jours à ajouter
* @returns La nouvelle date
*/
addDays: (date, days) => {
const dateObj = typeof date === 'string' ? (0, date_fns_1.parseISO)(date) : date;
return (0, date_fns_1.addDays)(dateObj, days);
},
/**
* Soustrait un nombre de jours d'une date
* @param date - La date de départ
* @param days - Nombre de jours à soustraire
* @returns La nouvelle date
*/
subDays: (date, days) => {
const dateObj = typeof date === 'string' ? (0, date_fns_1.parseISO)(date) : date;
return (0, date_fns_1.subDays)(dateObj, days);
},
/**
* Calcule la différence en jours entre deux dates
* @param dateLeft - Première date
* @param dateRight - Deuxième date
* @returns Nombre de jours de différence
*/
diffInDays: (dateLeft, dateRight) => {
const dateLeftObj = typeof dateLeft === 'string' ? (0, date_fns_1.parseISO)(dateLeft) : dateLeft;
const dateRightObj = typeof dateRight === 'string' ? (0, date_fns_1.parseISO)(dateRight) : dateRight;
return (0, date_fns_1.differenceInDays)(dateLeftObj, dateRightObj);
},
/**
* Obtient le début de la semaine pour une date donnée
* @param date - La date
* @returns Date du début de la semaine
*/
startOfWeek: (date) => {
const dateObj = typeof date === 'string' ? (0, date_fns_1.parseISO)(date) : date;
return (0, date_fns_1.startOfWeek)(dateObj, { locale: locale_1.fr });
},
/**
* Obtient la fin de la semaine pour une date donnée
* @param date - La date
* @returns Date de fin de la semaine
*/
endOfWeek: (date) => {
const dateObj = typeof date === 'string' ? (0, date_fns_1.parseISO)(date) : date;
return (0, date_fns_1.endOfWeek)(dateObj, { locale: locale_1.fr });
},
/**
* Obtient le début du mois pour une date donnée
* @param date - La date
* @returns Date du début du mois
*/
startOfMonth: (date) => {
const dateObj = typeof date === 'string' ? (0, date_fns_1.parseISO)(date) : date;
return (0, date_fns_1.startOfMonth)(dateObj);
},
/**
* Obtient la fin du mois pour une date donnée
* @param date - La date
* @returns Date de fin du mois
*/
endOfMonth: (date) => {
const dateObj = typeof date === 'string' ? (0, date_fns_1.parseISO)(date) : date;
return (0, date_fns_1.endOfMonth)(dateObj);
},
/**
* Vérifie si une date est dans un intervalle
* @param date - La date à vérifier
* @param startDate - Date de début de l'intervalle
* @param endDate - Date de fin de l'intervalle
* @returns true si la date est dans l'intervalle
*/
isWithinInterval: (date, startDate, endDate) => {
const dateObj = typeof date === 'string' ? (0, date_fns_1.parseISO)(date) : date;
const start = typeof startDate === 'string' ? (0, date_fns_1.parseISO)(startDate) : startDate;
const end = typeof endDate === 'string' ? (0, date_fns_1.parseISO)(endDate) : endDate;
return (0, date_fns_1.isWithinInterval)(dateObj, { start, end });
},
/**
* Obtient le nombre de jours dans un mois donné
* @param month - Numéro du mois (1-12)
* @param year - Année
* @returns Nombre de jours dans le mois
*/
getDaysInMonthCount: (month, year) => {
// Valider le numéro du mois (1-12)
if (month < 1 || month > 12) {
throw new Error('Le numéro du mois doit être compris entre 1 et 12');
}
// Le jour 0 du mois suivant nous donne le dernier jour du mois actuel
return new Date(year, month, 0).getDate();
},
},
/**
* Retourne le chemin absolu du répertoire racine de l'application
* @returns Le chemin absolu de la racine du projet
*/
root: () => {
return path.resolve(process.cwd());
},
/**
* Inclut rcursivement les fichiers d'un répertoire selon une extension
* @param dir - Le répertoire à scanner
* @param payload - L'extension des fichiers à inclure (sans le point)
* @returns Un tableau des classes exportées depuis les fichiers
*/
filesInclude(dir, payload) {
const exportedFiles = [];
const files = fs.readdirSync(dir);
for (const file of files) {
// Exclure le fichier index.ts lui-même
if (file !== 'index.js' && file.endsWith('.' + payload + '.js')) {
const routeModule = require(path.join(dir, file));
for (const moduleExport of Object.values(routeModule)) {
// Vérifiez si c'est une classe (vous pouvez ajouter des vérifications supplémentaires si nécessaire)
if (typeof moduleExport === 'function') {
exportedFiles.push(moduleExport);
}
}
}
}
// Exportez toutes les classes de route découvertes
return exportedFiles;
},
/**
* Gère les retours d'erreur de manière standardisée
* @param e - L'erreur à traiter
* @param location - L'emplacement où l'erreur s'est produite
* @param method - La méthode où l'erreur s'est produite
* @returns Un objet d'erreur formaté
*/
catchReturn(e, location, method) {
// Log any errors that occur during the process
services_1.LoggerService.log({ type: services_1.LogLevel.Error, content: JSON.stringify(e), location, method });
// Return a predefined error object for the catch block
if (globals_1.default.mode === 'dev') {
return {
status: globals_1.defines.status.serverError,
message: globals_1.defines.message.tryCatch,
data: e
};
}
else {
return globals_1.defines.controlerTryCatchObject;
}
},
};
exports.default = coddyger;