@starterlib/cli 0.11.0 → 0.11.1

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 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`) |
@@ -100,6 +100,10 @@ par un point d'entree vide dans la configuration `production`).
100
100
  `raison`, une `date`) ; l'etape `i18n` y cherche chaque texte sans casse ni accents et en mots
101
101
  entiers, chaque motif tel quel (format detaille : `src/etapes/formulations.mjs`). Sans reglage,
102
102
  rien n'est cherche : le socle ne connait aucune formulation ;
103
+ - la feuille de marque que la SPA versionne : `starterWeb.feuilleDeMarque`, chemin relatif a sa racine
104
+ (`marque/starter-tokens-<nom>.css`, ecrite par `starter-web jetons --sortie marque`) ; l'etape
105
+ `jetons` la veut identique a celle que le moteur installe engendre de sa marque, fins de ligne mises
106
+ a part. Sans reglage, seule la marque est jugee ;
103
107
  - le prefixe des selecteurs : `prefix` du projet d'`angular.json` (ou `starterWeb.prefixe`) ;
104
108
  - le dossier livre : `outputPath` de la cible `@angular/build:application`, plus `browser` ;
105
109
  - 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.0",
3
+ "version": "0.11.1",
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",
@@ -25,8 +25,8 @@ import { natureDesFichiers } from '../livraison.mjs';
25
25
  export const BUDGETS_DU_REMOTE = { pageKo: 60, totalKo: 250, catalogueKo: 30 };
26
26
 
27
27
  /**
28
- * Les seuils de l'hote, en Ko brotli (ADR 0031) : 309 pour le premier ecran reel, 288 pour la
29
- * charge initiale (ADR web 0005, D167). Leur histoire : ramenes au socle 0.10.0 (releves dans
28
+ * Les seuils de l'hote, en Ko brotli (ADR 0031) : 313 pour le premier ecran reel, 289 pour la
29
+ * charge initiale (ADR web 0005, D168). Leur histoire : ramenes au socle 0.10.0 (releves dans
30
30
  * l'ADR 0031) ; la charge initiale passee de 280 a 281 le 2026-09-29, decision du proprietaire :
31
31
  * 280,4 Ko mesures avec le socle 0.10.9, dont les controles d'empreinte S05 du lot 272 tournent au
32
32
  * demarrage. Puis, le meme jour, 282 et 301 (decision de l'orchestrateur sur autorisation du
@@ -35,13 +35,16 @@ export const BUDGETS_DU_REMOTE = { pageKo: 60, totalKo: 250, catalogueKo: 30 };
35
35
  * marque, demarrage determine, amorce). Puis 288 et 309 le 2026-10-07 : la coquille d'Aplomb
36
36
  * mesuree contre la 0.11.0 construite, avant publication, 286,96 et 307,86 Ko (+5,1 et +6,2 Ko sur
37
37
  * 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).
38
+ * 287,4 et 308,3 Ko avec sa feuille de marque et la feuille de sa police de titre (+0,44 Ko). Puis
39
+ * 289 et 313 le 2026-10-07 : la coquille d'Aplomb refaite sur ses maquettes (menu en haut, barre
40
+ * inferieure, bandeau du compte simule, pied, accueil de simulation), mesuree contre la 0.11.1
41
+ * construite, avant publication, 288,2 et 312,2 Ko (tronc a 47 410 octets, D168).
39
42
  *
40
43
  * ⚠️ Ce ne sont pas la cible du plan SPA §2.8 (170 Ko). L'ecart restant est STRUCTUREL : un paquet
41
44
  * partage en singleton part ENTIER, parce que n'importe quel remote peut en avoir besoin. Un seuil
42
45
  * se baisse ; il ne se leve jamais sans mesure ecrite et sans date.
43
46
  */
44
- export const BUDGETS_DE_L_HOTE = { premierEcranKo: 309, chargeInitialeKo: 288, cibleDuPlanKo: 170 };
47
+ export const BUDGETS_DE_L_HOTE = { premierEcranKo: 313, chargeInitialeKo: 289, cibleDuPlanKo: 170 };
45
48
 
46
49
  /** Les imports DYNAMIQUES d'un module : les pages qu'il charge a la demande. */
47
50
  const IMPORT_DYNAMIQUE = /\bimport\s*\(\s*["']([^"']+)["']\s*\)/g;
@@ -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 { fichierDeMarque, jugerLaMarque } from '../marque.mjs';
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) marque = ` ; marque ${String(juge.valeurs.nom)} conforme`;
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/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
+ }