@starterlib/cli 0.10.13 → 0.11.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 +48 -32
- package/matrice-compatibilite.md +35 -20
- package/package.json +1 -1
- package/src/construction/construire.mjs +13 -6
- package/src/construction/scenarios.mjs +155 -0
- package/src/construction/simulations.mjs +5 -2
- package/src/construction/sprite.mjs +9 -4
- package/src/etapes/autonome.mjs +131 -0
- package/src/etapes/budget.mjs +12 -8
- package/src/etapes/dependances.mjs +1 -1
- package/src/etapes/formulations.mjs +182 -0
- package/src/etapes/i18n.mjs +58 -8
- package/src/etapes/jetons.mjs +22 -3
- package/src/etapes/navigateurs.mjs +21 -0
- package/src/etapes/outillage.mjs +63 -5
- package/src/etapes/securite.mjs +79 -4
- package/src/etapes/simulations.mjs +20 -2
- package/src/etapes/versions.mjs +19 -3
- package/src/etapes/vulnerabilites.mjs +1 -1
- package/src/index.mjs +8 -0
- package/src/lancer.mjs +86 -3
- package/src/marque.mjs +78 -0
- package/src/navigateurs.mjs +128 -0
- package/src/projet.mjs +7 -4
- package/src/verifier.mjs +8 -4
package/README.md
CHANGED
|
@@ -31,42 +31,45 @@ Scripts d'une SPA :
|
|
|
31
31
|
|
|
32
32
|
## Commandes
|
|
33
33
|
|
|
34
|
-
| Commande | Ce qu'elle fait
|
|
35
|
-
| --------------------------- |
|
|
36
|
-
| `starter-web start` | L'hote de developpement : sprite, simulations (remote), puis `ng serve` sous `STARTER_WEB_HOTE_DEV=1` (`--port N`)
|
|
37
|
-
| `starter-web verify` | Les etapes ci-dessous, dans l'ordre, arretees a la premiere qui echoue, dont le nom est ecrit
|
|
38
|
-
| `starter-web construire` | Sprite, `ng build`, prechargement de la police (hote), manifeste, precompression
|
|
39
|
-
| `starter-web sprite` | Pose le sprite hache (`public/`) et sa constante engendree (`sprite-genere.ts`)
|
|
40
|
-
| `starter-web manifeste` | Engendre `manifest.json` dans le dossier livre ; idempotent
|
|
41
|
-
| `starter-web precompresser` | Ecrit les variantes `.br` et `.gz`, et `precompression.index` (chaque variante et le condense de son source, que le serveur confronte) ; `starter-web precompresser <dossier>` pour un autre dossier
|
|
42
|
-
| `starter-web i18n:types` | Engendre `src/app/i18n/cles.ts`, le type des cles de chaque perimetre (`injecterTraduction<C>`)
|
|
43
|
-
| `starter-web simulations` | Recopie les stubs WireMock du service (`../src/mock`), corps compris, pour l'hote de developpement (`src/hote-dev/simulations.engendre.json`)
|
|
44
|
-
| `starter-web
|
|
34
|
+
| Commande | Ce qu'elle fait |
|
|
35
|
+
| --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
36
|
+
| `starter-web start` | L'hote de developpement : sprite, simulations (remote), puis `ng serve` sous `STARTER_WEB_HOTE_DEV=1` (`--port N`) |
|
|
37
|
+
| `starter-web verify` | Les etapes ci-dessous, dans l'ordre, arretees a la premiere qui echoue, dont le nom est ecrit |
|
|
38
|
+
| `starter-web construire` | Sprite, `ng build`, prechargement de la police (hote), manifeste, precompression |
|
|
39
|
+
| `starter-web sprite` | Pose le sprite hache (`public/`) et sa constante engendree (`sprite-genere.ts`) |
|
|
40
|
+
| `starter-web manifeste` | Engendre `manifest.json` dans le dossier livre ; idempotent |
|
|
41
|
+
| `starter-web precompresser` | Ecrit les variantes `.br` et `.gz`, et `precompression.index` (chaque variante et le condense de son source, que le serveur confronte) ; `starter-web precompresser <dossier>` pour un autre dossier |
|
|
42
|
+
| `starter-web i18n:types` | Engendre `src/app/i18n/cles.ts`, le type des cles de chaque perimetre (`injecterTraduction<C>`) |
|
|
43
|
+
| `starter-web simulations` | Recopie les stubs WireMock du service (`../src/mock`), corps compris, pour l'hote de developpement (`src/hote-dev/simulations.engendre.json`) ; `--scenarios` liste et juge les scenarios nommes du remote (`src/hote-dev/scenarios.json`), chacun avec son adresse `?scenario=<nom>` (P08-10) |
|
|
44
|
+
| `starter-web navigateurs` | Ecrit `.browserslistrc` : la liste browserslist du socle, tiree du plancher de la matrice (lot 276) |
|
|
45
|
+
| `starter-web etapes` | Liste les etapes et les roles qu'elles concernent |
|
|
45
46
|
|
|
46
47
|
Codes de sortie : `0` conforme ; `1` une etape a echoue ; `2` la commande ne peut pas s'executer
|
|
47
48
|
(argument inconnu, projet illisible).
|
|
48
49
|
|
|
49
50
|
## Les etapes de `verify`
|
|
50
51
|
|
|
51
|
-
| Etape | Role | Ce qu'elle garde
|
|
52
|
-
| ---------------- | -------- |
|
|
53
|
-
| `versions` |
|
|
54
|
-
| `
|
|
55
|
-
| `
|
|
56
|
-
| `
|
|
57
|
-
| `
|
|
58
|
-
| `
|
|
59
|
-
| `
|
|
60
|
-
| `
|
|
61
|
-
| `
|
|
62
|
-
| `
|
|
63
|
-
| `
|
|
64
|
-
| `
|
|
65
|
-
| `
|
|
66
|
-
| `
|
|
67
|
-
| `
|
|
68
|
-
| `
|
|
69
|
-
| `
|
|
52
|
+
| Etape | Role | Ce qu'elle garde |
|
|
53
|
+
| ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
54
|
+
| `versions` | tous | Versions exactes de la matrice, greffon de federation lie a Angular, pnpm, Node, train du socle |
|
|
55
|
+
| `navigateurs` | tous | La liste browserslist de la SPA (`.browserslistrc`, ou `browserslist` de `package.json`) est celle du plancher de la matrice : ni absente, ni plus basse, ni plus large (lot 276) |
|
|
56
|
+
| `dependances` | tous | Dependances de production revues, paquets interdits, aucun outil du socle recopie sous `tools/` |
|
|
57
|
+
| `jetons` | tous | Chaque `var(--st-*)` sans repli existe dans `@starterlib/tokens` (feuilles et styles en ligne) |
|
|
58
|
+
| `format` | tous | `prettier --check .` |
|
|
59
|
+
| `lint` | tous | Prefixe des selecteurs (jamais `st-`), `eslint .`, puis stylelint (configuration du socle exigee) |
|
|
60
|
+
| `i18n` | tous | Memes cles et arguments en fr et en, messages lisibles, cles appelees presentes, aide de chaque page (`<perimetre>.aide.<page>`), types a jour, formulations interdites par l'application (`starterWeb.formulationsInterdites`) |
|
|
61
|
+
| `test` | tous | `ng test --no-watch` |
|
|
62
|
+
| `contrat` | tous | `pnpm run contrat:check` s'il existe (client d'API engendre, lot 175), sinon sautee en le disant |
|
|
63
|
+
| `simulations` | remote | Les stubs WireMock du service, tels que l'hote de developpement les rejoue, a jour (lot 269) ; sautee sans simulateur ni scenarios ; un stub hors du sous-ensemble est nomme ; le fichier de scenarios, s'il existe, juge (P08-10 : un scenario que l'hote ne rejouerait pas est un defaut) |
|
|
64
|
+
| `build` | tous | `starter-web construire` |
|
|
65
|
+
| `vulnerabilites` | tous | `pnpm audit --prod` : HIGH et CRITICAL bloquent sauf exception DATEE de `securite/exceptions-npm.json` (un trimestre au plus) ; SBOM CycloneDX dans `dist/sbom-front.cdx.json`, a cote du dossier livre (jamais servie) ; licences AGPL, SSPL et inconnues refusees (lot 139) |
|
|
66
|
+
| `manifeste` | les deux | `validerLeManifesteDeRemote` et le schema de `@starterlib/core` INSTALLE ; le nom partout le meme |
|
|
67
|
+
| `federation` | les deux | Partage en singleton strict a plage explicite, Angular et le socle partages, aucun import nu orphelin |
|
|
68
|
+
| `entree` | hote | Aucun paquet partage importe statiquement avant `initFederation` |
|
|
69
|
+
| `budget` | les deux | En brotli. Remote : chaque page (60 Ko), le total (250 Ko), les catalogues. Hote : premier ecran |
|
|
70
|
+
| `autonome` | autonome | Aucune federation livree (`remoteEntry`, carte d'importation, `es-module-shims`) ; versions d'Angular et du socle egales a celles du jumeau (`starterWeb.jumeau`) ; poids de l'ecran (`starterWeb.ecran` : entree et seuil en Ko br), lu dans la carte de la construction (lot 240) |
|
|
71
|
+
| `amorcage` | hote | Aucun pair lourd (CDK, aria, formulaires, surfaces) dans le premier ecran |
|
|
72
|
+
| `securite` | tous | Puits de l'ADR 0029 dans le code de la SPA, politiques Trusted Types exactes, cartes, SVG, meta CSP |
|
|
70
73
|
|
|
71
74
|
`--etapes a,b` n'en joue que certaines ; `--sauter a,b` en retire.
|
|
72
75
|
|
|
@@ -81,9 +84,22 @@ par un point d'entree vide dans la configuration `production`).
|
|
|
81
84
|
|
|
82
85
|
## Ce que le CLI lit, et d'ou
|
|
83
86
|
|
|
84
|
-
- le role : `package.json#starterWeb.role` (`"hote"` pour la coquille
|
|
85
|
-
`
|
|
87
|
+
- le role : `package.json#starterWeb.role` (`"hote"` pour la coquille, `"autonome"` pour une
|
|
88
|
+
application servie seule, sans federation : l'ecran anonyme d'identity, lot 240), sinon `remote` des
|
|
89
|
+
qu'un `manifest.source.json` existe ;
|
|
90
|
+
- pour une application autonome, dans `starterWeb` : `nom` (le projet d'`angular.json`),
|
|
91
|
+
`i18n.perimetres` (ses catalogues), `jumeau` (le dossier du remote du meme service, dont elle
|
|
92
|
+
partage les versions) et `ecran` (`{ "entree": "src/app/pages/connexion.ts", "seuilKo": 155 }`) ;
|
|
93
|
+
`starter-web construire` n'y ecrit pas de manifeste, et pose `--stats-json` ; `securite` y
|
|
94
|
+
neutralise UNE lecture de cookie du cadre (`DomAdapter.getCookie`, dans `main` faute de morceau
|
|
95
|
+
partage), toute autre restant un defaut ;
|
|
86
96
|
- le nom et `pleinePage` : `manifest.source.json` (un remote), `socle` pour l'hote ;
|
|
97
|
+
- les formulations que l'application interdit dans ses textes : `starterWeb.formulationsInterdites`,
|
|
98
|
+
chemin d'un fichier JSON relatif a sa racine, qui liste des `formulations` (un `id`, des `textes`
|
|
99
|
+
ou un `motif`, des `langues` au besoin) et des `exceptions` (une `formulation`, une `cle`, une
|
|
100
|
+
`raison`, une `date`) ; l'etape `i18n` y cherche chaque texte sans casse ni accents et en mots
|
|
101
|
+
entiers, chaque motif tel quel (format detaille : `src/etapes/formulations.mjs`). Sans reglage,
|
|
102
|
+
rien n'est cherche : le socle ne connait aucune formulation ;
|
|
87
103
|
- le prefixe des selecteurs : `prefix` du projet d'`angular.json` (ou `starterWeb.prefixe`) ;
|
|
88
104
|
- le dossier livre : `outputPath` de la cible `@angular/build:application`, plus `browser` ;
|
|
89
105
|
- le train requis et le socle construit : `remoteEntry.json`, ce que la federation a reellement
|
package/matrice-compatibilite.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Matrice de compatibilite du socle frontal
|
|
2
2
|
|
|
3
|
-
Verifiee le 2026-
|
|
3
|
+
Verifiee le 2026-10-07 contre le registre npm (montee au dernier correctif de la ligne 22.2 ; avant elle, lot 154). Toute montee de version se fait
|
|
4
4
|
**ligne par ligne, dans le meme commit**, et `pnpm versions:check` echoue si le
|
|
5
5
|
`package.json` s'en ecarte (version non exacte, autre que celle de la matrice, paquet Angular absent
|
|
6
6
|
de la matrice, greffon de federation d'une autre majeure.mineure qu'Angular, autre pnpm, Node sous le
|
|
@@ -9,27 +9,30 @@ lit CE document, publie avec lui, et ses essais le comparent a la matrice de `ve
|
|
|
9
9
|
|
|
10
10
|
⚠️ **Trois jours d'anciennete au moins** : `minimumReleaseAge: 4320` (`pnpm-workspace.yaml`) tient hors
|
|
11
11
|
du verrou toute version publiee depuis moins de trois jours (constat A1405). Une version plus recente,
|
|
12
|
-
meme corrective, attend :
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
meme corrective, attend : au 2026-10-07, `axe-core` 4.14.0 (2026-10-05), `typescript-eslint` 8.71.1
|
|
13
|
+
(2026-10-05), `jsdom` 30.1.2 (2026-10-04), `@microsoft/api-extractor` 7.59.4 (2026-10-06) et `orval`
|
|
14
|
+
8.40.0 (2026-10-04) n'entrent pas ; la version precedente de chacun y entre. Angular monte en 22.2.1 le
|
|
15
|
+
2026-10-07 (correctif publie le 2026-09-30), apres la 22.2.0 du 2026-09-27.
|
|
15
16
|
|
|
16
17
|
## Train `2026.1`
|
|
17
18
|
|
|
18
19
|
| Element | Version | Pourquoi cette version exactement |
|
|
19
20
|
| -------------------------------------------------------------------------------------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
20
|
-
| `@angular/core`, `common`, `compiler`, `compiler-cli`, `forms`, `platform-browser`, `router` | `22.2.
|
|
21
|
-
| `@angular/cdk`, `aria` | `22.2.
|
|
22
|
-
| `@angular/
|
|
23
|
-
| `
|
|
24
|
-
| `
|
|
21
|
+
| `@angular/core`, `common`, `compiler`, `compiler-cli`, `forms`, `platform-browser`, `router` | `22.2.1` | Dernier correctif de la ligne 22.2, publie le 2026-09-30 (plus de trois jours au 2026-10-07) |
|
|
22
|
+
| `@angular/cdk`, `aria` | `22.2.1` | Le paquet `aria` est stable depuis la 22 ; il porte les primitives sans style. `@angular/material` est retire : aucun composant du socle ne l'importe |
|
|
23
|
+
| `@angular/elements` | `22.2.1` | Les custom elements de `@starterlib/elements` seulement (lot 299, decision du proprietaire du 2026-10-01) ; son pair exige le numero exact de `@angular/core`, d'ou le meme 22.2.1 |
|
|
24
|
+
| `@angular/build`, `@angular/cli` | `22.2.1` | ⚠️ **Cadence differente de `core`.** L'outillage recoit des correctifs que le coeur ne recoit pas. Une matrice qui ne porterait qu'un seul numero mentirait des le premier correctif |
|
|
25
|
+
| `@angular-devkit/schematics` | `22.2.1` | Le moteur des schematics du CLI d'Angular, au meme numero : `@starterlib/schematics` (lot 285) n'en importe rien a l'execution, ses essais le lancent (`SchematicTestRunner`) |
|
|
26
|
+
| `ng-packagr` | `22.2.4` | Derniere stable de la ligne 22.2 (2026-10-01) |
|
|
27
|
+
| `typescript` | `6.0.3` | ⚠️ **Piege.** La 7.0.2 est publiee, mais `@angular/compiler-cli@22.2.1` exige `>=6.0 <6.1`. Installer la derniere casse la compilation |
|
|
25
28
|
| `node` | `>=24.15.0` | 24.x LTS, declare dans `engines` ; le meme plancher que la construction Maven des SPA (`frontend.node.version`) |
|
|
26
29
|
| `pnpm` | `11.27.1` | Declare dans `packageManager` ; reglages dans `pnpm-workspace.yaml` (`allowBuilds`, `minimumReleaseAge`). Le meme pour la construction Maven des SPA (`frontend.pnpm.version` de `platform-parent`) |
|
|
27
|
-
| `vitest`, `@vitest/browser`, `@vitest/browser-playwright`, `@vitest/coverage-v8` | `5.0.
|
|
30
|
+
| `vitest`, `@vitest/browser`, `@vitest/browser-playwright`, `@vitest/coverage-v8` | `5.0.3` | Lanceur officiel du constructeur `@angular/build:unit-test` ; un meme numero pour toute la famille (des numeros meles chargent deux copies du lanceur) |
|
|
28
31
|
| `playwright`, `@playwright/test` | `1.63.0` | Le navigateur des essais : un correctif change un rendu mesure au pixel |
|
|
29
|
-
| `eslint` | `10.
|
|
32
|
+
| `eslint` | `10.12.0` | `angular-eslint@22.5.0` accepte les majeurs 9 et 10 |
|
|
30
33
|
| `angular-eslint` | `22.5.0` | Suit le majeur d'Angular |
|
|
31
|
-
| `stylelint`, `postcss-scss` | `17.
|
|
32
|
-
| `jsdom`, `axe-core` | `30.
|
|
34
|
+
| `stylelint`, `postcss-scss` | `17.16.0`, `4.0.9` | Les feuilles du socle et des SPA (lot 178, `@starterlib/eslint-config/stylelint`) ; `postcss-scss` lit le SCSS |
|
|
35
|
+
| `jsdom`, `axe-core` | `30.1.1`, `4.13.0` | Le DOM des essais unitaires et le controle d'accessibilite : un correctif change ce qu'un essai voit |
|
|
33
36
|
|
|
34
37
|
## Prochain train : `2026.2` (prevu, non applique)
|
|
35
38
|
|
|
@@ -47,8 +50,8 @@ interfaces), avec `pnpm verify` et `banc-d-assemblage.sh --construire` verts :
|
|
|
47
50
|
|
|
48
51
|
| Element | Version | Avertissement |
|
|
49
52
|
| --------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
50
|
-
| `@angular-architects/native-federation` | `22.2.
|
|
51
|
-
| `orval` | `8.
|
|
53
|
+
| `@angular-architects/native-federation` | `22.2.2` | ⚠️ **A epingler a l'exact, jamais par etiquette.** Le 2026-09-12, l'etiquette `latest` du paquet pointait sur la **21.2.6**, publiee apres la 22.1.2. Un `pnpm add` sans version ramene donc un majeur de retard, en silence, et l'echec se manifeste au chargement d'un remote, loin de la cause. Version mesuree au spike du 2026-09-16. Sa majeure.mineure est celle d'Angular (22.2) : `versions:check` refuse un couple disjoint, et les deux montent dans le meme commit (235a) |
|
|
54
|
+
| `orval` | `8.39.0` | Client d'API engendre depuis le contrat du service (ADR web 0008) : services `HttpClient` pour les ecritures, `httpResource` pour les lectures, aucun schema zod, donc aucune dependance a l'execution. Derniere stable de plus de trois jours au 2026-10-07 (8.39.0, publiee le 2026-09-30) ; a epingler a l'exact, en dependance de developpement |
|
|
52
55
|
| `es-module-shims` | `2.8.4` | Dependance du greffon, et pas un detail : c'est ELLE qui cree la politique de types de confiance `es-module-shims`. Toute montee doit verifier que le nom de la politique n'a pas change, sinon la page devient blanche sans erreur serveur |
|
|
53
56
|
| `@axe-core/playwright` | `4.13.0` | Les essais d'accessibilite de bout en bout de la coquille (Playwright) ; le meme numero qu'`axe-core`, qui fait le controle : deux moteurs d'une version differente ne signaleraient pas les memes violations |
|
|
54
57
|
|
|
@@ -67,19 +70,31 @@ maximum, fonction par fonction, de ce que les feuilles et le noyau emploient san
|
|
|
67
70
|
Sous ce plancher, rien ne casse sans le dire : une surface sans `@starting-style` apparait d'un coup ; une
|
|
68
71
|
couleur sans `light-dark()` n'existe pas, d'ou le plancher.
|
|
69
72
|
|
|
73
|
+
Au-dessus du plancher, AVEC repli (P08-03) : la requete de style d'une propriete personnalisee,
|
|
74
|
+
`@container style(--st-prefixe-de-ton: visible)` (Chrome 111, Safari 18, Firefox 151), affiche le prefixe
|
|
75
|
+
de ton (« Erreur : ») qu'une application demande visible ; en deca, il reste masque, et toujours lu.
|
|
76
|
+
|
|
70
77
|
Ce plancher est plus haut que celui d'Angular 22.2 (« baseline widely available » au 2026-05-07 : Chrome et
|
|
71
78
|
Edge 119, Firefox 119, Safari et iOS 17) : la construction ne vise pas plus bas que le socle n'en a besoin.
|
|
72
79
|
|
|
80
|
+
**Liste partagee (lot 276, 0.10.14).** La liste browserslist de chaque SPA DERIVE de la ligne du plancher
|
|
81
|
+
ci-dessus, que `@starterlib/cli` lit dans ce document publie avec lui : Chrome, Edge, Chrome Android et la
|
|
82
|
+
WebView d'Android au plancher de Chrome, Firefox et Firefox Android a celui de Firefox, Safari et iOS a
|
|
83
|
+
celui de Safari. `starter-web navigateurs` l'ecrit dans `.browserslistrc` ; l'etape `navigateurs` de
|
|
84
|
+
`starter-web verify` refuse une liste absente, plus basse ou plus large. Sous le plancher, l'hote montre
|
|
85
|
+
la page « navigateur non pris en charge » de `@starterlib/core/navigateur` au lieu de demarrer
|
|
86
|
+
(detection par fonction, jamais par l'agent utilisateur).
|
|
87
|
+
|
|
73
88
|
**Mesure (banc d'assemblage du BFF, lot 276, 2026-10-01).** Playwright 1.63 : Chromium 153, Firefox 155,
|
|
74
89
|
WebKit 26.6, Pixel 7 et iPhone 15 emules. Chromium et le telephone Android jouent tout le banc a chaque
|
|
75
90
|
poussee ; Firefox, WebKit et l'iPhone jouent les scenarios `@moteurs` et `@mobile` chaque semaine
|
|
76
91
|
(`BANC_MOTEURS=tous`).
|
|
77
92
|
|
|
78
|
-
| Moteur | Version mesuree | Plancher | Ce qui se degrade entre le plancher et la mesure
|
|
79
|
-
| ------------- | --------------- | -------- |
|
|
80
|
-
| Chromium/Edge | 153 | 123 | rien de connu : les types de confiance y sont appliques depuis bien avant 123
|
|
81
|
-
| Firefox | 155 | 129 | la protection des puits DOM par les types de confiance, si la version ne les a pas |
|
|
82
|
-
| Safari/iOS | 26.6 | 17.5 | idem ; la politique bloque toujours les scripts sans nonce
|
|
93
|
+
| Moteur | Version mesuree | Plancher | Ce qui se degrade entre le plancher et la mesure |
|
|
94
|
+
| ------------- | --------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
95
|
+
| Chromium/Edge | 153 | 123 | rien de connu : les types de confiance y sont appliques depuis bien avant 123 |
|
|
96
|
+
| Firefox | 155 | 129 | la protection des puits DOM par les types de confiance, si la version ne les a pas ; avant 151, le prefixe de ton reste masque sous `--st-prefixe-de-ton: visible` |
|
|
97
|
+
| Safari/iOS | 26.6 | 17.5 | idem ; la politique bloque toujours les scripts sans nonce ; avant 18, le prefixe de ton reste masque |
|
|
83
98
|
|
|
84
99
|
**WebView.** Android System WebView suit Chromium, WKWebView suit le Safari du systeme : memes planchers
|
|
85
100
|
(decisions mobiles, ADR 0043 du socle `api/starter`). **Revision** : a chaque montee de Playwright (nouveaux moteurs) et au plus
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@starterlib/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Chaine de verification et de construction des SPA du socle frontal starter : starter-web verify, construire, sprite, manifeste, precompresser. Jamais en dependance de production.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -50,21 +50,28 @@ export function construire(
|
|
|
50
50
|
{ configuration = 'production', journal = console, sprite = true } = {},
|
|
51
51
|
) {
|
|
52
52
|
if (sprite) journal.info(` sprite : ${poserLeSprite(projet)}`);
|
|
53
|
+
// Une application autonome ecrit la carte de sa construction : l'etape `autonome` y lit le
|
|
54
|
+
// morceau de la route de son ecran (lot 240).
|
|
55
|
+
const carte = projet.role === 'autonome' ? ['--stats-json'] : [];
|
|
53
56
|
const code = executer(
|
|
54
57
|
'pnpm',
|
|
55
|
-
['exec', 'ng', 'build', '--configuration', configuration],
|
|
58
|
+
['exec', 'ng', 'build', '--configuration', configuration, ...carte],
|
|
56
59
|
projet.racine,
|
|
57
60
|
);
|
|
58
61
|
if (code !== 0) {
|
|
59
62
|
journal.erreur(` ng build --configuration ${configuration} : code ${String(code)}.`);
|
|
60
63
|
return code;
|
|
61
64
|
}
|
|
62
|
-
|
|
65
|
+
// L'hote et l'application autonome peignent un premier ecran : la police s'y precharge.
|
|
66
|
+
if (projet.role === 'hote' || projet.role === 'autonome')
|
|
63
67
|
journal.info(` police prechargee : ${prechargerLaPolice(projet.sortie)}`);
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
// Une application autonome n'est pas assemblee : aucun manifeste (lot 240).
|
|
69
|
+
if (projet.role !== 'autonome') {
|
|
70
|
+
const manifeste = ecrireLeManifeste(projet);
|
|
71
|
+
journal.info(
|
|
72
|
+
` manifest.json : ${manifeste.nom} ${manifeste.version}, socle ${manifeste.socle.construit}`,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
68
75
|
const { resume, defauts } = juger(precompresser(projet.sortie));
|
|
69
76
|
journal.info(` precompression : ${resume}`);
|
|
70
77
|
for (const defaut of defauts) journal.erreur(` - ${defaut}`);
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Le fichier de scenarios d'un remote (P08-10) : `src/hote-dev/scenarios.json`, les etats nommes
|
|
3
|
+
* d'une page que l'hote de developpement ouvre par l'adresse (`?scenario=<nom>`,
|
|
4
|
+
* `@starterlib/testing/hote-dev`). `starter-web simulations --scenarios` les liste ; l'etape
|
|
5
|
+
* `simulations` de `verify` les juge.
|
|
6
|
+
*
|
|
7
|
+
* ```json
|
|
8
|
+
* {
|
|
9
|
+
* "scenarios": {
|
|
10
|
+
* "liste-vide": {
|
|
11
|
+
* "description": "Aucun element : l'etat vide de la liste",
|
|
12
|
+
* "stubs": [
|
|
13
|
+
* {
|
|
14
|
+
* "request": { "method": "GET", "urlPath": "/api/v1/elements" },
|
|
15
|
+
* "response": { "status": 200, "jsonBody": { "content": [], "nextCursor": null } }
|
|
16
|
+
* }
|
|
17
|
+
* ]
|
|
18
|
+
* },
|
|
19
|
+
* "gestionnaire": {
|
|
20
|
+
* "description": "Session d'un gestionnaire",
|
|
21
|
+
* "session": { "nomAffiche": "Gabriel Essai", "roles": ["GESTIONNAIRE"] }
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* Un scenario porte une `description`, et au besoin des `stubs` (le sous-ensemble de WireMock que
|
|
28
|
+
* l'hote rejoue, corps EN LIGNE : `jsonBody` ou `body`) et une `session` (ce qu'elle change de la
|
|
29
|
+
* session simulee). Tout ecart est un DEFAUT : un scenario ecrit pour l'hote doit s'y rejouer. Les
|
|
30
|
+
* noms et les donnees sont fictifs : aucune donnee personnelle reelle.
|
|
31
|
+
*/
|
|
32
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
33
|
+
import { join } from 'node:path';
|
|
34
|
+
import { horsDuSousEnsemble } from './simulations.mjs';
|
|
35
|
+
|
|
36
|
+
/** Ou vit le fichier de scenarios, depuis la racine de la SPA. */
|
|
37
|
+
export const CHEMIN_DES_SCENARIOS = join('src', 'hote-dev', 'scenarios.json');
|
|
38
|
+
|
|
39
|
+
/** Le nom d'un scenario : celui qu'on tape dans l'adresse (`NOM_DE_SCENARIO` de l'hote). */
|
|
40
|
+
export const NOM_DE_SCENARIO = /^[a-z][a-z0-9-]{0,60}$/;
|
|
41
|
+
|
|
42
|
+
const CLES_DU_SCENARIO = new Set(['description', 'stubs', 'session']);
|
|
43
|
+
|
|
44
|
+
/** Ce que la session simulee d'un scenario peut changer (`ReponseDeSession` du noyau). */
|
|
45
|
+
const CLES_DE_SESSION = new Set([
|
|
46
|
+
'authenticated',
|
|
47
|
+
'userId',
|
|
48
|
+
'csrfToken',
|
|
49
|
+
'email',
|
|
50
|
+
'nomAffiche',
|
|
51
|
+
'langue',
|
|
52
|
+
'theme',
|
|
53
|
+
'roles',
|
|
54
|
+
'permissionsAffichables',
|
|
55
|
+
'mustChangePassword',
|
|
56
|
+
'montantsMasques',
|
|
57
|
+
'expiresAt',
|
|
58
|
+
'absoluteExpiresAt',
|
|
59
|
+
]);
|
|
60
|
+
|
|
61
|
+
const estUnObjet = (valeur) =>
|
|
62
|
+
typeof valeur === 'object' && valeur !== null && !Array.isArray(valeur);
|
|
63
|
+
|
|
64
|
+
/** Les defauts d'un scenario (vide : il se rejoue). */
|
|
65
|
+
function defautsDuScenario(nom, scenario) {
|
|
66
|
+
const defauts = [];
|
|
67
|
+
if (!NOM_DE_SCENARIO.test(nom)) {
|
|
68
|
+
defauts.push(`scenario "${nom}" : nom attendu en minuscules et tirets (^[a-z][a-z0-9-]*$).`);
|
|
69
|
+
}
|
|
70
|
+
if (!estUnObjet(scenario)) return [...defauts, `scenario "${nom}" : un objet est attendu.`];
|
|
71
|
+
for (const cle of Object.keys(scenario)) {
|
|
72
|
+
if (!CLES_DU_SCENARIO.has(cle)) defauts.push(`scenario "${nom}" : cle inconnue "${cle}".`);
|
|
73
|
+
}
|
|
74
|
+
if (typeof scenario.description !== 'string' || scenario.description.trim() === '') {
|
|
75
|
+
defauts.push(`scenario "${nom}" : description absente (ce que le scenario montre).`);
|
|
76
|
+
}
|
|
77
|
+
if (scenario.stubs !== undefined) {
|
|
78
|
+
if (!Array.isArray(scenario.stubs)) {
|
|
79
|
+
defauts.push(`scenario "${nom}" : stubs attendus en liste.`);
|
|
80
|
+
} else {
|
|
81
|
+
for (const [indice, stub] of scenario.stubs.entries()) {
|
|
82
|
+
const ou = `scenario "${nom}", stub ${String(indice)}`;
|
|
83
|
+
if (!estUnObjet(stub?.request) || !estUnObjet(stub?.response)) {
|
|
84
|
+
defauts.push(`${ou} : request et response attendus.`);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (stub.response.bodyFileName !== undefined) {
|
|
88
|
+
defauts.push(`${ou} : corps en ligne attendu (jsonBody ou body), pas bodyFileName.`);
|
|
89
|
+
}
|
|
90
|
+
const raisons = horsDuSousEnsemble(stub);
|
|
91
|
+
if (raisons.length > 0) {
|
|
92
|
+
defauts.push(`${ou} : hors de ce que l'hote rejoue : ${raisons.join(', ')}.`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (scenario.session !== undefined) {
|
|
98
|
+
if (!estUnObjet(scenario.session)) {
|
|
99
|
+
defauts.push(`scenario "${nom}" : session attendue en objet.`);
|
|
100
|
+
} else {
|
|
101
|
+
for (const cle of Object.keys(scenario.session)) {
|
|
102
|
+
if (!CLES_DE_SESSION.has(cle)) {
|
|
103
|
+
defauts.push(`scenario "${nom}" : session, cle inconnue "${cle}".`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return defauts;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Lit et juge le fichier de scenarios : `{ chemin, scenarios, defauts }`, chaque scenario
|
|
113
|
+
* `{ nom, description, stubs, session }` (nombre de stubs, session changee ou non), ou `null` si la
|
|
114
|
+
* SPA n'en a pas.
|
|
115
|
+
*/
|
|
116
|
+
export function lireLesScenarios(projet) {
|
|
117
|
+
const chemin = join(projet.racine, CHEMIN_DES_SCENARIOS);
|
|
118
|
+
if (!existsSync(chemin)) return null;
|
|
119
|
+
let contenu;
|
|
120
|
+
try {
|
|
121
|
+
contenu = JSON.parse(readFileSync(chemin, 'utf8'));
|
|
122
|
+
} catch (erreur) {
|
|
123
|
+
return {
|
|
124
|
+
chemin,
|
|
125
|
+
scenarios: [],
|
|
126
|
+
defauts: [
|
|
127
|
+
`${CHEMIN_DES_SCENARIOS} illisible : ${erreur instanceof Error ? erreur.message : String(erreur)}.`,
|
|
128
|
+
],
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
if (!estUnObjet(contenu) || !estUnObjet(contenu.scenarios)) {
|
|
132
|
+
return {
|
|
133
|
+
chemin,
|
|
134
|
+
scenarios: [],
|
|
135
|
+
defauts: [`${CHEMIN_DES_SCENARIOS} : un objet "scenarios" est attendu.`],
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
const defauts = [];
|
|
139
|
+
for (const cle of Object.keys(contenu)) {
|
|
140
|
+
if (cle !== 'scenarios' && cle !== '$comment') {
|
|
141
|
+
defauts.push(`${CHEMIN_DES_SCENARIOS} : cle inconnue "${cle}".`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const scenarios = [];
|
|
145
|
+
for (const [nom, scenario] of Object.entries(contenu.scenarios)) {
|
|
146
|
+
defauts.push(...defautsDuScenario(nom, scenario));
|
|
147
|
+
scenarios.push({
|
|
148
|
+
nom,
|
|
149
|
+
description: typeof scenario?.description === 'string' ? scenario.description : '',
|
|
150
|
+
stubs: Array.isArray(scenario?.stubs) ? scenario.stubs.length : 0,
|
|
151
|
+
session: estUnObjet(scenario?.session),
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
return { chemin, scenarios, defauts };
|
|
155
|
+
}
|
|
@@ -110,8 +110,11 @@ export function racineDesStubs(projet) {
|
|
|
110
110
|
return null;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
/**
|
|
114
|
-
|
|
113
|
+
/**
|
|
114
|
+
* Les raisons pour lesquelles l'hote ne rejouerait pas ce stub (vide : il le rejoue). Le fichier de
|
|
115
|
+
* scenarios (P08-10) les tient pour des defauts.
|
|
116
|
+
*/
|
|
117
|
+
export function horsDuSousEnsemble(stub) {
|
|
115
118
|
const raisons = [];
|
|
116
119
|
const inconnues = (objet, admises, ou) => {
|
|
117
120
|
for (const cle of Object.keys(objet ?? {})) {
|
|
@@ -20,9 +20,14 @@ import { empreinteCourte } from '../commun.mjs';
|
|
|
20
20
|
|
|
21
21
|
const SPRITE_HACHE = /^sprite-[A-Z0-9]{8}\.svg$/;
|
|
22
22
|
|
|
23
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Les chemins du sprite selon le role. Une application autonome (lot 240) peint le sprite du SOCLE,
|
|
25
|
+
* comme l'hote : elle n'a ni remote ni sprite metier.
|
|
26
|
+
*/
|
|
27
|
+
const duSocle = (projet) => projet.role === 'hote' || projet.role === 'autonome';
|
|
28
|
+
|
|
24
29
|
function reglages(projet) {
|
|
25
|
-
if (projet
|
|
30
|
+
if (duSocle(projet)) {
|
|
26
31
|
return {
|
|
27
32
|
source: join(
|
|
28
33
|
projet.racine,
|
|
@@ -74,11 +79,11 @@ export function poserLeSprite(projet) {
|
|
|
74
79
|
const { source, dossier, adresse, genere, constante } = reglages(projet);
|
|
75
80
|
if (!existsSync(source)) {
|
|
76
81
|
throw new Error(
|
|
77
|
-
`sprite absent : ${source}${projet
|
|
82
|
+
`sprite absent : ${source}${duSocle(projet) ? " (pnpm install d'abord)" : ''}.`,
|
|
78
83
|
);
|
|
79
84
|
}
|
|
80
85
|
const contenu = readFileSync(source);
|
|
81
|
-
if (projet
|
|
86
|
+
if (duSocle(projet)) verifierLeSpriteDuSocle(source, contenu);
|
|
82
87
|
const fichier = `sprite-${empreinteCourte(contenu)}.svg`;
|
|
83
88
|
mkdirSync(dossier, { recursive: true });
|
|
84
89
|
for (const existant of readdirSync(dossier)) {
|