@storyshelf/affected 0.7.0 → 0.9.0-next-d2cc082

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/git.d.mts CHANGED
@@ -1,6 +1,5 @@
1
1
  import __tsdown_shims_path from 'node:path';
2
2
  import __tsdown_shims_url from 'node:url';
3
- //#region src/git.d.ts
4
3
  /** Upper bound on changed files before falling back to a full render. */
5
4
  declare const MAX_CHANGED_FILES = 10000;
6
5
  /** Prefix marking CLI-synthesized identities for checkouts without git. */
@@ -42,6 +41,5 @@ declare function gitHeadSha(cwd: string): string | null;
42
41
  declare function gitBranchName(cwd: string): string | null;
43
42
  /** Synthesize a unique local sha for checkouts without git. */
44
43
  declare function localSha(): string;
45
- //#endregion
46
44
  export { GitRepoStatus, LOCAL_BRANCH, LOCAL_SHA_PREFIX, MAX_CHANGED_FILES, changedFiles, gitBranchName, gitHeadSha, gitRepoStatus, isShallowRepo, localSha };
47
45
  //# sourceMappingURL=git.d.mts.map
package/dist/git.mjs CHANGED
@@ -3,7 +3,7 @@ import "node:url";
3
3
  import.meta.url;
4
4
  import { execFileSync } from "node:child_process";
5
5
  import { randomUUID } from "node:crypto";
6
- //#region src/git.ts
6
+ // src/git.ts
7
7
  /** Upper bound on changed files before falling back to a full render. */
8
8
  const MAX_CHANGED_FILES = 1e4;
9
9
  /** Prefix marking CLI-synthesized identities for checkouts without git. */
@@ -115,7 +115,6 @@ function gitBranchName(cwd) {
115
115
  function localSha() {
116
116
  return `${LOCAL_SHA_PREFIX}${randomUUID().replaceAll("-", "").slice(0, 12)}`;
117
117
  }
118
- //#endregion
119
118
  export { LOCAL_BRANCH, LOCAL_SHA_PREFIX, MAX_CHANGED_FILES, changedFiles, gitBranchName, gitHeadSha, gitRepoStatus, isShallowRepo, localSha };
120
119
 
121
120
  //# sourceMappingURL=git.mjs.map
package/dist/index.d.mts CHANGED
@@ -6,7 +6,6 @@ import { STATS_FILENAME, buildGraph, graphModulesFor, loadDepGraph, loadStoryImp
6
6
  import { matchesAnyGlob, traceAffected } from "./trace.mjs";
7
7
  import { StoryPartition, selectAffectedStories } from "./select.mjs";
8
8
  import { PackageUsage, TrackedPackage, extractPackageUsage } from "./usage.mjs";
9
- //#region src/index.d.ts
10
9
  /**
11
10
  * Compute the affected story set for an upload. Never throws: every failure
12
11
  * degrades to a full render with a machine-readable `fullReason`, so
@@ -15,6 +14,5 @@ import { PackageUsage, TrackedPackage, extractPackageUsage } from "./usage.mjs";
15
14
  * @param input - Repository root, build dir, revisions, and trace options.
16
15
  */
17
16
  declare function computeAffected(input: AffectedInput): Promise<AffectedResult>;
18
- //#endregion
19
17
  export { type AffectedInput, type AffectedResult, type DepGraph, type GitRepoStatus, LOCAL_BRANCH, LOCAL_SHA_PREFIX, MAX_CHANGED_FILES, type PackageUsage, STATS_FILENAME, type StoryLike, type StoryPartition, type TraceOptions, type TrackedPackage, buildGraph, changedFiles, computeAffected, extractPackageUsage, gitBranchName, gitHeadSha, gitRepoStatus, graphModulesFor, isShallowRepo, loadDepGraph, loadStoryImportPaths, localSha, matchesAnyGlob, normalizePath, selectAffectedStories, statsPathFor, traceAffected };
20
18
  //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs CHANGED
@@ -6,7 +6,7 @@ import { STATS_FILENAME, buildGraph, graphModulesFor, loadDepGraph, loadStoryImp
6
6
  import { matchesAnyGlob, traceAffected } from "./trace.mjs";
7
7
  import { selectAffectedStories } from "./select.mjs";
8
8
  import { extractPackageUsage } from "./usage.mjs";
9
- //#region src/index.ts
9
+ // src/index.ts
10
10
  /**
11
11
  * Compute the affected story set for an upload. Never throws: every failure
12
12
  * degrades to a full render with a machine-readable `fullReason`, so
@@ -70,7 +70,6 @@ async function computeSelective(input) {
70
70
  return fullResult(changed, input.baseSha, reason);
71
71
  }
72
72
  }
73
- //#endregion
74
73
  export { LOCAL_BRANCH, LOCAL_SHA_PREFIX, MAX_CHANGED_FILES, STATS_FILENAME, buildGraph, changedFiles, computeAffected, extractPackageUsage, gitBranchName, gitHeadSha, gitRepoStatus, graphModulesFor, isShallowRepo, loadDepGraph, loadStoryImportPaths, localSha, matchesAnyGlob, normalizePath, selectAffectedStories, statsPathFor, traceAffected };
75
74
 
76
75
  //# sourceMappingURL=index.mjs.map
package/dist/select.d.mts CHANGED
@@ -1,7 +1,6 @@
1
1
  import __tsdown_shims_path from 'node:path';
2
2
  import __tsdown_shims_url from 'node:url';
3
3
  import { StoryLike } from "./types.mjs";
4
- //#region src/select.d.ts
5
4
  /** Stories split into render-now versus inherit-from-baseline sets. */
6
5
  interface StoryPartition<T> {
7
6
  /** Stories to capture in this build. */
@@ -19,6 +18,5 @@ interface StoryPartition<T> {
19
18
  * @param affectedImportPaths - Affected import paths, or `null` for full.
20
19
  */
21
20
  declare function selectAffectedStories<T extends StoryLike>(stories: readonly T[], affectedImportPaths: readonly string[] | null): StoryPartition<T>;
22
- //#endregion
23
21
  export { StoryPartition, selectAffectedStories };
24
22
  //# sourceMappingURL=select.d.mts.map
package/dist/select.mjs CHANGED
@@ -2,7 +2,7 @@ import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
4
  import { normalizePath } from "./stats.mjs";
5
- //#region src/select.ts
5
+ // src/select.ts
6
6
  /** Sort stories into render versus inherit buckets for an affected set. */
7
7
  function partitionByPath(stories, affected, render, inherit) {
8
8
  for (const story of stories) {
@@ -38,7 +38,6 @@ function selectAffectedStories(stories, affectedImportPaths) {
38
38
  inherit
39
39
  };
40
40
  }
41
- //#endregion
42
41
  export { selectAffectedStories };
43
42
 
44
43
  //# sourceMappingURL=select.mjs.map
package/dist/stats.d.mts CHANGED
@@ -1,7 +1,6 @@
1
1
  import __tsdown_shims_path from 'node:path';
2
2
  import __tsdown_shims_url from 'node:url';
3
3
  import { DepGraph } from "./types.mjs";
4
- //#region src/stats.d.ts
5
4
  /** Basename of the Vite stats file emitted next to a built Storybook. */
6
5
  declare const STATS_FILENAME = "preview-stats.json";
7
6
  /** A single module entry in a stats file (Vite or Webpack shape). */
@@ -42,6 +41,5 @@ declare function statsPathFor(cwd: string, buildDir: string, override?: string):
42
41
  declare function loadStoryImportPaths(cwd: string, buildDir: string): Promise<string[]>;
43
42
  /** Find graph modules referring to repo-relative file `target`. */
44
43
  declare function graphModulesFor(graph: DepGraph, target: string): string[];
45
- //#endregion
46
44
  export { STATS_FILENAME, buildGraph, graphModulesFor, loadDepGraph, loadStoryImportPaths, normalizePath, statsPathFor };
47
45
  //# sourceMappingURL=stats.d.mts.map
package/dist/stats.mjs CHANGED
@@ -1,9 +1,8 @@
1
- import "node:path";
1
+ import { join, resolve } from "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
4
  import { readFile } from "node:fs/promises";
5
- import { join, resolve } from "node:path";
6
- //#region src/stats.ts
5
+ // src/stats.ts
7
6
  /** Basename of the Vite stats file emitted next to a built Storybook. */
8
7
  const STATS_FILENAME = "preview-stats.json";
9
8
  /** Candidate index files listing a built Storybook's stories. */
@@ -166,7 +165,6 @@ function graphModulesFor(graph, target) {
166
165
  for (const file of Object.keys(graph.importedBy)) if (matchesFile(file, target) && !matched.includes(file)) matched.push(file);
167
166
  return matched;
168
167
  }
169
- //#endregion
170
168
  export { STATS_FILENAME, buildGraph, graphModulesFor, loadDepGraph, loadStoryImportPaths, normalizePath, statsPathFor, stripQueryAndLoader };
171
169
 
172
170
  //# sourceMappingURL=stats.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"stats.mjs","names":["record"],"sources":["../src/stats.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport type { DepGraph } from \"./types.ts\";\n\n/** Basename of the Vite stats file emitted next to a built Storybook. */\nexport const STATS_FILENAME = \"preview-stats.json\";\n\n/** Candidate index files listing a built Storybook's stories. */\nconst INDEX_CANDIDATES = [\"stories.json\", \"index.json\"];\n\n/** A single module entry in a stats file (Vite or Webpack shape). */\ninterface StatsModule {\n id?: unknown;\n name?: unknown;\n identifier?: unknown;\n imported?: unknown;\n importedIds?: unknown;\n dependencies?: unknown;\n reasons?: unknown;\n}\n\ninterface StoryIndex {\n entries?: Record<string, { importPath?: unknown }>;\n}\n\n/**\n * Strip bundler module-id decoration so sub-modules fold into their file:\n * webpack loader chains (`a-loader!b-loader??opts!./Button.vue`) keep only\n * the resource after the last `!`, and `?query` suffixes\n * (`Button.vue?vue&type=script`, `Card.svelte?svelte&type=style`) are dropped.\n */\nexport function stripQueryAndLoader(value: string): string {\n const resource = value.slice(value.lastIndexOf(\"!\") + 1);\n const queryStart = resource.indexOf(\"?\");\n return queryStart === -1 ? resource : resource.slice(0, queryStart);\n}\n\n/** Normalize a stats path to a repo-relative posix form for comparison. */\nexport function normalizePath(value: string): string {\n return stripQueryAndLoader(value)\n .replaceAll(\"\\\\\", \"/\")\n .replaceAll(/^\\.\\//gu, \"\")\n .replaceAll(/^\\//gu, \"\");\n}\n\n/** True when stats module `candidate` refers to repo-relative file `target`. */\nfunction matchesFile(candidate: string, target: string): boolean {\n if (candidate === target) {\n return true;\n }\n return candidate.endsWith(`/${target}`);\n}\n\n/** Coerce an unknown stats value to a list of normalized paths. */\nfunction asPathList(value: unknown): string[] {\n if (!Array.isArray(value)) {\n return [];\n }\n const paths: string[] = [];\n for (const entry of value) {\n if (typeof entry === \"string\" && entry.length > 0) {\n paths.push(normalizePath(entry));\n }\n }\n return paths;\n}\n\n/** Read a non-empty string field from a stats module entry. */\nfunction stringField(entry: StatsModule, key: \"id\" | \"name\" | \"identifier\"): string | null {\n const value = entry[key];\n return typeof value === \"string\" && value.length > 0 ? value : null;\n}\n\n/** Read the file a stats module entry refers to, if any. */\nfunction moduleFile(entry: StatsModule): string | null {\n const raw =\n stringField(entry, \"id\") ?? stringField(entry, \"name\") ?? stringField(entry, \"identifier\");\n return raw === null ? null : normalizePath(raw);\n}\n\n/** Forward imports declared by a stats module entry, if any. */\nfunction moduleImports(entry: StatsModule): string[] {\n return asPathList(entry.imported ?? entry.importedIds ?? entry.dependencies);\n}\n\n/** Dependent names declared via Webpack-style `reasons`, if any. */\nfunction moduleReasonNames(entry: StatsModule): string[] {\n if (!Array.isArray(entry.reasons)) {\n return [];\n }\n const names: string[] = [];\n for (const reason of entry.reasons) {\n if (typeof reason === \"object\" && reason !== null) {\n const record = reason as Record<string, unknown>;\n const name = record[\"moduleName\"] ?? record[\"module\"];\n if (typeof name === \"string\" && name.length > 0) {\n names.push(normalizePath(name));\n }\n }\n }\n return names;\n}\n\n/** Attach a record-shaped module entry to its name. */\nfunction entryWithName(name: string, value: unknown): StatsModule {\n if (typeof value === \"object\" && value !== null) {\n return { name, ...(value as StatsModule) };\n }\n return { name };\n}\n\n/** Extract module entries from a parsed stats document of unknown shape. */\nfunction moduleEntries(document: unknown): StatsModule[] {\n if (typeof document !== \"object\" || document === null) {\n return [];\n }\n const record = document as Record<string, unknown>;\n const raw = record[\"modules\"];\n if (Array.isArray(raw)) {\n return raw.filter((entry): entry is StatsModule => typeof entry === \"object\");\n }\n if (typeof raw === \"object\" && raw !== null) {\n return Object.entries(raw as Record<string, unknown>).map(([name, value]) =>\n entryWithName(name, value),\n );\n }\n return [];\n}\n\n/** Record one directed edge in the graph under construction. */\nfunction addEdge(\n imports: Map<string, Set<string>>,\n importedBy: Map<string, Set<string>>,\n from: string,\n to: string,\n): void {\n if (from === to) {\n return;\n }\n const forward = imports.get(from) ?? new Set<string>();\n forward.add(to);\n imports.set(from, forward);\n const reverse = importedBy.get(to) ?? new Set<string>();\n reverse.add(from);\n importedBy.set(to, reverse);\n}\n\n/** Add one stats entry's edges to the graph under construction. */\nfunction addEntryEdges(\n imports: Map<string, Set<string>>,\n importedBy: Map<string, Set<string>>,\n entry: StatsModule,\n): void {\n const file = moduleFile(entry);\n if (!file) {\n return;\n }\n for (const imported of moduleImports(entry)) {\n addEdge(imports, importedBy, file, imported);\n }\n for (const dependent of moduleReasonNames(entry)) {\n addEdge(imports, importedBy, dependent, file);\n }\n}\nfunction toGraph(\n imports: Map<string, Set<string>>,\n importedBy: Map<string, Set<string>>,\n): DepGraph {\n return {\n imports: Object.fromEntries([...imports].map(([file, set]) => [file, [...set].toSorted()])),\n importedBy: Object.fromEntries(\n [...importedBy].map(([file, set]) => [file, [...set].toSorted()]),\n ),\n };\n}\n\n/**\n * Build a bidirectional dependency graph from parsed stats modules.\n *\n * @param entries - Module entries from a Vite or Webpack stats document.\n * @returns Bidirectional graph, or `null` when no usable edges exist.\n */\nexport function buildGraph(entries: StatsModule[]): DepGraph | null {\n const imports = new Map<string, Set<string>>();\n const importedBy = new Map<string, Set<string>>();\n for (const entry of entries) {\n addEntryEdges(imports, importedBy, entry);\n }\n if (imports.size === 0) {\n return null;\n }\n return toGraph(imports, importedBy);\n}\n\n/**\n * Load and parse a stats file into a dependency graph.\n *\n * @param statsPath - Absolute or cwd-relative path to the stats JSON file.\n * @returns Graph, or `null` when the file is missing or unrecognized.\n */\nexport async function loadDepGraph(statsPath: string): Promise<DepGraph | null> {\n let raw: string;\n try {\n raw = await readFile(statsPath, \"utf8\");\n } catch {\n return null;\n }\n let document: unknown;\n try {\n document = JSON.parse(raw) as unknown;\n } catch {\n return null;\n }\n return buildGraph(moduleEntries(document));\n}\n\n/** Resolve the stats file path for a built Storybook directory. */\nexport function statsPathFor(cwd: string, buildDir: string, override?: string): string {\n if (override) {\n return resolve(cwd, override);\n }\n return join(resolve(cwd, buildDir), STATS_FILENAME);\n}\n\n/**\n * Load the deduplicated story import paths from a built Storybook's index.\n *\n * @param cwd - Repository root.\n * @param buildDir - Built Storybook directory.\n * @returns Normalized import paths; throws when no index is readable.\n */\nexport async function loadStoryImportPaths(cwd: string, buildDir: string): Promise<string[]> {\n const root = resolve(cwd, buildDir);\n const documents = await Promise.all(\n INDEX_CANDIDATES.map(async (name) => {\n try {\n return JSON.parse(await readFile(join(root, name), \"utf8\")) as StoryIndex;\n } catch {\n return null;\n }\n }),\n );\n const found = documents.find((document) => document !== null);\n if (!found?.entries) {\n throw new Error(`No Storybook index found in ${root}`);\n }\n const paths = new Set<string>();\n for (const entry of Object.values(found.entries)) {\n if (typeof entry.importPath === \"string\" && entry.importPath.length > 0) {\n paths.add(normalizePath(entry.importPath));\n }\n }\n return [...paths].toSorted();\n}\n\n/** Find graph modules referring to repo-relative file `target`. */\nexport function graphModulesFor(graph: DepGraph, target: string): string[] {\n const matched: string[] = [];\n for (const file of Object.keys(graph.imports)) {\n if (matchesFile(file, target)) {\n matched.push(file);\n }\n }\n for (const file of Object.keys(graph.importedBy)) {\n if (matchesFile(file, target) && !matched.includes(file)) {\n matched.push(file);\n }\n }\n return matched;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"stats.mjs","names":["record"],"sources":["../src/stats.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport type { DepGraph } from \"./types.ts\";\n\n/** Basename of the Vite stats file emitted next to a built Storybook. */\nexport const STATS_FILENAME = \"preview-stats.json\";\n\n/** Candidate index files listing a built Storybook's stories. */\nconst INDEX_CANDIDATES = [\"stories.json\", \"index.json\"];\n\n/** A single module entry in a stats file (Vite or Webpack shape). */\ninterface StatsModule {\n id?: unknown;\n name?: unknown;\n identifier?: unknown;\n imported?: unknown;\n importedIds?: unknown;\n dependencies?: unknown;\n reasons?: unknown;\n}\n\ninterface StoryIndex {\n entries?: Record<string, { importPath?: unknown }>;\n}\n\n/**\n * Strip bundler module-id decoration so sub-modules fold into their file:\n * webpack loader chains (`a-loader!b-loader??opts!./Button.vue`) keep only\n * the resource after the last `!`, and `?query` suffixes\n * (`Button.vue?vue&type=script`, `Card.svelte?svelte&type=style`) are dropped.\n */\nexport function stripQueryAndLoader(value: string): string {\n const resource = value.slice(value.lastIndexOf(\"!\") + 1);\n const queryStart = resource.indexOf(\"?\");\n return queryStart === -1 ? resource : resource.slice(0, queryStart);\n}\n\n/** Normalize a stats path to a repo-relative posix form for comparison. */\nexport function normalizePath(value: string): string {\n return stripQueryAndLoader(value)\n .replaceAll(\"\\\\\", \"/\")\n .replaceAll(/^\\.\\//gu, \"\")\n .replaceAll(/^\\//gu, \"\");\n}\n\n/** True when stats module `candidate` refers to repo-relative file `target`. */\nfunction matchesFile(candidate: string, target: string): boolean {\n if (candidate === target) {\n return true;\n }\n return candidate.endsWith(`/${target}`);\n}\n\n/** Coerce an unknown stats value to a list of normalized paths. */\nfunction asPathList(value: unknown): string[] {\n if (!Array.isArray(value)) {\n return [];\n }\n const paths: string[] = [];\n for (const entry of value) {\n if (typeof entry === \"string\" && entry.length > 0) {\n paths.push(normalizePath(entry));\n }\n }\n return paths;\n}\n\n/** Read a non-empty string field from a stats module entry. */\nfunction stringField(entry: StatsModule, key: \"id\" | \"name\" | \"identifier\"): string | null {\n const value = entry[key];\n return typeof value === \"string\" && value.length > 0 ? value : null;\n}\n\n/** Read the file a stats module entry refers to, if any. */\nfunction moduleFile(entry: StatsModule): string | null {\n const raw =\n stringField(entry, \"id\") ?? stringField(entry, \"name\") ?? stringField(entry, \"identifier\");\n return raw === null ? null : normalizePath(raw);\n}\n\n/** Forward imports declared by a stats module entry, if any. */\nfunction moduleImports(entry: StatsModule): string[] {\n return asPathList(entry.imported ?? entry.importedIds ?? entry.dependencies);\n}\n\n/** Dependent names declared via Webpack-style `reasons`, if any. */\nfunction moduleReasonNames(entry: StatsModule): string[] {\n if (!Array.isArray(entry.reasons)) {\n return [];\n }\n const names: string[] = [];\n for (const reason of entry.reasons) {\n if (typeof reason === \"object\" && reason !== null) {\n const record = reason as Record<string, unknown>;\n const name = record[\"moduleName\"] ?? record[\"module\"];\n if (typeof name === \"string\" && name.length > 0) {\n names.push(normalizePath(name));\n }\n }\n }\n return names;\n}\n\n/** Attach a record-shaped module entry to its name. */\nfunction entryWithName(name: string, value: unknown): StatsModule {\n if (typeof value === \"object\" && value !== null) {\n return { name, ...(value as StatsModule) };\n }\n return { name };\n}\n\n/** Extract module entries from a parsed stats document of unknown shape. */\nfunction moduleEntries(document: unknown): StatsModule[] {\n if (typeof document !== \"object\" || document === null) {\n return [];\n }\n const record = document as Record<string, unknown>;\n const raw = record[\"modules\"];\n if (Array.isArray(raw)) {\n return raw.filter((entry): entry is StatsModule => typeof entry === \"object\");\n }\n if (typeof raw === \"object\" && raw !== null) {\n return Object.entries(raw as Record<string, unknown>).map(([name, value]) =>\n entryWithName(name, value),\n );\n }\n return [];\n}\n\n/** Record one directed edge in the graph under construction. */\nfunction addEdge(\n imports: Map<string, Set<string>>,\n importedBy: Map<string, Set<string>>,\n from: string,\n to: string,\n): void {\n if (from === to) {\n return;\n }\n const forward = imports.get(from) ?? new Set<string>();\n forward.add(to);\n imports.set(from, forward);\n const reverse = importedBy.get(to) ?? new Set<string>();\n reverse.add(from);\n importedBy.set(to, reverse);\n}\n\n/** Add one stats entry's edges to the graph under construction. */\nfunction addEntryEdges(\n imports: Map<string, Set<string>>,\n importedBy: Map<string, Set<string>>,\n entry: StatsModule,\n): void {\n const file = moduleFile(entry);\n if (!file) {\n return;\n }\n for (const imported of moduleImports(entry)) {\n addEdge(imports, importedBy, file, imported);\n }\n for (const dependent of moduleReasonNames(entry)) {\n addEdge(imports, importedBy, dependent, file);\n }\n}\nfunction toGraph(\n imports: Map<string, Set<string>>,\n importedBy: Map<string, Set<string>>,\n): DepGraph {\n return {\n imports: Object.fromEntries([...imports].map(([file, set]) => [file, [...set].toSorted()])),\n importedBy: Object.fromEntries(\n [...importedBy].map(([file, set]) => [file, [...set].toSorted()]),\n ),\n };\n}\n\n/**\n * Build a bidirectional dependency graph from parsed stats modules.\n *\n * @param entries - Module entries from a Vite or Webpack stats document.\n * @returns Bidirectional graph, or `null` when no usable edges exist.\n */\nexport function buildGraph(entries: StatsModule[]): DepGraph | null {\n const imports = new Map<string, Set<string>>();\n const importedBy = new Map<string, Set<string>>();\n for (const entry of entries) {\n addEntryEdges(imports, importedBy, entry);\n }\n if (imports.size === 0) {\n return null;\n }\n return toGraph(imports, importedBy);\n}\n\n/**\n * Load and parse a stats file into a dependency graph.\n *\n * @param statsPath - Absolute or cwd-relative path to the stats JSON file.\n * @returns Graph, or `null` when the file is missing or unrecognized.\n */\nexport async function loadDepGraph(statsPath: string): Promise<DepGraph | null> {\n let raw: string;\n try {\n raw = await readFile(statsPath, \"utf8\");\n } catch {\n return null;\n }\n let document: unknown;\n try {\n document = JSON.parse(raw) as unknown;\n } catch {\n return null;\n }\n return buildGraph(moduleEntries(document));\n}\n\n/** Resolve the stats file path for a built Storybook directory. */\nexport function statsPathFor(cwd: string, buildDir: string, override?: string): string {\n if (override) {\n return resolve(cwd, override);\n }\n return join(resolve(cwd, buildDir), STATS_FILENAME);\n}\n\n/**\n * Load the deduplicated story import paths from a built Storybook's index.\n *\n * @param cwd - Repository root.\n * @param buildDir - Built Storybook directory.\n * @returns Normalized import paths; throws when no index is readable.\n */\nexport async function loadStoryImportPaths(cwd: string, buildDir: string): Promise<string[]> {\n const root = resolve(cwd, buildDir);\n const documents = await Promise.all(\n INDEX_CANDIDATES.map(async (name) => {\n try {\n return JSON.parse(await readFile(join(root, name), \"utf8\")) as StoryIndex;\n } catch {\n return null;\n }\n }),\n );\n const found = documents.find((document) => document !== null);\n if (!found?.entries) {\n throw new Error(`No Storybook index found in ${root}`);\n }\n const paths = new Set<string>();\n for (const entry of Object.values(found.entries)) {\n if (typeof entry.importPath === \"string\" && entry.importPath.length > 0) {\n paths.add(normalizePath(entry.importPath));\n }\n }\n return [...paths].toSorted();\n}\n\n/** Find graph modules referring to repo-relative file `target`. */\nexport function graphModulesFor(graph: DepGraph, target: string): string[] {\n const matched: string[] = [];\n for (const file of Object.keys(graph.imports)) {\n if (matchesFile(file, target)) {\n matched.push(file);\n }\n }\n for (const file of Object.keys(graph.importedBy)) {\n if (matchesFile(file, target) && !matched.includes(file)) {\n matched.push(file);\n }\n }\n return matched;\n}\n"],"mappings":"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"}
package/dist/trace.d.mts CHANGED
@@ -1,7 +1,6 @@
1
1
  import __tsdown_shims_path from 'node:path';
2
2
  import __tsdown_shims_url from 'node:url';
3
3
  import { DepGraph, TraceOptions } from "./types.mjs";
4
- //#region src/trace.d.ts
5
4
  /** True when `path` matches any of the given glob patterns. */
6
5
  declare function matchesAnyGlob(path: string, patterns: readonly string[]): boolean;
7
6
  /**
@@ -14,6 +13,5 @@ declare function matchesAnyGlob(path: string, patterns: readonly string[]): bool
14
13
  * @returns Affected story files, or `null` when everything must render.
15
14
  */
16
15
  declare function traceAffected(graph: DepGraph, changedFiles: string[], storyFiles: readonly string[], options?: TraceOptions): string[] | null;
17
- //#endregion
18
16
  export { matchesAnyGlob, traceAffected };
19
17
  //# sourceMappingURL=trace.d.mts.map
package/dist/trace.mjs CHANGED
@@ -2,7 +2,7 @@ import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
4
  import { graphModulesFor } from "./stats.mjs";
5
- //#region src/trace.ts
5
+ // src/trace.ts
6
6
  /** Basenames whose change invalidates every story (global render setup). */
7
7
  const GLOBAL_BASENAMES = /* @__PURE__ */ new Set([
8
8
  "preview.js",
@@ -33,8 +33,7 @@ const LOCKFILE_BASENAMES = /* @__PURE__ */ new Set([
33
33
  "pnpm-lock.yaml",
34
34
  "yarn.lock",
35
35
  "bun.lock",
36
- "bun.lockb",
37
- "deno.lock"
36
+ "bun.lockb"
38
37
  ]);
39
38
  /** Basename of a repo-relative path. */
40
39
  function basename(path) {
@@ -160,7 +159,6 @@ function traceAffected(graph, changedFiles, storyFiles, options = {}) {
160
159
  const storyOf = storyNodeMap(graph, storyFiles);
161
160
  return [...reachableStories(graph, traceRoots(graph, relevant, storyOf), storyOf)].toSorted();
162
161
  }
163
- //#endregion
164
162
  export { matchesAnyGlob, traceAffected };
165
163
 
166
164
  //# sourceMappingURL=trace.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"trace.mjs","names":[],"sources":["../src/trace.ts"],"sourcesContent":["import { graphModulesFor } from \"./stats.ts\";\nimport type { DepGraph, TraceOptions } from \"./types.ts\";\n\n/** Basenames whose change invalidates every story (global render setup). */\nconst GLOBAL_BASENAMES = new Set([\n \"preview.js\",\n \"preview.jsx\",\n \"preview.ts\",\n \"preview.tsx\",\n \"preview.mjs\",\n \"preview.cjs\",\n \"preview.mts\",\n \"preview.cts\",\n \"manager.js\",\n \"manager.jsx\",\n \"manager.ts\",\n \"manager.tsx\",\n]);\n\n/** Config basenames whose change may add, remove, or re-glob stories. */\nconst CONFIG_BASENAMES = new Set([\"main.js\", \"main.ts\", \"main.mjs\", \"main.cjs\", \"main.mts\"]);\n\n/** Lockfiles whose change means dependency versions cannot be resolved. */\nconst LOCKFILE_BASENAMES = new Set([\n \"package.json\",\n \"package-lock.json\",\n \"pnpm-lock.yaml\",\n \"yarn.lock\",\n \"bun.lock\",\n \"bun.lockb\",\n \"deno.lock\",\n]);\n\n/** Basename of a repo-relative path. */\nfunction basename(path: string): string {\n const index = path.lastIndexOf(\"/\");\n return index === -1 ? path : path.slice(index + 1);\n}\n\n/** True when a changed file forces a full render of every story. */\nfunction isGlobalFile(path: string): boolean {\n const base = basename(path);\n if (GLOBAL_BASENAMES.has(base) || CONFIG_BASENAMES.has(base) || LOCKFILE_BASENAMES.has(base)) {\n return true;\n }\n return path.includes(\".storybook/\") && (CONFIG_BASENAMES.has(base) || GLOBAL_BASENAMES.has(base));\n}\n\n/** Regex-special chars escaped when translating globs (kept discrete: no `${`). */\nconst REGEX_SPECIALS = new Set([\"+\", \"^\", \"$\", \"{\", \"}\", \"(\", \")\", \"|\", \"[\", \"]\", \"\\\\\", \".\"]);\n\n/** Translate one glob token at `index` into regex text and advance width. */\nfunction translateGlobToken(pattern: string, index: number): { text: string; advance: number } {\n const char = pattern[index];\n if (char === \"*\") {\n return pattern[index + 1] === \"*\" ? { text: \".*\", advance: 2 } : { text: \"[^/]*\", advance: 1 };\n }\n if (char === \"?\") {\n return { text: \"[^/]\", advance: 1 };\n }\n if (char !== undefined && REGEX_SPECIALS.has(char)) {\n return { text: `\\\\${char}`, advance: 1 };\n }\n return { text: char ?? \"\", advance: 1 };\n}\n\n/** Escape regex syntax while translating `*`, `**`, and `?` globs. */\nfunction globToRegExp(pattern: string): RegExp {\n const parts: string[] = [];\n let index = 0;\n while (index < pattern.length) {\n const token = translateGlobToken(pattern, index);\n parts.push(token.text);\n index += token.advance;\n }\n return new RegExp(`^${parts.join(\"\")}$`, \"u\");\n}\n\n/** True when `path` matches any of the given glob patterns. */\nexport function matchesAnyGlob(path: string, patterns: readonly string[]): boolean {\n return patterns.some((pattern) => globToRegExp(pattern).test(path));\n}\n\n/** Queue reverse-edge dependents not yet visited. */\nfunction pushUnseen(seen: Set<string>, pending: string[], dependents: readonly string[]): void {\n for (const dependent of dependents) {\n if (!seen.has(dependent)) {\n seen.add(dependent);\n pending.push(dependent);\n }\n }\n}\n\n/** Fold one graph node into the affected set and queue its dependents. */\nfunction processNode(\n graph: DepGraph,\n storyOf: ReadonlyMap<string, string>,\n seen: Set<string>,\n pending: string[],\n affected: Set<string>,\n current: string,\n): void {\n const story = storyOf.get(current);\n if (story !== undefined) {\n affected.add(story);\n }\n pushUnseen(seen, pending, graph.importedBy[current] ?? []);\n}\n\n/** Collect every story file reachable from `roots` via reverse edges. */\nfunction reachableStories(\n graph: DepGraph,\n roots: string[],\n storyOf: ReadonlyMap<string, string>,\n): Set<string> {\n const seen = new Set<string>(roots);\n const pending = [...roots];\n const affected = new Set<string>();\n while (pending.length > 0) {\n const current = pending.pop();\n if (current === undefined) {\n break;\n }\n processNode(graph, storyOf, seen, pending, affected, current);\n }\n return affected;\n}\n\n/** Map every graph node to its story file (suffix match for absolute stats). */\nfunction storyNodeMap(graph: DepGraph, storyFiles: readonly string[]): Map<string, string> {\n const nodes = new Set([...Object.keys(graph.imports), ...Object.keys(graph.importedBy)]);\n const map = new Map<string, string>();\n for (const story of storyFiles) {\n for (const node of nodes) {\n if ((node === story || node.endsWith(`/${story}`)) && !map.has(node)) {\n map.set(node, story);\n }\n }\n }\n return map;\n}\n/** Root modules for tracing: changed modules plus directly changed stories. */\nfunction traceRoots(\n graph: DepGraph,\n relevant: string[],\n storyOf: ReadonlyMap<string, string>,\n): string[] {\n const roots = changedModules(graph, relevant);\n for (const file of relevant) {\n if (storyOf.has(file)) {\n roots.push(file);\n }\n }\n return [...new Set(roots)];\n}\n/** Map changed files to graph modules, dropping files outside the graph. */\nfunction changedModules(graph: DepGraph, changed: string[]): string[] {\n const modules = new Set<string>();\n for (const file of changed) {\n for (const module of graphModulesFor(graph, file)) {\n modules.add(module);\n }\n }\n return [...modules];\n}\n\n/**\n * Trace changed files through the dependency graph to story files.\n *\n * @param graph - Bidirectional module graph of the built Storybook.\n * @param changedFiles - Repo-relative changed files.\n * @param storyFiles - Normalized story import paths from the story index.\n * @param options - Untraced globs excluded from tracing.\n * @returns Affected story files, or `null` when everything must render.\n */\nexport function traceAffected(\n graph: DepGraph,\n changedFiles: string[],\n storyFiles: readonly string[],\n options: TraceOptions = {},\n): string[] | null {\n const untraced = options.untraced ?? [];\n const relevant = changedFiles.filter((file) => !matchesAnyGlob(file, untraced));\n const forcing = relevant.find((file) => isGlobalFile(file));\n if (forcing !== undefined) {\n return null;\n }\n const storyOf = storyNodeMap(graph, storyFiles);\n const roots = traceRoots(graph, relevant, storyOf);\n return [...reachableStories(graph, roots, storyOf)].toSorted();\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"trace.mjs","names":[],"sources":["../src/trace.ts"],"sourcesContent":["import { graphModulesFor } from \"./stats.ts\";\nimport type { DepGraph, TraceOptions } from \"./types.ts\";\n\n/** Basenames whose change invalidates every story (global render setup). */\nconst GLOBAL_BASENAMES = new Set([\n \"preview.js\",\n \"preview.jsx\",\n \"preview.ts\",\n \"preview.tsx\",\n \"preview.mjs\",\n \"preview.cjs\",\n \"preview.mts\",\n \"preview.cts\",\n \"manager.js\",\n \"manager.jsx\",\n \"manager.ts\",\n \"manager.tsx\",\n]);\n\n/** Config basenames whose change may add, remove, or re-glob stories. */\nconst CONFIG_BASENAMES = new Set([\"main.js\", \"main.ts\", \"main.mjs\", \"main.cjs\", \"main.mts\"]);\n\n/** Lockfiles whose change means dependency versions cannot be resolved. */\nconst LOCKFILE_BASENAMES = new Set([\n \"package.json\",\n \"package-lock.json\",\n \"pnpm-lock.yaml\",\n \"yarn.lock\",\n \"bun.lock\",\n \"bun.lockb\",\n]);\n\n/** Basename of a repo-relative path. */\nfunction basename(path: string): string {\n const index = path.lastIndexOf(\"/\");\n return index === -1 ? path : path.slice(index + 1);\n}\n\n/** True when a changed file forces a full render of every story. */\nfunction isGlobalFile(path: string): boolean {\n const base = basename(path);\n if (GLOBAL_BASENAMES.has(base) || CONFIG_BASENAMES.has(base) || LOCKFILE_BASENAMES.has(base)) {\n return true;\n }\n return path.includes(\".storybook/\") && (CONFIG_BASENAMES.has(base) || GLOBAL_BASENAMES.has(base));\n}\n\n/** Regex-special chars escaped when translating globs (kept discrete: no `${`). */\nconst REGEX_SPECIALS = new Set([\"+\", \"^\", \"$\", \"{\", \"}\", \"(\", \")\", \"|\", \"[\", \"]\", \"\\\\\", \".\"]);\n\n/** Translate one glob token at `index` into regex text and advance width. */\nfunction translateGlobToken(pattern: string, index: number): { text: string; advance: number } {\n const char = pattern[index];\n if (char === \"*\") {\n return pattern[index + 1] === \"*\" ? { text: \".*\", advance: 2 } : { text: \"[^/]*\", advance: 1 };\n }\n if (char === \"?\") {\n return { text: \"[^/]\", advance: 1 };\n }\n if (char !== undefined && REGEX_SPECIALS.has(char)) {\n return { text: `\\\\${char}`, advance: 1 };\n }\n return { text: char ?? \"\", advance: 1 };\n}\n\n/** Escape regex syntax while translating `*`, `**`, and `?` globs. */\nfunction globToRegExp(pattern: string): RegExp {\n const parts: string[] = [];\n let index = 0;\n while (index < pattern.length) {\n const token = translateGlobToken(pattern, index);\n parts.push(token.text);\n index += token.advance;\n }\n return new RegExp(`^${parts.join(\"\")}$`, \"u\");\n}\n\n/** True when `path` matches any of the given glob patterns. */\nexport function matchesAnyGlob(path: string, patterns: readonly string[]): boolean {\n return patterns.some((pattern) => globToRegExp(pattern).test(path));\n}\n\n/** Queue reverse-edge dependents not yet visited. */\nfunction pushUnseen(seen: Set<string>, pending: string[], dependents: readonly string[]): void {\n for (const dependent of dependents) {\n if (!seen.has(dependent)) {\n seen.add(dependent);\n pending.push(dependent);\n }\n }\n}\n\n/** Fold one graph node into the affected set and queue its dependents. */\nfunction processNode(\n graph: DepGraph,\n storyOf: ReadonlyMap<string, string>,\n seen: Set<string>,\n pending: string[],\n affected: Set<string>,\n current: string,\n): void {\n const story = storyOf.get(current);\n if (story !== undefined) {\n affected.add(story);\n }\n pushUnseen(seen, pending, graph.importedBy[current] ?? []);\n}\n\n/** Collect every story file reachable from `roots` via reverse edges. */\nfunction reachableStories(\n graph: DepGraph,\n roots: string[],\n storyOf: ReadonlyMap<string, string>,\n): Set<string> {\n const seen = new Set<string>(roots);\n const pending = [...roots];\n const affected = new Set<string>();\n while (pending.length > 0) {\n const current = pending.pop();\n if (current === undefined) {\n break;\n }\n processNode(graph, storyOf, seen, pending, affected, current);\n }\n return affected;\n}\n\n/** Map every graph node to its story file (suffix match for absolute stats). */\nfunction storyNodeMap(graph: DepGraph, storyFiles: readonly string[]): Map<string, string> {\n const nodes = new Set([...Object.keys(graph.imports), ...Object.keys(graph.importedBy)]);\n const map = new Map<string, string>();\n for (const story of storyFiles) {\n for (const node of nodes) {\n if ((node === story || node.endsWith(`/${story}`)) && !map.has(node)) {\n map.set(node, story);\n }\n }\n }\n return map;\n}\n/** Root modules for tracing: changed modules plus directly changed stories. */\nfunction traceRoots(\n graph: DepGraph,\n relevant: string[],\n storyOf: ReadonlyMap<string, string>,\n): string[] {\n const roots = changedModules(graph, relevant);\n for (const file of relevant) {\n if (storyOf.has(file)) {\n roots.push(file);\n }\n }\n return [...new Set(roots)];\n}\n/** Map changed files to graph modules, dropping files outside the graph. */\nfunction changedModules(graph: DepGraph, changed: string[]): string[] {\n const modules = new Set<string>();\n for (const file of changed) {\n for (const module of graphModulesFor(graph, file)) {\n modules.add(module);\n }\n }\n return [...modules];\n}\n\n/**\n * Trace changed files through the dependency graph to story files.\n *\n * @param graph - Bidirectional module graph of the built Storybook.\n * @param changedFiles - Repo-relative changed files.\n * @param storyFiles - Normalized story import paths from the story index.\n * @param options - Untraced globs excluded from tracing.\n * @returns Affected story files, or `null` when everything must render.\n */\nexport function traceAffected(\n graph: DepGraph,\n changedFiles: string[],\n storyFiles: readonly string[],\n options: TraceOptions = {},\n): string[] | null {\n const untraced = options.untraced ?? [];\n const relevant = changedFiles.filter((file) => !matchesAnyGlob(file, untraced));\n const forcing = relevant.find((file) => isGlobalFile(file));\n if (forcing !== undefined) {\n return null;\n }\n const storyOf = storyNodeMap(graph, storyFiles);\n const roots = traceRoots(graph, relevant, storyOf);\n return [...reachableStories(graph, roots, storyOf)].toSorted();\n}\n"],"mappings":"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"}
package/dist/types.d.mts CHANGED
@@ -1,6 +1,5 @@
1
1
  import __tsdown_shims_path from 'node:path';
2
2
  import __tsdown_shims_url from 'node:url';
3
- //#region src/types.d.ts
4
3
  /**
5
4
  * Shared types for affected capture: dependency graphs, trace inputs, and
6
5
  * the affected-set result. Zero runtime dependencies by design — both the
@@ -52,6 +51,5 @@ interface AffectedResult {
52
51
  interface StoryLike {
53
52
  importPath?: string | null;
54
53
  }
55
- //#endregion
56
54
  export { AffectedInput, AffectedResult, DepGraph, StoryLike, TraceOptions };
57
55
  //# sourceMappingURL=types.d.mts.map
package/dist/usage.d.mts CHANGED
@@ -1,7 +1,6 @@
1
1
  import __tsdown_shims_path from 'node:path';
2
2
  import __tsdown_shims_url from 'node:url';
3
3
  import { DepGraph } from "./types.mjs";
4
- //#region src/usage.d.ts
5
4
  /** A dependency package a story file reaches, and the first module that reaches it. */
6
5
  interface PackageUsage {
7
6
  /** Story file (repo-relative, as given by the Storybook index). */
@@ -26,6 +25,5 @@ interface TrackedPackage {
26
25
  * @param packages - Packages to track (e.g. the project's declared dependencies).
27
26
  */
28
27
  declare function extractPackageUsage(graph: DepGraph, storyFiles: readonly string[], packages: Record<string, TrackedPackage>): PackageUsage[];
29
- //#endregion
30
28
  export { PackageUsage, TrackedPackage, extractPackageUsage };
31
29
  //# sourceMappingURL=usage.d.mts.map
package/dist/usage.mjs CHANGED
@@ -2,7 +2,7 @@ import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
4
  import { graphModulesFor } from "./stats.mjs";
5
- //#region src/usage.ts
5
+ // src/usage.ts
6
6
  const NODE_MODULES = "node_modules/";
7
7
  /** Package name for a `…/node_modules/<pkg>/…` module path, handling scopes. */
8
8
  function nodeModulesPackage(module) {
@@ -60,7 +60,6 @@ function extractPackageUsage(graph, storyFiles, packages) {
60
60
  const tracked = new Map(Object.entries(packages));
61
61
  return storyFiles.flatMap((storyFile) => usageForStory(graph, storyFile, graphModulesFor(graph, storyFile), tracked));
62
62
  }
63
- //#endregion
64
63
  export { extractPackageUsage };
65
64
 
66
65
  //# sourceMappingURL=usage.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storyshelf/affected",
3
- "version": "0.7.0",
3
+ "version": "0.9.0-next-d2cc082",
4
4
  "description": "Affected capture for StoryShelf: dependency-graph tracing that selects the stories impacted by a change.",
5
5
  "keywords": [
6
6
  "affected",
@@ -60,18 +60,9 @@
60
60
  "oxlint-tsgolint": "^7.0.2001",
61
61
  "tsdown": "^0.22.14",
62
62
  "typescript": "^7.0.2",
63
- "vitest": "^5.0.0"
63
+ "vitest": "^5.0.5"
64
64
  },
65
65
  "engines": {
66
66
  "node": ">=24"
67
- },
68
- "jsr": {
69
- "runtimeCompat": {
70
- "node": true,
71
- "deno": true,
72
- "bun": true,
73
- "workerd": false,
74
- "browser": false
75
- }
76
67
  }
77
68
  }