• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

inclusion-numerique / coop-mediation-numerique / d042ddf5-824b-4a46-8c8f-8237a8853f64

25 Mar 2026 10:41AM UTC coverage: 10.692% (+3.8%) from 6.896%
d042ddf5-824b-4a46-8c8f-8237a8853f64

push

circleci

web-flow
Merge pull request #465 from inclusion-numerique/fix/brevo-shared-contacts

fix(brevo): handle shared Brevo account with Les Bases

699 of 10508 branches covered (6.65%)

Branch coverage included in aggregate %.

18 of 122 new or added lines in 13 files covered. (14.75%)

814 existing lines in 86 files now uncovered.

2168 of 16307 relevant lines covered (13.29%)

2.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/apps/web/src/utils/changeObjectKeysCaseRecursive.ts
1
import { camelCase, constantCase, pascalCase, snakeCase } from 'change-case'
2

3
type CaseType = 'snake' | 'camel' | 'constant' | 'pascal'
4

5
// exemple minimaliste de snake_case
6
type SnakeCase<S extends string> =
7
  // on coupe la chaîne caractère par caractère
8
  S extends `${infer First}${infer Rest}`
9
    ? // si le prochain caractère n'est pas en majuscule, on colle
10
      // sinon on insère un underscore
11
      Rest extends Uncapitalize<Rest>
12
      ? `${Lowercase<First>}${SnakeCase<Rest>}`
13
      : `${Lowercase<First>}_${SnakeCase<Rest>}`
14
    : S
15

16
// camelCase depuis snake_case (vraiment simplifié)
17
type CamelCase<S extends string> = S extends `${infer Before}_${infer After}`
18
  ? `${Lowercase<Before>}${Capitalize<CamelCase<After>>}`
19
  : Lowercase<S>
20

21
// PASCALcase (simplifié)
22
// (on part d'une base camelCase et on capitalise le premier)
23
type PascalCase<S extends string> = S extends `${infer First}${infer Rest}`
24
  ? `${Uppercase<First>}${Rest}`
25
  : S
26

27
// CONSTANT_CASE (tout majuscule, underscore)
28
type ConstantCase<S extends string> =
29
  SnakeCase<S> extends infer R extends string ? Uppercase<R> : never
30

31
// on choisit la transformation
32
type ChangeCase<S extends string, C extends CaseType> = C extends 'snake'
33
  ? SnakeCase<S>
34
  : C extends 'camel'
35
    ? CamelCase<S>
36
    : C extends 'pascal'
37
      ? PascalCase<CamelCase<S>> // on “nettoie” la chaîne avant
38
      : C extends 'constant'
39
        ? ConstantCase<S>
40
        : S
41

42
// le type récursif sur les clés d’un objet
43
export type ChangeObjectKeysCaseRecursive<
44
  T,
45
  C extends CaseType,
46
> = T extends readonly any[] // si c’est un tableau, on applique récursivement à ses éléments
47
  ? { [K in keyof T]: ChangeObjectKeysCaseRecursive<T[K], C> }
48
  : // si c’est un objet "pur" (pas un tableau), on renomme les clés
49
    T extends object
50
    ? {
51
        [K in keyof T as ChangeCase<
52
          Extract<K, string>,
53
          C
54
        >]: ChangeObjectKeysCaseRecursive<T[K], C>
55
      }
56
    : T
UNCOV
57
const changeCaseFunctions = {
×
58
  snake: snakeCase,
59
  camel: camelCase,
60
  constant: constantCase,
61
  pascal: pascalCase,
62
} satisfies Record<CaseType, (input: string) => string>
63

UNCOV
64
export const changeObjectKeysCaseRecursive = <T, C extends CaseType>(
×
65
  data: T,
66
  caseType: C,
67
): ChangeObjectKeysCaseRecursive<T, C> => {
UNCOV
68
  const changeCase = changeCaseFunctions[caseType]
×
69

UNCOV
70
  if (Array.isArray(data)) {
×
UNCOV
71
    return data.map(
×
72
      (item) =>
UNCOV
73
        changeObjectKeysCaseRecursive(
×
74
          item,
75
          caseType,
76
        ) as ChangeObjectKeysCaseRecursive<T, C>,
77
    ) as ChangeObjectKeysCaseRecursive<T, C>
78
  }
79

UNCOV
80
  if (data && typeof data === 'object' && data !== null) {
×
UNCOV
81
    return Object.fromEntries(
×
UNCOV
82
      Object.entries(data).map(([key, value]) => [
×
83
        changeCase(key),
84
        changeObjectKeysCaseRecursive(value, caseType),
85
      ]),
86
    ) as ChangeObjectKeysCaseRecursive<T, C>
87
  }
88

UNCOV
89
  return data as ChangeObjectKeysCaseRecursive<T, C>
×
90
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc