// Function to build the hierarchical data structure for the tree
function buildTreeData(elements) {
const treeRoot = { children: {}, element: null, name: 'Root' };
const nodeMap = { 'Root': treeRoot };
console.log("Building tree with elements:", elements.length);
elements.forEach((el, index) => {
const path = el.path;
const id = el.id || null;
const sliceName = el.sliceName || null;
console.log(`Element ${index}: path=${path}, id=${id}, sliceName=${sliceName}`);
if (!path) {
console.warn(`Skipping element ${index} with no path`);
return;
}
const parts = path.split('.');
let currentPath = '';
let parentNode = treeRoot;
for (let i = 0; i < parts.length; i++) {
const part = parts[i];
currentPath = i === 0 ? part : `${currentPath}.${part}`;
// For extensions, append sliceName to path if present
let nodeKey = part;
if (part === 'extension' && i === parts.length - 1 && sliceName) {
nodeKey = `${part}:${sliceName}`;
currentPath = id || currentPath; // Use id for precise matching in extensions
}
if (!nodeMap[currentPath]) {
const newNode = {
children: {},
element: null,
name: nodeKey,
path: currentPath
};
let parentPath = i === 0 ? 'Root' : parts.slice(0, i).join('.');
parentNode = nodeMap[parentPath] || treeRoot;
parentNode.children[nodeKey] = newNode;
nodeMap[currentPath] = newNode;
console.log(`Created node: path=${currentPath}, name=${nodeKey}`);
}
if (i === parts.length - 1) {
const targetNode = nodeMap[currentPath];
targetNode.element = el;
console.log(`Assigned element to node: path=${currentPath}, id=${id}, sliceName=${sliceName}`);
}
parentNode = nodeMap[currentPath];
}
});
const treeData = Object.values(treeRoot.children);
console.log("Tree data constructed:", treeData);
return treeData;
}
// Function to render a single node (and its children recursively) as an
function renderNodeAsLi(node, mustSupportPathsSet, level = 0) {
if (!node || !node.element) {
console.warn("Skipping render for invalid node:", node);
return '';
}
const el = node.element;
const path = el.path || 'N/A';
const id = el.id || null;
const sliceName = el.sliceName || null;
const min = el.min !== undefined ? el.min : '';
const max = el.max || '';
const short = el.short || '';
const definition = el.definition || '';
console.log(`Rendering node: path=${path}, id=${id}, sliceName=${sliceName}`);
console.log(` MustSupportPathsSet contains path: ${mustSupportPathsSet.has(path)}`);
if (id) {
console.log(` MustSupportPathsSet contains id: ${mustSupportPathsSet.has(id)}`);
}
// Check MS for path, id, or normalized extension path
let isMustSupport = mustSupportPathsSet.has(path) || (id && mustSupportPathsSet.has(id));
if (!isMustSupport && path.startsWith('Extension.extension')) {
const basePath = path.split(':')[0];
const baseId = id ? id.split(':')[0] : null;
isMustSupport = mustSupportPathsSet.has(basePath) || (baseId && mustSupportPathsSet.has(baseId));
console.log(` Extension check: basePath=${basePath}, baseId=${baseId}, isMustSupport=${isMustSupport}`);
}
console.log(` Final isMustSupport for ${path}: ${isMustSupport}`);
const liClass = isMustSupport ? 'list-group-item py-1 px-2 list-group-item-warning' : 'list-group-item py-1 px-2';
const mustSupportDisplay = isMustSupport ? '' : '';
const hasChildren = Object.keys(node.children).length > 0;
const collapseId = `collapse-${path.replace(/[\.\:\/\[\]\(\)]/g, '-')}`;
const padding = level * 20;
const pathStyle = `padding-left: ${padding}px; white-space: nowrap;`;
let typeString = 'N/A';
if (el.type && el.type.length > 0) {
typeString = el.type.map(t => {
let s = t.code || '';
let profiles = t.targetProfile || t.profile || [];
if (profiles.length > 0) {
const targetTypes = profiles.map(p => (p || '').split('/').pop()).filter(Boolean).join(', ');
if (targetTypes) {
s += `(${targetTypes})`;
}
}
return s;
}).join(' | ');
}
let childrenHtml = '';
if (hasChildren) {
childrenHtml += ``;
Object.values(node.children).sort((a, b) => (a.element?.path ?? a.name).localeCompare(b.element?.path ?? b.name)).forEach(childNode => {
childrenHtml += renderNodeAsLi(childNode, mustSupportPathsSet, level + 1);
});
childrenHtml += `
`;
}
let itemHtml = ``;
itemHtml += ``;
itemHtml += `
`;
itemHtml += ``;
if (hasChildren) {
itemHtml += ``;
}
itemHtml += ``;
itemHtml += `${node.name}
`;
itemHtml += `
`;
itemHtml += `
${min}..${max}
`;
itemHtml += `
${typeString}
`;
itemHtml += `
${mustSupportDisplay}
`;
let descriptionTooltipAttrs = '';
if (definition) {
const escapedDefinition = definition
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/\n/g, ' ');
descriptionTooltipAttrs = `data-bs-toggle="tooltip" data-bs-placement="top" title="${escapedDefinition}"`;
}
itemHtml += `
${short || (definition ? '(definition only)' : '')}
`;
itemHtml += `
`;
itemHtml += childrenHtml;
itemHtml += ``;
return itemHtml;
}