// integrations/cisco-dect/statusXmlInventory.js // // Walk a parsed status.xml tree and list every leaf path with a short // preview. Used by collect-raw tooling to spot populated sections // (RSSI_List, Device_Presence, SIP_Identity_Status, etc.) without // hand-reading XML. import { xmlToObject } from './statusXml.js'; const HANDSET_RELATED = /rssi|presence|sip_identity|device_line|statistics|rpn|mac/i; /** * @typedef {object} SectionInventoryEntry * @property {string} path dot-separated path from root * @property {boolean} isEmpty true when leaf is absent or whitespace-only * @property {string|null} preview truncated leaf value (null for empty containers) * @property {boolean} handsetRelated heuristic flag for operator summaries */ /** * Build a flat inventory of leaf paths from raw status.xml text. * * @param {string} xml * @returns {SectionInventoryEntry[]} */ export function inventoryStatusXml(xml) { if (typeof xml !== 'string' || !xml.trim()) return []; const tree = xmlToObject(xml); const entries = []; walk(tree, '', entries); return entries; } /** * Summarize non-empty handset-related paths for console output. * * @param {SectionInventoryEntry[]} inventory * @returns {{ nonEmpty: number, handsetRelated: number, paths: string[] }} */ export function summarizeInventory(inventory) { const list = Array.isArray(inventory) ? inventory : []; const nonEmpty = list.filter((e) => !e.isEmpty); const handsetPaths = nonEmpty .filter((e) => e.handsetRelated) .map((e) => e.path); return { nonEmpty: nonEmpty.length, handsetRelated: handsetPaths.length, paths: handsetPaths, }; } function walk(node, prefix, out) { if (node == null) { pushLeaf(prefix, '', out); return; } if (typeof node === 'string') { pushLeaf(prefix, node, out); return; } if (typeof node !== 'object') { pushLeaf(prefix, String(node), out); return; } const keys = Object.keys(node); if (keys.length === 0) { pushLeaf(prefix, '', out); return; } for (const key of keys) { const path = prefix ? `${prefix}.${key}` : key; walk(node[key], path, out); } } function pushLeaf(path, value, out) { const str = value == null ? '' : String(value).trim(); const isEmpty = str === ''; out.push({ path, isEmpty, preview: isEmpty ? null : truncate(str, 120), handsetRelated: HANDSET_RELATED.test(path), }); } function truncate(s, max) { if (s.length <= max) return s; return `${s.slice(0, max - 1)}…`; }