Skip to content

@storyshelf/affected

View as Markdown

@storyshelf/affected computes which stories are impacted by a change: git diff → bundler graph → reverse trace → affected story files. Both @storyshelf/core (server partition) and storyshelf (CLI computation) consume it, so the two sides always agree. It has zero runtime dependencies (Node builtins only) to keep the CI client light.

JSR JSR Score

Terminal window
npm i @storyshelf/affected
import {
computeAffected, // full pipeline: git + index + stats + trace (never throws)
traceAffected, // graph + changed files + story files -> affected, or null for full
selectAffectedStories, // stories + affected paths -> { render, inherit }
changedFiles, // git diff baseline..HEAD plus staged/untracked
gitHeadSha, // local git HEAD, or null without git
gitBranchName, // local git branch, or null without git
gitRepoStatus, // "ok" | "shallow" | "no-git"
localSha, // synthetic unique sha (LOCAL_SHA_PREFIX) for non-git checkouts
loadDepGraph, // preview-stats.json -> bidirectional DepGraph (null when unusable)
loadStoryImportPaths, // index.json/stories.json -> story import paths
} from "@storyshelf/affected";

computeAffected({ cwd, buildDir, baseSha, headSha, untraced?, statsFile? }) returns { affectedImportPaths: string[] | null, changedFiles, baselineSha, fullReason }. A null affected set means "render everything" — the contract is fail-open by design, which is what lets affected capture stay enabled by default.

Accepted stats shapes: Vite preview-stats.json module arrays (id/importedIds), record-shaped module maps, and Webpack-style reasons edges. Absolute stats paths match repo-relative changes by suffix.

One concern per file: types (graph/result shapes), stats (parse + index), graph edge helpers live in stats, git (diff, shallow guard, 10k cap), trace (glob matcher, global bailouts, BFS), select (partition), index (composition root).

You don’t install it directly — core and the CLI already depend on it. Reach for it when building a custom story source (Ladle/Histoire): implement the graph loader for your builder and reuse traceAffected/selectAffectedStories unchanged. See Affected capture.