Portage navigateur complet de l'app Android HormoneTrack v1.4.10 : - moteur PK fidèle (Estrannaise tables ODS, Transfem Science V3C, WHSAH fit Mona, Bateman) — paramètres identiques, invariants Android préservés (fixes #19-#23, #35, #52-#62), 121 tests Node épinglés - calibration par période d'ester et par modèle affiché (#60/#61) - UI 6 écrans + éditeur, CurveChart Canvas (zoom/pan fractionnaire, prévision, pics/creux, fuseau configurable), rappels web (Notification API), seuils d'alerte, i18n FR/EN - sauvegarde JSON v2 compatible Android bidirectionnelle (rétrocompat v1) - 100 % local : localStorage, aucun serveur applicatif, aucune télémétrie - processus : scripts/check.sh (syntaxe, i18n, tests, E2E navigateur, smoke HTTP), docs séparées (README + DEVELOPPEMENT + CHANGELOG) - dépôt GIT SÉPARÉ de l'Android : historique 100 % propre, versions alignées sur l'Android porté, changelogs indépendants Non porté (impossible dans un navigateur, documenté §12) : agenda récurrent, notifications onglet fermé, montre.
76 lines
3.5 KiB
JavaScript
76 lines
3.5 KiB
JavaScript
/**
|
|
* ─────────────────────────────────────────────────────────────────────────────
|
|
* ChangelogHelper (portage de `settings/ChangelogHelper.kt`, v1.3.0) :
|
|
* alimente le dialog « Nouveautés » affiché après chaque mise à jour.
|
|
*
|
|
* Le contenu vient de `docs/CHANGELOG.md` (relatif à la racine web, fetché au
|
|
* démarrage — le fichier sert aussi de source pour les releases git ; c'est
|
|
* l'équivalent de l'asset changelog.md embarqué côté Android, synchronisé par
|
|
* la tâche Gradle copyChangelog).
|
|
*
|
|
* PUR → testable en Node (web/tests/changelog.test.js).
|
|
* ─────────────────────────────────────────────────────────────────────────────
|
|
*/
|
|
|
|
/**
|
|
* Compare deux versions SemVer « X.Y.Z » NUMÉRIQUEMENT (composant par
|
|
* composant) — une comparaison lexicographique considérerait à tort
|
|
* « 1.2.9 > 1.2.10 » (piège #38 côté Android : `v1.2.10 < v1.2.5` en
|
|
* comparaison de chaînes).
|
|
*
|
|
* @param {string} current
|
|
* @param {string|null|undefined} reference null = première installation → true
|
|
* @returns {boolean}
|
|
*/
|
|
export function isVersionNewer(current, reference) {
|
|
if (reference === null || reference === undefined || reference.trim() === '') return true;
|
|
const c = parse(current);
|
|
const r = parse(reference);
|
|
if (!c) return true; // version courante non parsable → considérer plus neuve (défensif)
|
|
if (!r) return true;
|
|
const len = Math.max(c.length, r.length);
|
|
for (let i = 0; i < len; i++) {
|
|
const a = c[i] ?? 0;
|
|
const b = r[i] ?? 0;
|
|
if (a !== b) return a > b;
|
|
}
|
|
return false; // identiques
|
|
}
|
|
|
|
/** @private Parse "v1.2.3" → [1,2,3] ; null si format non numérique. */
|
|
function parse(version) {
|
|
const cleaned = String(version).trim().replace(/^v/, '');
|
|
if (!/^\d+(\.\d+)*$/.test(cleaned)) return null;
|
|
return cleaned.split('.').map(Number);
|
|
}
|
|
|
|
/**
|
|
* Extrait de la CHANGELOG (markdown) les sections des versions STRICTEMENT
|
|
* plus récentes que `lastSeenVersion` (null = première installation → la
|
|
* version courante seule), jusqu'à `currentVersion` incluse.
|
|
*
|
|
* Format attendu : des sections « ## [X.Y.Z] — … » avec leur corps, la plus
|
|
* récente EN PREMIER (convention Keep a Changelog du dépôt).
|
|
*
|
|
* @param {string} markdown
|
|
* @param {string|null} lastSeenVersion
|
|
* @param {string} currentVersion
|
|
* @returns {string} markdown concaténé des nouveautés ("" si rien de nouveau)
|
|
*/
|
|
export function sectionsSince(markdown, lastSeenVersion, currentVersion) {
|
|
const pattern = /## \[(\d+\.\d+\.\d+)\][^\n]*\n([\s\S]*?)(?=\n## \[|\s*$)/g;
|
|
let out = '';
|
|
for (const match of markdown.matchAll(pattern)) {
|
|
const version = match[1];
|
|
// Sections triées de la plus récente à la plus ancienne :
|
|
// - inclure ce qui est STRICTEMENT plus récent que la dernière version
|
|
// vue (lastSeen null = première installation → section courante seule) ;
|
|
// - s'arrêter dès qu'on descend sous lastSeen (déjà vu).
|
|
if (lastSeenVersion !== null && !isVersionNewer(version, lastSeenVersion)) break;
|
|
if (lastSeenVersion === null && version !== currentVersion) continue;
|
|
if (out !== '') out += '\n\n---\n\n';
|
|
out += `## Version ${version}\n\n${match[2].trim()}`;
|
|
}
|
|
return out.trim();
|
|
}
|