Lot 4 modernisation JS (SonarLint) + restauration CI sonarqube non-bloquante
Build and deploy / test-python (push) Successful in 11m18s
Build and deploy / test-js (push) Successful in 1m16s
Build and deploy / lint-python (push) Successful in 4m24s
Build and deploy / lint-js (push) Successful in 2m51s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Build and deploy / sonarqube (push) Successful in 5m30s
Build and deploy / test-python (push) Successful in 11m18s
Build and deploy / test-js (push) Successful in 1m16s
Build and deploy / lint-python (push) Successful in 4m24s
Build and deploy / lint-js (push) Successful in 2m51s
Build and deploy / build-and-push (push) Skipped
Build and deploy / deploy (push) Skipped
Build and deploy / sonarqube (push) Successful in 5m30s
Corrige les findings SonarQube (via SonarLint IDE, fichier par fichier) sur ~24 fichiers static/js/ : parseFloat/parseInt -> Number.*, .replace(/x/g,y) -> .replaceAll, .indexOf() -> .includes()/.startsWith(), getAttribute/setAttribute -> .dataset, tableaux -> Set, x && x.y -> x?.y (verifie site par site), extraction de template litteraux imbriques, ternaires imbriquees, refactors de complexite cognitive (S3776) via tables de dispatch, Object.hasOwn, .at(), et deduplication de fonctions identiques (S4144). Deux exceptions S2486 documentees/corrigees (filter-repeater-rows.js) et un cas S2703 de partage inter-scripts complete (_collisionWizard, trigger-editor.js <-> collision-rules-editor.js). Details complets dans CODE_QUALITY.md section 5. Restaure aussi le job CI "sonarqube" (non-bloquant) dans .gitea/workflows/deploy.yml maintenant que l'instance prod est operationnelle. Suites vertes : 276/276 JS (node --test), 591/591 Python (pytest). SKIP=djlint sur ce commit : hook djlint bloquant sur le backlog H021 (styles inline, 49 occurrences/6 templates) deja documente comme dette assumee non traitee dans CODE_QUALITY.md section 6, aucun rapport avec ce commit (aucun template touche ici) - valide explicitement avec l'utilisateur avant de contourner ce hook. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
66d8eaeae8
commit
ccf836f2c5
@@ -15,7 +15,7 @@
|
||||
// play.html) et sont routés depuis forgeRenderElementHtml() ci-dessous
|
||||
// via forgeSpecialRenderer().
|
||||
|
||||
const FORGE_LAYOUT_CAPABLE_WIDGETS = ['conteneur', 'repeteur_donnees', 'liste', 'liste_numerotee', 'groupe_champs', 'tableau'];
|
||||
const FORGE_LAYOUT_CAPABLE_WIDGETS = new Set(['conteneur', 'repeteur_donnees', 'liste', 'liste_numerotee', 'groupe_champs', 'tableau']);
|
||||
|
||||
// Widgets à balise simple portés à l'étape 3 — {tag, hasContent,
|
||||
// selfClosing, fixedAttrs} — port direct de screens/widgets/registry.py
|
||||
@@ -66,9 +66,9 @@ const FORGE_SPECIAL_WIDGET_FIXED_ATTRS = { tableau: { class: 'table' } };
|
||||
|
||||
function forgeHtmlEscape(s) {
|
||||
return String(s)
|
||||
.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>')
|
||||
.replaceAll('"', '"')
|
||||
.replaceAll("'", ''');
|
||||
}
|
||||
|
||||
// Port de apply_ctx.py — {{champ}} remplacé par la valeur de la ligne en
|
||||
@@ -89,7 +89,7 @@ function forgeAutoId(el) {
|
||||
|
||||
// Port de parent_flex_direction.py.
|
||||
function forgeParentFlexDirection(parentEl) {
|
||||
const style = (parentEl && parentEl.style) || {};
|
||||
const style = parentEl?.style || {};
|
||||
if (style.display !== 'flex') return null;
|
||||
return style['flex-direction'] || 'row';
|
||||
}
|
||||
@@ -99,8 +99,8 @@ function forgeParentFlexDirection(parentEl) {
|
||||
// enfant), même garde-fous (transform réservé au cadre extérieur pour un
|
||||
// élément posé directement sur l'écran, 0px ignoré = pas de surcharge).
|
||||
function forgeStyleString(el, parentFlexDirection, widgetKey) {
|
||||
const style = { ...el.style || {} };
|
||||
if (FORGE_LAYOUT_CAPABLE_WIDGETS.indexOf(widgetKey) !== -1 && !('display' in style)) {
|
||||
const style = { ...el.style };
|
||||
if (FORGE_LAYOUT_CAPABLE_WIDGETS.has(widgetKey) && !('display' in style)) {
|
||||
style.display = 'flex';
|
||||
if (!('flex-direction' in style)) style['flex-direction'] = 'column';
|
||||
}
|
||||
@@ -150,13 +150,13 @@ function forgeVisibleAttrs(el, meta, ctx) {
|
||||
const rawAttrs = el.attributes || {};
|
||||
const attrs = {};
|
||||
Object.keys(rawAttrs).forEach((k) => {
|
||||
if (k.indexOf('_') === 0) return;
|
||||
if (k.startsWith('_')) return;
|
||||
const v = rawAttrs[k];
|
||||
attrs[k] = typeof v === 'string' ? forgeApplyCtx(v, ctx) : v;
|
||||
});
|
||||
Object.assign(attrs, meta.fixedAttrs || {});
|
||||
const extraClasses = Object.keys(rawAttrs)
|
||||
.filter((k) => k.indexOf('_class_') === 0 && rawAttrs[k])
|
||||
.filter((k) => k.startsWith('_class_') && rawAttrs[k])
|
||||
.map((k) => rawAttrs[k]);
|
||||
if (extraClasses.length) {
|
||||
const baseClass = attrs.class || '';
|
||||
@@ -170,7 +170,7 @@ function forgeVisibleAttrs(el, meta, ctx) {
|
||||
|
||||
// Port de render_children.py.
|
||||
function forgeRenderChildren(el, gameData, childrenMap, ctx) {
|
||||
const kids = (childrenMap && childrenMap[el.id]) || [];
|
||||
const kids = childrenMap?.[el.id] || [];
|
||||
const flexDir = forgeParentFlexDirection(el);
|
||||
return kids.map((c) => forgeRenderElementHtml(c, gameData, childrenMap, ctx, flexDir)).join('');
|
||||
}
|
||||
@@ -182,9 +182,9 @@ function forgeResolveBoundRowCtx(gameData, attrs) {
|
||||
let definitionId = attrs._data_definition_id;
|
||||
if (!definitionId) return null;
|
||||
definitionId = String(definitionId);
|
||||
const fieldsMetaForDef = gameData.fields_meta && gameData.fields_meta[definitionId];
|
||||
const fieldsMetaForDef = gameData.fields_meta?.[definitionId];
|
||||
if (!fieldsMetaForDef) return null;
|
||||
let rows = (gameData.data && gameData.data[definitionId]) || [];
|
||||
let rows = gameData.data?.[definitionId] || [];
|
||||
const decoded = forgeDecodeClauses(attrs, '_data_filtres_json', '_data_filtre_combinateur', '_data_filtre');
|
||||
rows = forgeFilterRowsByClauses(gameData, definitionId, rows, decoded.clauses, decoded.combinator);
|
||||
if (!rows.length) return null;
|
||||
@@ -206,8 +206,8 @@ function forgeResolveBoundRowCtx(gameData, attrs) {
|
||||
// une fois à l'export, voir full_game_payload.py) plutôt que depuis
|
||||
// d'éventuels enfants copiés en base.
|
||||
function forgeRenderElementTypeChildren(el, gameData, ctx) {
|
||||
const templateTree = gameData.element_type_templates && gameData.element_type_templates[String(el.element_type_id)];
|
||||
if (!templateTree || !templateTree.top.length) return [null, false];
|
||||
const templateTree = gameData.element_type_templates?.[String(el.element_type_id)];
|
||||
if (!templateTree?.top.length) return [null, false];
|
||||
const isOverlayOnly = templateTree.top.every((c) => c.widget === 'superposition');
|
||||
let { top } = templateTree;
|
||||
if (isOverlayOnly) {
|
||||
@@ -255,7 +255,7 @@ function forgeRenderElementHtml(el, gameData, childrenMap, ctx, parentFlexDirect
|
||||
const attrsRaw = el.attributes || {};
|
||||
|
||||
const hasVisibilityCondition = attrsRaw._visibilite_cond_mode === 'variable' || attrsRaw._visibilite_cond_mode === 'objet';
|
||||
const playMode = !!((ctx || {})._forge_play_mode);
|
||||
const playMode = !!ctx?._forge_play_mode;
|
||||
if (playMode && hasVisibilityCondition && !forgeIsElementVisibleOffline(gameData, attrsRaw, ctx)) {
|
||||
return `<div class="visibilityGated" data-element-id="${el.id}" style="display:none;"></div>`;
|
||||
}
|
||||
@@ -268,7 +268,7 @@ function forgeRenderElementHtml(el, gameData, childrenMap, ctx, parentFlexDirect
|
||||
};
|
||||
|
||||
const boundCtx = forgeResolveBoundRowCtx(gameData, attrsRaw);
|
||||
if (boundCtx) ctx = { ...ctx || {}, ...boundCtx };
|
||||
if (boundCtx) ctx = { ...ctx, ...boundCtx };
|
||||
|
||||
// meta d'un widget à special_render : fixedAttrs propre (voir
|
||||
// screens/widgets/registry.py — seul "tableau" en a un, "class":"table"),
|
||||
@@ -319,7 +319,7 @@ function forgeRenderElementHtml(el, gameData, childrenMap, ctx, parentFlexDirect
|
||||
return mark(`<${tag} ${forgeAttrString(attrs, style)}>${inner}</${tag}>`);
|
||||
}
|
||||
|
||||
const safeContent = content ? forgeHtmlEscape(content).replace(/\n/g, '<br>') : '';
|
||||
const safeContent = content ? forgeHtmlEscape(content).replaceAll('\n', '<br>') : '';
|
||||
return mark(`<${tag} ${forgeAttrString(attrs, style)}>${safeContent}${childHtml}</${tag}>`);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user