@starterlib/cli 0.11.0 → 0.11.2
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 +13 -3
- package/package.json +1 -1
- package/src/etapes/budget.mjs +70 -8
- package/src/etapes/jetons.mjs +23 -3
- package/src/etapes/securite.mjs +20 -9
- package/src/marque.mjs +29 -1
package/README.md
CHANGED
|
@@ -54,7 +54,7 @@ Codes de sortie : `0` conforme ; `1` une etape a echoue ; `2` la commande ne peu
|
|
|
54
54
|
| `versions` | tous | Versions exactes de la matrice, greffon de federation lie a Angular, pnpm, Node, train du socle |
|
|
55
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
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)
|
|
57
|
+
| `jetons` | tous | Chaque `var(--st-*)` sans repli existe dans `@starterlib/tokens` (feuilles et styles en ligne) ; la marque de la SPA (`marque.json`, `.ts` ou `.mjs`), rejouee par le moteur installe ; sa feuille versionnee (`starterWeb.feuilleDeMarque`), identique a celle qu'il engendre |
|
|
58
58
|
| `format` | tous | `prettier --check .` |
|
|
59
59
|
| `lint` | tous | Prefixe des selecteurs (jamais `st-`), `eslint .`, puis stylelint (configuration du socle exigee) |
|
|
60
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`) |
|
|
@@ -66,7 +66,7 @@ Codes de sortie : `0` conforme ; `1` une etape a echoue ; `2` la commande ne peu
|
|
|
66
66
|
| `manifeste` | les deux | `validerLeManifesteDeRemote` et le schema de `@starterlib/core` INSTALLE ; le nom partout le meme |
|
|
67
67
|
| `federation` | les deux | Partage en singleton strict a plage explicite, Angular et le socle partages, aucun import nu orphelin |
|
|
68
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
|
|
69
|
+
| `budget` | les deux | En brotli. Remote : chaque page (60 Ko), le total (250 Ko), les catalogues. Hote : charge initiale et premier ecran (ses entrees, `starterWeb.premierEcran.entrees`, D171) |
|
|
70
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
71
|
| `amorcage` | hote | Aucun pair lourd (CDK, aria, formulaires, surfaces) dans le premier ecran |
|
|
72
72
|
| `securite` | tous | Puits de l'ADR 0029 dans le code de la SPA, politiques Trusted Types exactes, cartes, SVG, meta CSP |
|
|
@@ -89,10 +89,16 @@ par un point d'entree vide dans la configuration `production`).
|
|
|
89
89
|
qu'un `manifest.source.json` existe ;
|
|
90
90
|
- pour une application autonome, dans `starterWeb` : `nom` (le projet d'`angular.json`),
|
|
91
91
|
`i18n.perimetres` (ses catalogues), `jumeau` (le dossier du remote du meme service, dont elle
|
|
92
|
-
partage les versions)
|
|
92
|
+
partage les versions), `ecran` (`{ "entree": "src/app/pages/connexion.ts", "seuilKo": 155 }`) et, s'il en
|
|
93
|
+
cree, `trustedTypes` (les politiques Trusted Types qu'elle cree en plus de celles du BFF, que sa page doit porter
|
|
94
|
+
nommement : `["verification-humaine"]`) ;
|
|
93
95
|
`starter-web construire` n'y ecrit pas de manifeste, et pose `--stats-json` ; `securite` y
|
|
94
96
|
neutralise UNE lecture de cookie du cadre (`DomAdapter.getCookie`, dans `main` faute de morceau
|
|
95
97
|
partage), toute autre restant un defaut ;
|
|
98
|
+
- pour l'hote, dans `starterWeb` : `premierEcran.entrees` (les sources de ses gabarits et de sa page d'arrivee,
|
|
99
|
+
`["src/app/gabarits/coquille.ts", "src/app/pages/accueil.ts"]`), cherchees dans `browser-stats.json` que la
|
|
100
|
+
cible esbuild d'`angular.json` ecrit avec `statsJson: true` ; sans elles, le premier ecran compte toutes les pages
|
|
101
|
+
de route (D171) ;
|
|
96
102
|
- le nom et `pleinePage` : `manifest.source.json` (un remote), `socle` pour l'hote ;
|
|
97
103
|
- les formulations que l'application interdit dans ses textes : `starterWeb.formulationsInterdites`,
|
|
98
104
|
chemin d'un fichier JSON relatif a sa racine, qui liste des `formulations` (un `id`, des `textes`
|
|
@@ -100,6 +106,10 @@ par un point d'entree vide dans la configuration `production`).
|
|
|
100
106
|
`raison`, une `date`) ; l'etape `i18n` y cherche chaque texte sans casse ni accents et en mots
|
|
101
107
|
entiers, chaque motif tel quel (format detaille : `src/etapes/formulations.mjs`). Sans reglage,
|
|
102
108
|
rien n'est cherche : le socle ne connait aucune formulation ;
|
|
109
|
+
- la feuille de marque que la SPA versionne : `starterWeb.feuilleDeMarque`, chemin relatif a sa racine
|
|
110
|
+
(`marque/starter-tokens-<nom>.css`, ecrite par `starter-web jetons --sortie marque`) ; l'etape
|
|
111
|
+
`jetons` la veut identique a celle que le moteur installe engendre de sa marque, fins de ligne mises
|
|
112
|
+
a part. Sans reglage, seule la marque est jugee ;
|
|
103
113
|
- le prefixe des selecteurs : `prefix` du projet d'`angular.json` (ou `starterWeb.prefixe`) ;
|
|
104
114
|
- le dossier livre : `outputPath` de la cible `@angular/build:application`, plus `browser` ;
|
|
105
115
|
- le train requis et le socle construit : `remoteEntry.json`, ce que la federation a reellement
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@starterlib/cli",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.2",
|
|
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",
|
package/src/etapes/budget.mjs
CHANGED
|
@@ -15,18 +15,19 @@
|
|
|
15
15
|
* partages resolus par la carte d'importation.
|
|
16
16
|
*/
|
|
17
17
|
import { readFileSync, readdirSync, existsSync, statSync } from 'node:fs';
|
|
18
|
-
import { join } from 'node:path';
|
|
18
|
+
import { dirname, join } from 'node:path';
|
|
19
19
|
import { brotliCompressSync, constants } from 'node:zlib';
|
|
20
20
|
import { cloture, departDeLaPage, totaux } from '../cloture.mjs';
|
|
21
21
|
import { fichiers, ko, lireJson, relatif } from '../commun.mjs';
|
|
22
22
|
import { natureDesFichiers } from '../livraison.mjs';
|
|
23
|
+
import { morceauDeLEntree } from './autonome.mjs';
|
|
23
24
|
|
|
24
25
|
/** Les budgets d'un remote, en Ko brotli (plan SPA §2.8). */
|
|
25
26
|
export const BUDGETS_DU_REMOTE = { pageKo: 60, totalKo: 250, catalogueKo: 30 };
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
|
-
* Les seuils de l'hote, en Ko brotli (ADR 0031) :
|
|
29
|
-
* charge initiale (ADR web 0005,
|
|
29
|
+
* Les seuils de l'hote, en Ko brotli (ADR 0031) : 312 pour le premier ecran reel, mesure sur les
|
|
30
|
+
* entrees que l'hote declare, 289 pour la charge initiale (ADR web 0005, D168 et D171). Leur histoire : ramenes au socle 0.10.0 (releves dans
|
|
30
31
|
* l'ADR 0031) ; la charge initiale passee de 280 a 281 le 2026-09-29, decision du proprietaire :
|
|
31
32
|
* 280,4 Ko mesures avec le socle 0.10.9, dont les controles d'empreinte S05 du lot 272 tournent au
|
|
32
33
|
* demarrage. Puis, le meme jour, 282 et 301 (decision de l'orchestrateur sur autorisation du
|
|
@@ -35,13 +36,23 @@ export const BUDGETS_DU_REMOTE = { pageKo: 60, totalKo: 250, catalogueKo: 30 };
|
|
|
35
36
|
* marque, demarrage determine, amorce). Puis 288 et 309 le 2026-10-07 : la coquille d'Aplomb
|
|
36
37
|
* mesuree contre la 0.11.0 construite, avant publication, 286,96 et 307,86 Ko (+5,1 et +6,2 Ko sur
|
|
37
38
|
* la 0.10.14 : barre inferieure, action critique et raccourci, ressource rafraichie, tronc), puis
|
|
38
|
-
* 287,4 et 308,3 Ko avec sa feuille de marque et la feuille de sa police de titre (+0,44 Ko).
|
|
39
|
+
* 287,4 et 308,3 Ko avec sa feuille de marque et la feuille de sa police de titre (+0,44 Ko). Puis
|
|
40
|
+
* 289 et 313 le 2026-10-07 : la coquille d'Aplomb refaite sur ses maquettes (menu en haut, barre
|
|
41
|
+
* inferieure, bandeau du compte simule, pied, accueil de simulation), mesuree contre la 0.11.1
|
|
42
|
+
* construite, avant publication, 288,2 et 312,2 Ko (tronc a 47 410 octets, D168). Puis 314 pour le
|
|
43
|
+
* premier ecran le 2026-10-07 (D169) : la meme coquille avec la garde du parcours d'ouverture (lecture
|
|
44
|
+
* du parcours avant l'accueil, client engendre compris), le gabarit pleine page refait et la page de
|
|
45
|
+
* repli du parcours, mesuree contre la 0.11.1 publiee et le tronc de la 0.11.2, 288,8 et 313,7 Ko.
|
|
46
|
+
* Puis 312 le 2026-10-08 (D171, avant la publication de la 0.11.2) : le premier ecran se mesure sur les
|
|
47
|
+
* ENTREES que l'hote declare (ses gabarits, sa page d'arrivee) et non plus sur toutes ses pages de route ;
|
|
48
|
+
* la coquille d'Aplomb avec le cablage du parcours, le contexte de compte, l'etat du bot (en `@defer`) et
|
|
49
|
+
* le bouton d'arret permanent, 311,3 Ko.
|
|
39
50
|
*
|
|
40
51
|
* ⚠️ Ce ne sont pas la cible du plan SPA §2.8 (170 Ko). L'ecart restant est STRUCTUREL : un paquet
|
|
41
52
|
* partage en singleton part ENTIER, parce que n'importe quel remote peut en avoir besoin. Un seuil
|
|
42
53
|
* se baisse ; il ne se leve jamais sans mesure ecrite et sans date.
|
|
43
54
|
*/
|
|
44
|
-
export const BUDGETS_DE_L_HOTE = { premierEcranKo:
|
|
55
|
+
export const BUDGETS_DE_L_HOTE = { premierEcranKo: 312, chargeInitialeKo: 289, cibleDuPlanKo: 170 };
|
|
45
56
|
|
|
46
57
|
/** Les imports DYNAMIQUES d'un module : les pages qu'il charge a la demande. */
|
|
47
58
|
const IMPORT_DYNAMIQUE = /\bimport\s*\(\s*["']([^"']+)["']\s*\)/g;
|
|
@@ -158,25 +169,76 @@ function budgetDuRemote(projet) {
|
|
|
158
169
|
};
|
|
159
170
|
}
|
|
160
171
|
|
|
172
|
+
/**
|
|
173
|
+
* Le premier ecran de l'hote (D171) : la charge initiale (cloture de profondeur 1 depuis la page) et les
|
|
174
|
+
* ENTREES que l'hote declare (ses gabarits, sa page d'arrivee), chacune avec ses imports STATIQUES ; ni
|
|
175
|
+
* leurs imports dynamiques (un `@defer`, une page chargee a la demande), ni les autres pages de route.
|
|
176
|
+
*
|
|
177
|
+
* @param morceaux les fichiers des entrees, lus dans la carte de la construction ; `null` sans entrees
|
|
178
|
+
* declarees : la mesure reste alors la cloture de profondeur 2 (toutes les pages de route)
|
|
179
|
+
*/
|
|
180
|
+
export function premierEcranDeLHote(sortie, depart, carte, morceaux) {
|
|
181
|
+
if (morceaux === null) return cloture(sortie, depart, carte, 2);
|
|
182
|
+
const ecran = cloture(sortie, depart, carte, 1);
|
|
183
|
+
for (const [chemin, taille] of cloture(sortie, morceaux, carte, 0)) {
|
|
184
|
+
if (!ecran.has(chemin)) ecran.set(chemin, taille);
|
|
185
|
+
}
|
|
186
|
+
return ecran;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Les fichiers des entrees du premier ecran (`starterWeb.premierEcran.entrees` : les sources, comme
|
|
191
|
+
* `starterWeb.ecran` d'une application autonome), lus dans la carte de la construction
|
|
192
|
+
* (`browser-stats.json`, que la cible esbuild d'`angular.json` ecrit avec `statsJson: true` : le
|
|
193
|
+
* builder de Native Federation refuse `--stats-json`). `null` sans entrees declarees. Une carte absente
|
|
194
|
+
* ou une entree introuvable est un defaut, jamais un repli silencieux sur l'ancienne mesure.
|
|
195
|
+
*/
|
|
196
|
+
function entreesDuPremierEcran(projet, defauts) {
|
|
197
|
+
const entrees = projet.paquet.starterWeb?.premierEcran?.entrees;
|
|
198
|
+
if (!Array.isArray(entrees) || entrees.length === 0) return null;
|
|
199
|
+
const stats = lireJson(join(dirname(projet.sortie), 'browser-stats.json'));
|
|
200
|
+
if (stats === null) {
|
|
201
|
+
defauts.push(
|
|
202
|
+
'starterWeb.premierEcran : browser-stats.json absent (poser statsJson: true sur la cible ' +
|
|
203
|
+
"esbuild d'angular.json, puis construire).",
|
|
204
|
+
);
|
|
205
|
+
return [];
|
|
206
|
+
}
|
|
207
|
+
const morceaux = [];
|
|
208
|
+
for (const entree of entrees) {
|
|
209
|
+
const morceau = morceauDeLEntree(stats, entree);
|
|
210
|
+
if (morceau === null) {
|
|
211
|
+
defauts.push(
|
|
212
|
+
`starterWeb.premierEcran : l'entree ${String(entree)} est introuvable dans browser-stats.json.`,
|
|
213
|
+
);
|
|
214
|
+
} else {
|
|
215
|
+
morceaux.push(morceau);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return morceaux;
|
|
219
|
+
}
|
|
220
|
+
|
|
161
221
|
function budgetDeLHote(projet) {
|
|
162
222
|
const index = join(projet.sortie, 'index.html');
|
|
163
223
|
if (!existsSync(index)) {
|
|
164
224
|
return { defauts: [`${projet.sortieRelative}/index.html absent : construire d'abord.`] };
|
|
165
225
|
}
|
|
226
|
+
const defauts = [];
|
|
166
227
|
const carte = lireJson(join(projet.sortie, 'importmap.json'))?.imports ?? {};
|
|
167
228
|
const depart = departDeLaPage(readFileSync(index, 'utf8'));
|
|
168
229
|
const initiale = totaux(cloture(projet.sortie, depart, carte, 1));
|
|
169
|
-
const
|
|
230
|
+
const morceaux = entreesDuPremierEcran(projet, defauts);
|
|
231
|
+
const premierEcran = premierEcranDeLHote(projet.sortie, depart, carte, morceaux);
|
|
170
232
|
const ecran = totaux(premierEcran);
|
|
171
233
|
const details = [
|
|
172
234
|
`charge initiale ${String(ko(initiale.brotli))} Ko br (${String(initiale.fichiers)} fichiers)`,
|
|
173
|
-
`premier ecran reel ${String(ko(ecran.brotli))} Ko br (${String(ecran.fichiers)} fichiers
|
|
235
|
+
`premier ecran reel ${String(ko(ecran.brotli))} Ko br (${String(ecran.fichiers)} fichiers, ` +
|
|
236
|
+
`${morceaux === null ? 'toutes les pages de route' : 'entrees declarees'})`,
|
|
174
237
|
...[...premierEcran.entries()]
|
|
175
238
|
.sort((a, b) => b[1].brotli - a[1].brotli)
|
|
176
239
|
.slice(0, 5)
|
|
177
240
|
.map(([chemin, taille]) => ` ${String(ko(taille.brotli))} Ko br ${chemin}`),
|
|
178
241
|
];
|
|
179
|
-
const defauts = [];
|
|
180
242
|
if (ko(initiale.brotli) > BUDGETS_DE_L_HOTE.chargeInitialeKo) {
|
|
181
243
|
defauts.push(
|
|
182
244
|
`charge initiale : ${String(ko(initiale.brotli))} Ko br > ${String(BUDGETS_DE_L_HOTE.chargeInitialeKo)} Ko.`,
|
package/src/etapes/jetons.mjs
CHANGED
|
@@ -14,12 +14,19 @@
|
|
|
14
14
|
*
|
|
15
15
|
* La MARQUE de la SPA (niveau 2 bis : `marque.json`, `marque.ts` ou `marque.mjs` a la racine) est
|
|
16
16
|
* rejouee ici a chaque verification, par le moteur des jetons installe : une valeur reprise qui fait
|
|
17
|
-
* tomber une paire sous son seuil rougit `verify`, paire nommee, avant la construction.
|
|
17
|
+
* tomber une paire sous son seuil rougit `verify`, paire nommee, avant la construction. Sa feuille
|
|
18
|
+
* versionnee, si la SPA la declare (`starterWeb.feuilleDeMarque`), doit etre celle que ce moteur
|
|
19
|
+
* engendre : une feuille perimee rougit aussi.
|
|
18
20
|
*/
|
|
19
21
|
import { readFileSync } from 'node:fs';
|
|
20
22
|
import { join } from 'node:path';
|
|
21
23
|
import { fichiers, relatif } from '../commun.mjs';
|
|
22
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
FICHIERS_DE_MARQUE,
|
|
26
|
+
deriveDeLaFeuille,
|
|
27
|
+
fichierDeMarque,
|
|
28
|
+
jugerLaMarque,
|
|
29
|
+
} from '../marque.mjs';
|
|
23
30
|
|
|
24
31
|
/** Poses a l'execution par un composant du socle, donc absents des feuilles engendrees. */
|
|
25
32
|
const POSES_A_L_EXECUTION = new Set([
|
|
@@ -110,11 +117,24 @@ export default {
|
|
|
110
117
|
const { defauts, lues } = jugerLesJetons(feuilles, definis);
|
|
111
118
|
let marque = '';
|
|
112
119
|
const chemin = fichierDeMarque(projet.racine);
|
|
120
|
+
const versionnee = projet.paquet?.starterWeb?.feuilleDeMarque;
|
|
113
121
|
if (chemin !== null) {
|
|
114
122
|
const nom = relatif(projet.racine, chemin);
|
|
115
123
|
const juge = await jugerLaMarque(projet.racine, chemin);
|
|
116
124
|
for (const defaut of juge.defauts) defauts.push(`${nom} : ${defaut}`);
|
|
117
|
-
if (juge.defauts.length === 0)
|
|
125
|
+
if (juge.defauts.length === 0) {
|
|
126
|
+
marque = ` ; marque ${String(juge.valeurs.nom)} conforme`;
|
|
127
|
+
if (versionnee !== undefined) {
|
|
128
|
+
const attendue = juge.moteur.feuilleDeMarque(juge.valeurs);
|
|
129
|
+
const derive = deriveDeLaFeuille(projet.racine, versionnee, juge.valeurs.nom, attendue);
|
|
130
|
+
if (derive === null) marque += `, ${String(versionnee)} a jour`;
|
|
131
|
+
else defauts.push(derive);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
} else if (versionnee !== undefined) {
|
|
135
|
+
defauts.push(
|
|
136
|
+
`package.json : starterWeb.feuilleDeMarque sans fichier de marque (${FICHIERS_DE_MARQUE.join(', ')}).`,
|
|
137
|
+
);
|
|
118
138
|
}
|
|
119
139
|
return {
|
|
120
140
|
defauts,
|
package/src/etapes/securite.mjs
CHANGED
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Pour tout fichier livre, cadre compris :
|
|
7
7
|
* - eval, new Function, stockage du navigateur, lecture de cookie ;
|
|
8
|
-
* - politiques Trusted Types comparees a la liste EXACTE du BFF
|
|
8
|
+
* - politiques Trusted Types comparees a la liste EXACTE du BFF, plus celles qu'une application declare
|
|
9
|
+
* (un remote dans `manifest.source.json#trustedTypes`, lot 270 ; une application autonome dans
|
|
10
|
+
* `package.json#starterWeb.trustedTypes`, 0.11.2)
|
|
9
11
|
* (`platform.web.headers.csp.trusted-types-policies`), augmentee de celles que le remote
|
|
10
12
|
* declare (`trustedTypes` de `manifest.source.json`, lot 270) ;
|
|
11
13
|
* - cartes de source (et leurs variantes compressees), script dans un SVG ;
|
|
@@ -241,7 +243,8 @@ export function jugerUnFichierLivre(
|
|
|
241
243
|
defauts.push(
|
|
242
244
|
`${nom} : politique Trusted Types hors liste ("${politique}" ; admises : ` +
|
|
243
245
|
`${[...POLITIQUES_ADMISES, ...declarees].join(', ')}). La declarer dans ` +
|
|
244
|
-
'manifest.source.json (trustedTypes)
|
|
246
|
+
`${role === 'autonome' ? 'package.json (starterWeb.trustedTypes)' : 'manifest.source.json (trustedTypes)'} ` +
|
|
247
|
+
'et a la CSP du BFF avant livraison.',
|
|
245
248
|
);
|
|
246
249
|
}
|
|
247
250
|
}
|
|
@@ -271,15 +274,23 @@ export default {
|
|
|
271
274
|
};
|
|
272
275
|
}
|
|
273
276
|
const { partages } = natureDesFichiers(lireJson(join(projet.sortie, 'remoteEntry.json')));
|
|
274
|
-
// Les politiques que
|
|
275
|
-
// CSP n'admet pas
|
|
276
|
-
|
|
277
|
+
// Les politiques que l'application declare : un remote (lot 270), que le BFF retire s'il en exige une
|
|
278
|
+
// que sa CSP n'admet pas ; une application autonome (0.11.2), dont la page doit les porter nommement
|
|
279
|
+
// (la page d'ui-auth d'Aplomb et le widget de verification humaine). L'etape le dit des la construction.
|
|
280
|
+
const declarees =
|
|
281
|
+
projet.role === 'remote'
|
|
282
|
+
? (projet.source?.trustedTypes ?? [])
|
|
283
|
+
: projet.role === 'autonome'
|
|
284
|
+
? (projet.paquet.starterWeb?.trustedTypes ?? [])
|
|
285
|
+
: [];
|
|
277
286
|
const avertissements = declarees
|
|
278
287
|
.filter((politique) => !POLITIQUES_ADMISES.includes(politique))
|
|
279
|
-
.map(
|
|
280
|
-
|
|
281
|
-
`trustedTypes : "${politique}" absente de la liste par defaut du BFF ` +
|
|
282
|
-
|
|
288
|
+
.map((politique) =>
|
|
289
|
+
projet.role === 'autonome'
|
|
290
|
+
? `trustedTypes : "${politique}" absente de la liste par defaut du BFF ` +
|
|
291
|
+
'(PLATFORM_WEB_CSP_TRUSTED_TYPES) : la page de l application doit la porter nommement.'
|
|
292
|
+
: `trustedTypes : "${politique}" absente de la liste par defaut du BFF ` +
|
|
293
|
+
'(PLATFORM_WEB_CSP_TRUSTED_TYPES) : le BFF retire le remote tant qu elle n y est pas.',
|
|
283
294
|
);
|
|
284
295
|
const defauts = [];
|
|
285
296
|
// Application autonome : la lecture de cookie du cadre, une seule fois dans tout le livrable.
|
package/src/marque.mjs
CHANGED
|
@@ -7,9 +7,13 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Fichier de marque : `marque.json`, ou un module `marque.ts` / `marque.mjs` qui exporte la table
|
|
9
9
|
* (`export default`, ou `export const marque`). Forme : `ValeursDeMarque` du moteur (README des jetons).
|
|
10
|
+
*
|
|
11
|
+
* Une SPA qui VERSIONNE sa feuille (chargee par `angular.json`, relue a la revue) la declare dans
|
|
12
|
+
* `starterWeb.feuilleDeMarque` : l'etape `jetons` la confronte alors a celle que le moteur installe
|
|
13
|
+
* engendre, et la refuse si elle a derive (P09-01 d'Aplomb, qui la gardait par un script a lui).
|
|
10
14
|
*/
|
|
11
15
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
12
|
-
import { join, resolve } from 'node:path';
|
|
16
|
+
import { basename, dirname, join, resolve } from 'node:path';
|
|
13
17
|
import { pathToFileURL } from 'node:url';
|
|
14
18
|
import { dossierInstalle } from './socle-installe.mjs';
|
|
15
19
|
|
|
@@ -76,3 +80,27 @@ export async function ecrireLaFeuilleDeMarque(racine, chemin, sortie) {
|
|
|
76
80
|
writeFileSync(feuille, moteur.feuilleDeMarque(valeurs));
|
|
77
81
|
return { valeurs, defauts, feuille };
|
|
78
82
|
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* La feuille VERSIONNEE d'une SPA (`versionnee` : `starterWeb.feuilleDeMarque`, relatif a sa racine),
|
|
86
|
+
* confrontee a la feuille `attendue` que le moteur installe engendre de sa marque `nom` : `null` si elle
|
|
87
|
+
* est a jour, le defaut sinon. Les fins de ligne ne comptent pas (une copie de travail sous Windows les
|
|
88
|
+
* convertit).
|
|
89
|
+
*/
|
|
90
|
+
export function deriveDeLaFeuille(racine, versionnee, nom, attendue) {
|
|
91
|
+
if (typeof versionnee !== 'string' || versionnee === '') {
|
|
92
|
+
return 'package.json : starterWeb.feuilleDeMarque, le chemin de la feuille versionnee, est attendu.';
|
|
93
|
+
}
|
|
94
|
+
const fichier = `starter-tokens-${nom}.css`;
|
|
95
|
+
if (basename(versionnee) !== fichier) {
|
|
96
|
+
return `starterWeb.feuilleDeMarque : ${versionnee}, la feuille de la marque ${nom} se nomme ${fichier}.`;
|
|
97
|
+
}
|
|
98
|
+
const regenerer = `starter-web jetons --sortie ${dirname(versionnee)}`;
|
|
99
|
+
const chemin = resolve(racine, versionnee);
|
|
100
|
+
if (!existsSync(chemin)) return `${versionnee} absente : ${regenerer}.`;
|
|
101
|
+
const lf = (texte) => texte.replace(/\r\n/g, '\n');
|
|
102
|
+
if (lf(readFileSync(chemin, 'utf8')) !== lf(attendue)) {
|
|
103
|
+
return `${versionnee} perimee : ${regenerer}, puis la relire et la commiter.`;
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|