@starterlib/util 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # Util
2
+
3
+ This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 22.1.0.
4
+
5
+ ## Code scaffolding
6
+
7
+ Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
8
+
9
+ ```bash
10
+ ng generate component component-name
11
+ ```
12
+
13
+ For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
14
+
15
+ ```bash
16
+ ng generate --help
17
+ ```
18
+
19
+ ## Building
20
+
21
+ To build the library, run:
22
+
23
+ ```bash
24
+ ng build util
25
+ ```
26
+
27
+ This command will compile your project, and the build artifacts will be placed in the `dist/` directory.
28
+
29
+ ### Publishing the Library
30
+
31
+ Once the project is built, you can publish your library by following these steps:
32
+
33
+ 1. Navigate to the `dist` directory:
34
+
35
+ ```bash
36
+ cd dist/util
37
+ ```
38
+
39
+ 2. Run the `npm publish` command to publish your library to the npm registry:
40
+ ```bash
41
+ npm publish
42
+ ```
43
+
44
+ ## Running unit tests
45
+
46
+ To execute unit tests with the [Vitest](https://vitest.dev/) test runner, use the following command:
47
+
48
+ ```bash
49
+ ng test
50
+ ```
51
+
52
+ ## Running end-to-end tests
53
+
54
+ For end-to-end (e2e) testing, run:
55
+
56
+ ```bash
57
+ ng e2e
58
+ ```
59
+
60
+ Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
61
+
62
+ ## Additional Resources
63
+
64
+ For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Formatage monetaire. Il vit dans le socle et non dans chaque SPA parce
3
+ * qu'une somme mal arrondie ou mal signee est un defaut bancaire, pas un
4
+ * defaut d'affichage.
5
+ */
6
+ /** Devises a zero decimale : le yen n'a pas de centime. */
7
+ const SANS_DECIMALE = new Set(['JPY', 'KRW', 'VND', 'XAF', 'XOF', 'CLP', 'ISK']);
8
+ /** Devises a trois decimales. */
9
+ const TROIS_DECIMALES = new Set(['BHD', 'IQD', 'JOD', 'KWD', 'LYD', 'OMR', 'TND']);
10
+ function decimalesDe(devise) {
11
+ const code = devise.toUpperCase();
12
+ if (SANS_DECIMALE.has(code))
13
+ return 0;
14
+ if (TROIS_DECIMALES.has(code))
15
+ return 3;
16
+ return 2;
17
+ }
18
+ function montant(unitesMineures, devise) {
19
+ if (!/^[A-Za-z]{3}$/.test(devise)) {
20
+ throw new Error(`Code devise invalide : ${devise}`);
21
+ }
22
+ if (typeof unitesMineures === 'number' && !Number.isInteger(unitesMineures)) {
23
+ throw new Error(`Un montant se compte en unites mineures entieres, recu : ${String(unitesMineures)}`);
24
+ }
25
+ return { unitesMineures: BigInt(unitesMineures), devise: devise.toUpperCase() };
26
+ }
27
+ /**
28
+ * Rend un montant dans la locale demandee. La conversion en nombre n'a lieu
29
+ * qu'a l'instant du rendu, sur une valeur bornee par la precision d'affichage :
30
+ * le calcul, lui, n'a jamais quitte l'entier.
31
+ */
32
+ function formaterMontant(valeur, options = {}) {
33
+ const { locale = 'fr-FR', signeExplicite = false, sansDevise = false } = options;
34
+ const decimales = decimalesDe(valeur.devise);
35
+ const negatif = valeur.unitesMineures < 0n;
36
+ const absolu = negatif ? -valeur.unitesMineures : valeur.unitesMineures;
37
+ const diviseur = 10n ** BigInt(decimales);
38
+ const entiere = absolu / diviseur;
39
+ const fraction = absolu % diviseur;
40
+ const formateur = new Intl.NumberFormat(locale, {
41
+ style: sansDevise ? 'decimal' : 'currency',
42
+ currency: valeur.devise,
43
+ minimumFractionDigits: decimales,
44
+ maximumFractionDigits: decimales,
45
+ signDisplay: 'never',
46
+ });
47
+ const nombre = decimales === 0
48
+ ? Number(entiere)
49
+ : Number(`${entiere.toString()}.${fraction.toString().padStart(decimales, '0')}`);
50
+ const rendu = formateur.format(nombre);
51
+ if (negatif)
52
+ return `−${rendu}`;
53
+ return signeExplicite && valeur.unitesMineures > 0n ? `+${rendu}` : rendu;
54
+ }
55
+
56
+ /**
57
+ * IBAN : validation par la cle ISO 7064 mod 97-10 et presentation par groupes
58
+ * de quatre. La validation vit ici pour qu'un champ de saisie refuse une
59
+ * frappe fautive sans aller-retour serveur ; elle ne remplace jamais le
60
+ * controle du backend.
61
+ */
62
+ const LONGUEURS = {
63
+ FR: 27,
64
+ DE: 22,
65
+ ES: 24,
66
+ IT: 27,
67
+ BE: 16,
68
+ PT: 25,
69
+ NL: 18,
70
+ LU: 20,
71
+ CH: 21,
72
+ GB: 22,
73
+ IE: 22,
74
+ AT: 20,
75
+ PL: 28,
76
+ SE: 24,
77
+ NO: 15,
78
+ DK: 18,
79
+ FI: 18,
80
+ CZ: 24,
81
+ GR: 27,
82
+ RO: 24,
83
+ BG: 22,
84
+ HR: 21,
85
+ HU: 28,
86
+ SK: 24,
87
+ SI: 19,
88
+ LT: 20,
89
+ LV: 21,
90
+ EE: 20,
91
+ MT: 31,
92
+ CY: 28,
93
+ MC: 27,
94
+ SM: 27,
95
+ };
96
+ function normaliserIban(saisie) {
97
+ return saisie.replace(/[\s-]/g, '').toUpperCase();
98
+ }
99
+ /** Modulo 97 sur la chaine, chiffre par chiffre : un IBAN depasse la
100
+ * precision d'un nombre JavaScript. */
101
+ function mod97(chaine) {
102
+ let reste = 0;
103
+ for (const caractere of chaine) {
104
+ reste = (reste * 10 + Number(caractere)) % 97;
105
+ }
106
+ return reste;
107
+ }
108
+ function ibanEstValide(saisie) {
109
+ const iban = normaliserIban(saisie);
110
+ if (!/^[A-Z]{2}[0-9]{2}[A-Z0-9]{10,30}$/.test(iban))
111
+ return false;
112
+ const pays = iban.slice(0, 2);
113
+ const longueurAttendue = LONGUEURS[pays];
114
+ if (longueurAttendue !== undefined && iban.length !== longueurAttendue)
115
+ return false;
116
+ const permute = iban.slice(4) + iban.slice(0, 4);
117
+ const numerique = permute.replace(/[A-Z]/g, (l) => (l.charCodeAt(0) - 55).toString());
118
+ return mod97(numerique) === 1;
119
+ }
120
+ /** Presentation par groupes de quatre, la seule lisible a l'oeil. */
121
+ function formaterIban(saisie) {
122
+ return normaliserIban(saisie)
123
+ .replace(/(.{4})/g, '$1 ')
124
+ .trim();
125
+ }
126
+ /**
127
+ * Masque tout sauf le pays et les quatre derniers caracteres. Un IBAN complet
128
+ * ne s'affiche jamais dans une liste : il suffit a initier un prelevement.
129
+ */
130
+ function masquerIban(saisie) {
131
+ const iban = normaliserIban(saisie);
132
+ if (iban.length < 8)
133
+ return '•'.repeat(iban.length);
134
+ const tete = iban.slice(0, 4);
135
+ const queue = iban.slice(-4);
136
+ return formaterIban(tete + '•'.repeat(iban.length - 8) + queue);
137
+ }
138
+
139
+ /**
140
+ * Masques d'affichage des identifiants sensibles.
141
+ *
142
+ * Regle commune : on garde de quoi RECONNAITRE, jamais de quoi UTILISER. Un
143
+ * numero complet affiche dans une liste suffit a initier une operation ; les
144
+ * quatre derniers caracteres suffisent a l'utilisateur pour savoir de quel
145
+ * moyen il s'agit.
146
+ */
147
+ /** Groupe par quatre, la seule presentation lisible a l'oeil. */
148
+ function grouperParQuatre(valeur) {
149
+ return valeur.replace(/(.{4})/g, '$1 ').trim();
150
+ }
151
+ function normaliserCarte(saisie) {
152
+ return saisie.replace(/[\s-]/g, '');
153
+ }
154
+ /**
155
+ * Ne laisse voir que les quatre derniers chiffres. Le reseau (les premiers
156
+ * chiffres) est volontairement masque : il identifie l'emetteur.
157
+ */
158
+ function masquerCarte(saisie) {
159
+ const carte = normaliserCarte(saisie);
160
+ if (carte.length <= 4)
161
+ return '•'.repeat(carte.length);
162
+ return grouperParQuatre('•'.repeat(carte.length - 4) + carte.slice(-4));
163
+ }
164
+ /**
165
+ * Validation de carte par la cle de Luhn. Elle sert a refuser une frappe
166
+ * fautive sans aller-retour serveur ; elle ne prouve rien sur l'existence du
167
+ * moyen de paiement.
168
+ */
169
+ function carteEstValide(saisie) {
170
+ const carte = normaliserCarte(saisie);
171
+ if (!/^[0-9]{12,19}$/.test(carte))
172
+ return false;
173
+ let somme = 0;
174
+ let double = false;
175
+ for (let index = carte.length - 1; index >= 0; index--) {
176
+ let chiffre = Number(carte[index]);
177
+ if (double) {
178
+ chiffre *= 2;
179
+ if (chiffre > 9)
180
+ chiffre -= 9;
181
+ }
182
+ somme += chiffre;
183
+ double = !double;
184
+ }
185
+ return somme % 10 === 0;
186
+ }
187
+ function normaliserTelephone(saisie) {
188
+ return saisie.replace(/[\s.\-()]/g, '');
189
+ }
190
+ /**
191
+ * Garde l'indicatif international et les deux derniers chiffres. Un numero
192
+ * entier permet d'usurper, de harceler, ou de tenter une prise de controle
193
+ * par message.
194
+ */
195
+ function masquerTelephone(saisie) {
196
+ const numero = normaliserTelephone(saisie);
197
+ const indicatif = numero.startsWith('+') ? numero.slice(0, 3) : '';
198
+ const reste = numero.slice(indicatif.length);
199
+ if (reste.length <= 2)
200
+ return indicatif + '•'.repeat(reste.length);
201
+ return `${indicatif}${'•'.repeat(reste.length - 2)}${reste.slice(-2)}`;
202
+ }
203
+ /**
204
+ * Fin lisible d'un identifiant, pour composer un nom accessible : une suite de
205
+ * puces est epelee caractere par caractere par plusieurs lecteurs d'ecran.
206
+ */
207
+ function quatreDerniers(saisie) {
208
+ const valeur = saisie.replace(/[\s-]/g, '');
209
+ return valeur.slice(-4);
210
+ }
211
+
212
+ /**
213
+ * @starterlib/util — fonctions pures partagees.
214
+ *
215
+ * Regle du paquet : aucune dependance Angular, aucun effet de bord, aucune
216
+ * lecture d'horloge ni de `window`. Tout ce qui vit ici doit se tester sans
217
+ * banc d'essai Angular.
218
+ */
219
+
220
+ /**
221
+ * Generated bundle index. Do not edit.
222
+ */
223
+
224
+ export { carteEstValide, decimalesDe, formaterIban, formaterMontant, ibanEstValide, masquerCarte, masquerIban, masquerTelephone, montant, normaliserCarte, normaliserIban, normaliserTelephone, quatreDerniers };
225
+ //# sourceMappingURL=starterlib-util.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"starterlib-util.mjs","sources":["../../../../packages/util/src/lib/montant.ts","../../../../packages/util/src/lib/iban.ts","../../../../packages/util/src/lib/masque.ts","../../../../packages/util/src/public-api.ts","../../../../packages/util/src/starterlib-util.ts"],"sourcesContent":["/**\n * Formatage monetaire. Il vit dans le socle et non dans chaque SPA parce\n * qu'une somme mal arrondie ou mal signee est un defaut bancaire, pas un\n * defaut d'affichage.\n */\n\n/**\n * Un montant ne se represente JAMAIS par un nombre a virgule flottante :\n * 0.1 + 0.2 ne fait pas 0.3. On transporte des unites mineures entieres\n * (centimes) et la devise qui leur donne leur echelle.\n */\nexport interface Montant {\n /** Unites mineures. 12,34 EUR s'ecrit 1234. */\n readonly unitesMineures: bigint;\n /** Code ISO 4217, trois lettres majuscules. */\n readonly devise: string;\n}\n\n/** Devises a zero decimale : le yen n'a pas de centime. */\nconst SANS_DECIMALE = new Set(['JPY', 'KRW', 'VND', 'XAF', 'XOF', 'CLP', 'ISK']);\n/** Devises a trois decimales. */\nconst TROIS_DECIMALES = new Set(['BHD', 'IQD', 'JOD', 'KWD', 'LYD', 'OMR', 'TND']);\n\nexport function decimalesDe(devise: string): number {\n const code = devise.toUpperCase();\n if (SANS_DECIMALE.has(code)) return 0;\n if (TROIS_DECIMALES.has(code)) return 3;\n return 2;\n}\n\nexport function montant(unitesMineures: bigint | number, devise: string): Montant {\n if (!/^[A-Za-z]{3}$/.test(devise)) {\n throw new Error(`Code devise invalide : ${devise}`);\n }\n if (typeof unitesMineures === 'number' && !Number.isInteger(unitesMineures)) {\n throw new Error(\n `Un montant se compte en unites mineures entieres, recu : ${String(unitesMineures)}`,\n );\n }\n return { unitesMineures: BigInt(unitesMineures), devise: devise.toUpperCase() };\n}\n\nexport interface OptionsDeFormatage {\n readonly locale?: string;\n /** Affiche `+` devant un montant positif. Utile sur un releve. */\n readonly signeExplicite?: boolean;\n /** Masque le symbole de devise (colonnes de tableau deja titrees). */\n readonly sansDevise?: boolean;\n}\n\n/**\n * Rend un montant dans la locale demandee. La conversion en nombre n'a lieu\n * qu'a l'instant du rendu, sur une valeur bornee par la precision d'affichage :\n * le calcul, lui, n'a jamais quitte l'entier.\n */\nexport function formaterMontant(valeur: Montant, options: OptionsDeFormatage = {}): string {\n const { locale = 'fr-FR', signeExplicite = false, sansDevise = false } = options;\n const decimales = decimalesDe(valeur.devise);\n const negatif = valeur.unitesMineures < 0n;\n const absolu = negatif ? -valeur.unitesMineures : valeur.unitesMineures;\n const diviseur = 10n ** BigInt(decimales);\n const entiere = absolu / diviseur;\n const fraction = absolu % diviseur;\n\n const formateur = new Intl.NumberFormat(locale, {\n style: sansDevise ? 'decimal' : 'currency',\n currency: valeur.devise,\n minimumFractionDigits: decimales,\n maximumFractionDigits: decimales,\n signDisplay: 'never',\n });\n\n const nombre =\n decimales === 0\n ? Number(entiere)\n : Number(`${entiere.toString()}.${fraction.toString().padStart(decimales, '0')}`);\n\n const rendu = formateur.format(nombre);\n if (negatif) return `−${rendu}`;\n return signeExplicite && valeur.unitesMineures > 0n ? `+${rendu}` : rendu;\n}\n","/**\n * IBAN : validation par la cle ISO 7064 mod 97-10 et presentation par groupes\n * de quatre. La validation vit ici pour qu'un champ de saisie refuse une\n * frappe fautive sans aller-retour serveur ; elle ne remplace jamais le\n * controle du backend.\n */\n\nconst LONGUEURS: Readonly<Record<string, number>> = {\n FR: 27,\n DE: 22,\n ES: 24,\n IT: 27,\n BE: 16,\n PT: 25,\n NL: 18,\n LU: 20,\n CH: 21,\n GB: 22,\n IE: 22,\n AT: 20,\n PL: 28,\n SE: 24,\n NO: 15,\n DK: 18,\n FI: 18,\n CZ: 24,\n GR: 27,\n RO: 24,\n BG: 22,\n HR: 21,\n HU: 28,\n SK: 24,\n SI: 19,\n LT: 20,\n LV: 21,\n EE: 20,\n MT: 31,\n CY: 28,\n MC: 27,\n SM: 27,\n};\n\nexport function normaliserIban(saisie: string): string {\n return saisie.replace(/[\\s-]/g, '').toUpperCase();\n}\n\n/** Modulo 97 sur la chaine, chiffre par chiffre : un IBAN depasse la\n * precision d'un nombre JavaScript. */\nfunction mod97(chaine: string): number {\n let reste = 0;\n for (const caractere of chaine) {\n reste = (reste * 10 + Number(caractere)) % 97;\n }\n return reste;\n}\n\nexport function ibanEstValide(saisie: string): boolean {\n const iban = normaliserIban(saisie);\n if (!/^[A-Z]{2}[0-9]{2}[A-Z0-9]{10,30}$/.test(iban)) return false;\n\n const pays = iban.slice(0, 2);\n const longueurAttendue = LONGUEURS[pays];\n if (longueurAttendue !== undefined && iban.length !== longueurAttendue) return false;\n\n const permute = iban.slice(4) + iban.slice(0, 4);\n const numerique = permute.replace(/[A-Z]/g, (l) => (l.charCodeAt(0) - 55).toString());\n return mod97(numerique) === 1;\n}\n\n/** Presentation par groupes de quatre, la seule lisible a l'oeil. */\nexport function formaterIban(saisie: string): string {\n return normaliserIban(saisie)\n .replace(/(.{4})/g, '$1 ')\n .trim();\n}\n\n/**\n * Masque tout sauf le pays et les quatre derniers caracteres. Un IBAN complet\n * ne s'affiche jamais dans une liste : il suffit a initier un prelevement.\n */\nexport function masquerIban(saisie: string): string {\n const iban = normaliserIban(saisie);\n if (iban.length < 8) return '•'.repeat(iban.length);\n const tete = iban.slice(0, 4);\n const queue = iban.slice(-4);\n return formaterIban(tete + '•'.repeat(iban.length - 8) + queue);\n}\n","/**\n * Masques d'affichage des identifiants sensibles.\n *\n * Regle commune : on garde de quoi RECONNAITRE, jamais de quoi UTILISER. Un\n * numero complet affiche dans une liste suffit a initier une operation ; les\n * quatre derniers caracteres suffisent a l'utilisateur pour savoir de quel\n * moyen il s'agit.\n */\n\n/** Groupe par quatre, la seule presentation lisible a l'oeil. */\nfunction grouperParQuatre(valeur: string): string {\n return valeur.replace(/(.{4})/g, '$1 ').trim();\n}\n\nexport function normaliserCarte(saisie: string): string {\n return saisie.replace(/[\\s-]/g, '');\n}\n\n/**\n * Ne laisse voir que les quatre derniers chiffres. Le reseau (les premiers\n * chiffres) est volontairement masque : il identifie l'emetteur.\n */\nexport function masquerCarte(saisie: string): string {\n const carte = normaliserCarte(saisie);\n if (carte.length <= 4) return '•'.repeat(carte.length);\n return grouperParQuatre('•'.repeat(carte.length - 4) + carte.slice(-4));\n}\n\n/**\n * Validation de carte par la cle de Luhn. Elle sert a refuser une frappe\n * fautive sans aller-retour serveur ; elle ne prouve rien sur l'existence du\n * moyen de paiement.\n */\nexport function carteEstValide(saisie: string): boolean {\n const carte = normaliserCarte(saisie);\n if (!/^[0-9]{12,19}$/.test(carte)) return false;\n\n let somme = 0;\n let double = false;\n for (let index = carte.length - 1; index >= 0; index--) {\n let chiffre = Number(carte[index]);\n if (double) {\n chiffre *= 2;\n if (chiffre > 9) chiffre -= 9;\n }\n somme += chiffre;\n double = !double;\n }\n return somme % 10 === 0;\n}\n\nexport function normaliserTelephone(saisie: string): string {\n return saisie.replace(/[\\s.\\-()]/g, '');\n}\n\n/**\n * Garde l'indicatif international et les deux derniers chiffres. Un numero\n * entier permet d'usurper, de harceler, ou de tenter une prise de controle\n * par message.\n */\nexport function masquerTelephone(saisie: string): string {\n const numero = normaliserTelephone(saisie);\n const indicatif = numero.startsWith('+') ? numero.slice(0, 3) : '';\n const reste = numero.slice(indicatif.length);\n if (reste.length <= 2) return indicatif + '•'.repeat(reste.length);\n return `${indicatif}${'•'.repeat(reste.length - 2)}${reste.slice(-2)}`;\n}\n\n/**\n * Fin lisible d'un identifiant, pour composer un nom accessible : une suite de\n * puces est epelee caractere par caractere par plusieurs lecteurs d'ecran.\n */\nexport function quatreDerniers(saisie: string): string {\n const valeur = saisie.replace(/[\\s-]/g, '');\n return valeur.slice(-4);\n}\n","/**\n * @starterlib/util — fonctions pures partagees.\n *\n * Regle du paquet : aucune dependance Angular, aucun effet de bord, aucune\n * lecture d'horloge ni de `window`. Tout ce qui vit ici doit se tester sans\n * banc d'essai Angular.\n */\nexport * from './lib/montant';\nexport * from './lib/iban';\nexport * from './lib/masque';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@starterlib/util",
3
+ "version": "0.1.0",
4
+ "description": "Fonctions pures du socle frontal starter : montants en unites mineures, IBAN, formatage. Aucune dependance Angular.",
5
+ "license": "UNLICENSED",
6
+ "sideEffects": false,
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/Arnoldkom/starter-web-platform.git",
13
+ "directory": "packages/util"
14
+ },
15
+ "homepage": "https://github.com/Arnoldkom/starter-web-platform/tree/main/packages/util#readme",
16
+ "keywords": [
17
+ "starter",
18
+ "socle-frontal",
19
+ "util"
20
+ ],
21
+ "module": "fesm2022/starterlib-util.mjs",
22
+ "typings": "types/starterlib-util.d.ts",
23
+ "exports": {
24
+ "./package.json": {
25
+ "default": "./package.json"
26
+ },
27
+ ".": {
28
+ "types": "./types/starterlib-util.d.ts",
29
+ "default": "./fesm2022/starterlib-util.mjs"
30
+ }
31
+ },
32
+ "type": "module",
33
+ "dependencies": {
34
+ "tslib": "^2.3.0"
35
+ }
36
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Formatage monetaire. Il vit dans le socle et non dans chaque SPA parce
3
+ * qu'une somme mal arrondie ou mal signee est un defaut bancaire, pas un
4
+ * defaut d'affichage.
5
+ */
6
+ /**
7
+ * Un montant ne se represente JAMAIS par un nombre a virgule flottante :
8
+ * 0.1 + 0.2 ne fait pas 0.3. On transporte des unites mineures entieres
9
+ * (centimes) et la devise qui leur donne leur echelle.
10
+ */
11
+ interface Montant {
12
+ /** Unites mineures. 12,34 EUR s'ecrit 1234. */
13
+ readonly unitesMineures: bigint;
14
+ /** Code ISO 4217, trois lettres majuscules. */
15
+ readonly devise: string;
16
+ }
17
+ declare function decimalesDe(devise: string): number;
18
+ declare function montant(unitesMineures: bigint | number, devise: string): Montant;
19
+ interface OptionsDeFormatage {
20
+ readonly locale?: string;
21
+ /** Affiche `+` devant un montant positif. Utile sur un releve. */
22
+ readonly signeExplicite?: boolean;
23
+ /** Masque le symbole de devise (colonnes de tableau deja titrees). */
24
+ readonly sansDevise?: boolean;
25
+ }
26
+ /**
27
+ * Rend un montant dans la locale demandee. La conversion en nombre n'a lieu
28
+ * qu'a l'instant du rendu, sur une valeur bornee par la precision d'affichage :
29
+ * le calcul, lui, n'a jamais quitte l'entier.
30
+ */
31
+ declare function formaterMontant(valeur: Montant, options?: OptionsDeFormatage): string;
32
+
33
+ /**
34
+ * IBAN : validation par la cle ISO 7064 mod 97-10 et presentation par groupes
35
+ * de quatre. La validation vit ici pour qu'un champ de saisie refuse une
36
+ * frappe fautive sans aller-retour serveur ; elle ne remplace jamais le
37
+ * controle du backend.
38
+ */
39
+ declare function normaliserIban(saisie: string): string;
40
+ declare function ibanEstValide(saisie: string): boolean;
41
+ /** Presentation par groupes de quatre, la seule lisible a l'oeil. */
42
+ declare function formaterIban(saisie: string): string;
43
+ /**
44
+ * Masque tout sauf le pays et les quatre derniers caracteres. Un IBAN complet
45
+ * ne s'affiche jamais dans une liste : il suffit a initier un prelevement.
46
+ */
47
+ declare function masquerIban(saisie: string): string;
48
+
49
+ /**
50
+ * Masques d'affichage des identifiants sensibles.
51
+ *
52
+ * Regle commune : on garde de quoi RECONNAITRE, jamais de quoi UTILISER. Un
53
+ * numero complet affiche dans une liste suffit a initier une operation ; les
54
+ * quatre derniers caracteres suffisent a l'utilisateur pour savoir de quel
55
+ * moyen il s'agit.
56
+ */
57
+ declare function normaliserCarte(saisie: string): string;
58
+ /**
59
+ * Ne laisse voir que les quatre derniers chiffres. Le reseau (les premiers
60
+ * chiffres) est volontairement masque : il identifie l'emetteur.
61
+ */
62
+ declare function masquerCarte(saisie: string): string;
63
+ /**
64
+ * Validation de carte par la cle de Luhn. Elle sert a refuser une frappe
65
+ * fautive sans aller-retour serveur ; elle ne prouve rien sur l'existence du
66
+ * moyen de paiement.
67
+ */
68
+ declare function carteEstValide(saisie: string): boolean;
69
+ declare function normaliserTelephone(saisie: string): string;
70
+ /**
71
+ * Garde l'indicatif international et les deux derniers chiffres. Un numero
72
+ * entier permet d'usurper, de harceler, ou de tenter une prise de controle
73
+ * par message.
74
+ */
75
+ declare function masquerTelephone(saisie: string): string;
76
+ /**
77
+ * Fin lisible d'un identifiant, pour composer un nom accessible : une suite de
78
+ * puces est epelee caractere par caractere par plusieurs lecteurs d'ecran.
79
+ */
80
+ declare function quatreDerniers(saisie: string): string;
81
+
82
+ export { carteEstValide, decimalesDe, formaterIban, formaterMontant, ibanEstValide, masquerCarte, masquerIban, masquerTelephone, montant, normaliserCarte, normaliserIban, normaliserTelephone, quatreDerniers };
83
+ export type { Montant, OptionsDeFormatage };