/** Dev fixture prefixes (import script / dev_fixture.php). */ export function isDevTestClientCode(code) { const c = String(code ?? '').trim(); return c.toUpperCase().startsWith('DEV-CL-'); } export function isDevTestUsername(username) { return String(username ?? '').trim().toLowerCase().startsWith('dev_'); } export function testDataRowClassForClient(clientCode) { return isDevTestClientCode(clientCode) ? ' row-test-data' : ''; } export function testDataRowClassForUser(username) { return isDevTestUsername(username) ? ' row-test-data' : ''; } const STABLE_KEY_RE = /^[a-zA-Z][a-zA-Z0-9_]*$/; /** Local question id from full questionID (hash__q5 → q5). */ export function questionLocalKey(questionID, fallback = '') { const id = String(questionID ?? ''); const sep = id.lastIndexOf('__'); if (sep >= 0) return id.slice(sep + 2); return fallback || id; } function parseQuestionConfig(q) { if (!q || typeof q !== 'object') return {}; let cfg = q.configJson; if (typeof cfg === 'string') { try { cfg = JSON.parse(cfg); } catch { cfg = {}; } } return cfg && typeof cfg === 'object' ? cfg : {}; } /** Stable question key for table headers / CSV (matches server qdb_question_column_label). */ export function questionDisplayKey(q) { if (!q) return ''; if (q.questionKey) return String(q.questionKey); const cfg = parseQuestionConfig(q); const fromCfg = String(cfg.questionKey || '').trim(); if (fromCfg && STABLE_KEY_RE.test(fromCfg)) return fromCfg; const dt = String(q.defaultText || '').trim(); if (dt && STABLE_KEY_RE.test(dt)) return dt; return questionLocalKey(q.questionID, dt); } /** German question text for header tooltips. */ export function questionGermanLabel(q) { const dt = String(q?.defaultText || '').trim(); const key = questionDisplayKey(q); if (dt && dt !== key) return dt; return ''; } /** header_order.json column id → question key (questionnaire_x-y → y). */ export function headerColumnQuestionKey(headerId) { const id = String(headerId ?? ''); if (id === 'client_code') return 'client_code'; const dash = id.indexOf('-'); if (dash < 0) return id; return id.slice(dash + 1); }