Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions dist/report-assets.js

Large diffs are not rendered by default.

46 changes: 45 additions & 1 deletion dist/report.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,16 @@ ${safeCssContent}
</svg>
<input type="search" id="search" placeholder="Search packages..." />
</div>
<div class="view-switch" id="view-switch">
<button
type="button"
class="view-switch-btn"
id="view-graph-btn"
data-view="graph"
>
Graph View
</button>
</div>
<button
type="button"
class="filters-toggle"
Expand Down Expand Up @@ -319,7 +329,41 @@ ${safeCssContent}

<!-- Main Content -->
<main class="main-content">
<div id="dependency-list" class="dependency-grid"></div>
<section class="view-panel active" id="list-view" data-view="list" aria-hidden="false">
<div id="dependency-list" class="dependency-grid"></div>
</section>
<section class="view-panel" id="graph-view" data-view="graph" aria-hidden="true">
<div class="graph-canvas-shell" id="graph-canvas-shell">
<canvas id="graph-canvas"></canvas>
<button type="button" class="graph-overlay graph-back-btn" id="graph-back-btn">Back to List</button>
<div class="graph-overlay graph-overlay-left" id="graph-workspace-wrap">
<label class="graph-workspace-label" for="graph-workspace">Workspace</label>
<select id="graph-workspace" class="graph-workspace-select"></select>
</div>
<div class="graph-controls graph-overlay graph-overlay-right" id="graph-controls">
<div class="zoom-controls">
<button type="button" class="graph-control-btn" data-action="zoom-in" aria-label="Zoom In">+</button>
<button type="button" class="graph-control-btn" data-action="zoom-out" aria-label="Zoom Out">−</button>
</div>
<div class="dpad">
<button type="button" class="graph-control-btn up" data-action="pan-up" aria-label="Pan Up">▲</button>
<button type="button" class="graph-control-btn left" data-action="pan-left" aria-label="Pan Left">◀</button>
<div class="center-spacer" aria-hidden="true"></div>
<button type="button" class="graph-control-btn right" data-action="pan-right" aria-label="Pan Right">▶</button>
<button type="button" class="graph-control-btn down" data-action="pan-down" aria-label="Pan Down">▼</button>
</div>
<button type="button" class="graph-control-btn reset-btn" data-action="reset">reset</button>
</div>
<div class="graph-popover" id="graph-popover" hidden>
<div class="graph-popover-name" id="graph-popover-name"></div>
<div class="graph-popover-meta" id="graph-popover-version"></div>
<div class="graph-popover-meta" id="graph-popover-license"></div>
<div class="graph-popover-meta" id="graph-popover-vulns"></div>
<div class="graph-popover-meta" id="graph-popover-amplification"></div>
<button type="button" class="graph-popover-action" id="graph-open-list">Open in List</button>
</div>
</div>
</section>
</main>

<footer class="report-footer">
Expand Down
23 changes: 22 additions & 1 deletion dist/runners/lockfileGraph.js
Original file line number Diff line number Diff line change
Expand Up @@ -565,11 +565,32 @@ function resolveNpmPackagePath(fromPackageKey, depName, packages) {
const rootCandidate = `node_modules/${depName}`;
return rootCandidate in packages ? rootCandidate : undefined;
}
/**
* Resolve an npm lockfile package key to the absolute filesystem path where that package would be installed under a given lock directory.
*
* @param packageKey - The package key from a lockfile (e.g., a normalized/package-relative path or package identifier).
* @param lockDir - The lockfile directory to treat as the installation root.
* @returns The absolute path inside `lockDir` corresponding to `packageKey` if it resolves to a location contained within `lockDir`, `undefined` otherwise.
*/
function resolveNpmInstalledPath(packageKey, lockDir) {
const normalizedKey = normalizeLockPackageKey(packageKey);
if (!normalizedKey)
return undefined;
return path_1.default.join(lockDir, ...normalizedKey.split('/'));
const segments = normalizedKey.split('/').filter(Boolean);
if (segments.length === 0)
return undefined;
for (const segment of segments) {
if (segment === '.' || segment === '..')
return undefined;
if (path_1.default.isAbsolute(segment))
return undefined;
}
const lockRoot = path_1.default.resolve(lockDir);
const resolved = path_1.default.resolve(lockRoot, ...segments);
const relative = path_1.default.relative(lockRoot, resolved);
if (relative.startsWith('..') || path_1.default.isAbsolute(relative))
return undefined;
return resolved;
}
/**
* Normalize a legacy npm lockfile node into a ResolvedNode.
Expand Down
2 changes: 1 addition & 1 deletion report-ui/dist/report.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion report-ui/dist/report.iife.js

Large diffs are not rendered by default.

Loading