mponent. if (!data.Components.Names) { // undefined, null, or empty data.Components.Names = ["default"]; } if (!data.Components.Assignments) { // undefined, null, or empty data.Components.Assignments = {}; } // Rebuild list of components. const componentsContainer = document.getElementById('components'); componentsContainer.replaceChildren(); // clear out previous state const assignSelect = document.getElementById('assign-select'); assignSelect.replaceChildren(); // clear out previous state const componentsList = document.createElement('ul'); componentsContainer.appendChild(componentsList); data.Components.Names.forEach((name, i) => { //
  • ■ name × const li = document.createElement('li'); li.index = i; // custom index field holds component index (for onClickDeleteComponent) componentsList.appendChild(li); // ■ name const span = document.createElement('span'); span.className = 'component'; span.style.color = componentColors[i % componentColors.length]; span.append('■ ', name) li.append(span); // × if (i > 0) { // the default component cannot be deleted const xSpan = document.createElement('span'); xSpan.className = 'delete'; xSpan.append(' ×') xSpan.addEventListener('click', onClickDeleteComponent); li.append(xSpan); } // Add component to the assignment dropdown. assignSelect.add(new Option(name, null)); }) // Rebuild list of decls grouped by file. const filesContainer = document.getElementById('files'); filesContainer.replaceChildren(); // clear out previous state data.Files.forEach(fileJson => { filesContainer.appendChild(createFileDiv(fileJson)); }); // Display strongly connected components. const deps = document.getElementById('deps'); deps.replaceChildren(); // clear out previous state const depsList = document.createElement('ul'); deps.append(depsList); // Be explicit if there are no component dependencies. if (data.Edges.length == 0) { const li = document.createElement('li'); depsList.append(li); li.append("No dependencies"); return; } // List all sets of mutually dependent components. data.Cycles.forEach((scc) => { const item = document.createElement('li'); item.append("⚠ Component cycle: " + scc.map(index => data.Components.Names[index]).join(', ')) depsList.append(item); }) // Show intercomponent edges. data.Edges.forEach((edge) => { const edgeItem = document.createElement('li'); depsList.append(edgeItem); // component edge const from = data.Components.Names[edge.From]; const to = data.Components.Names[edge.To]; edgeItem.append((edge.Cyclic ? "⚠ " : "") + from + " ➤ " + to); // sublist of symbol references that induced the edge const refsList = document.createElement('ul'); edgeItem.appendChild(refsList); refsList.className = 'refs-list'; edge.Refs.forEach(ref => { refsList.appendChild(createRefItem(ref)); }); }) } /** * makeURL returns a URL string with the specified path, * but preserving the current page's query parameters (view, pkg). */ function makeURL(path) { const url = new URL(window.location.href); url.pathname = url.pathname.substring(0, url.pathname.lastIndexOf('/')) + path; return url.href; } /** createFileDiv creates a
    for a fileJSON object. */ function createFileDiv(fileData) { // Create the main container for the file entry. const fileContainer = document.createElement('div'); fileContainer.className = 'file-node'; // Create and append the file's base name as a para. const para = document.createElement('p'); fileContainer.appendChild(para); // The file's checkbox applies in bulk to all specs within it. var specCheckboxes = []; const fileCheckbox = document.createElement('input'); fileCheckbox.type = 'checkbox'; fileCheckbox.addEventListener('click', (event) => { // Select/deselect all specs belonging to the file. const checked = event.target.checked; specCheckboxes.forEach(checkbox => { checkbox.checked = checked; }); }) para.appendChild(fileCheckbox); para.append("File "); // Link file name to start of file. const baseName = document.createElement('a'); para.appendChild(baseName); baseName.className = 'file-link'; baseName.textContent = fileData.Base; baseName.addEventListener('click', () => httpGET(fileData.URL)); // Process declarations if they exist. if (fileData.Decls && fileData.Decls.length > 0) { const declsList = document.createElement('ul'); declsList.className = 'decls-list'; // For now we flatten out the decl/spec grouping. fileData.Decls.forEach(decl => { if (decl.Specs && decl.Specs.length > 0) { decl.Specs.forEach(spec => { declsList.appendChild(createSpecItem(decl.Kind, spec, specCheckboxes)); }); } }); fileContainer.appendChild(declsList); } return fileContainer; } /** createSpecItem creates an
  • element for a specJSON object (one declared name). */ function createSpecItem(kind, specData, checkboxes) { //
  • myfunc... const specItem = document.createElement('li'); specItem.className = 'spec-node'; specItem.dataset.name = specData.Name; // custom .name field holds symbol's unique logical name // First child is a checkbox. const specCheckbox = document.createElement('input'); specCheckbox.type = 'checkbox'; specItem.appendChild(specCheckbox); checkboxes.push(specCheckbox); // Next is the component assignment color swatch. const assignSpan = document.createElement('span'); assignSpan.className = 'component-swatch'; assignSpan.textContent = "■"; { var index = data.Components.Assignments[specData.Name]; // may be undefined if (!index) { index = 0; // default } assignSpan.style.color = componentColors[index % componentColors.length]; assignSpan.title = "Component " + data.Components.Names[index]; // tooltip } specItem.appendChild(assignSpan); // Encircle the func/var/const/type indicator. const symbolSpan = document.createElement('span'); const symbol = String.fromCodePoint(kind.codePointAt(0) - 'a'.codePointAt(0) + 'ⓐ'.codePointAt(0)); symbolSpan.title = kind; // tooltip symbolSpan.append(`${symbol} `); specItem.append(symbolSpan); // Link name to declaration. const specName = document.createElement('a'); specItem.appendChild(specName); specName.textContent = ` ${specData.Name}`; specName.addEventListener('click', () => httpGET(specData.URL)); return specItem; } /** createRefItem creates an
  • element for a refJSON object (a reference). */ function createRefItem(refData) { const refItem = document.createElement('li'); refItem.className = 'ref-node'; // Link (from -> to) to the reference in from. const refLink = document.createElement('a'); refItem.appendChild(refLink); refLink.addEventListener('click', () => httpGET(refData.URL)); refLink.textContent = "${refData.From} ➤ ${refData.To}"; return refItem; } /** componentColors is a palette of dark, high-contrast colors. */ const componentColors = [ "#298429", "#4B4B8F", "#AD2C2C", "#A62CA6", "#6E65AF", "#D15050", "#2CA6A6", "#C55656", "#7B8C58", "#587676", "#B95EE1", "#AF6D41", ];