From 99bb59c8377ce90898cea0546f3aa39e6529a4f2 Mon Sep 17 00:00:00 2001 From: yannbf Date: Fri, 29 May 2026 12:32:10 +0200 Subject: [PATCH] Implement component to stories extraction --- .../ChangeDetectionService.ts | 39 +++++++++++++++++++ .../active-service-registry.ts | 27 +++++++++++++ .../src/core-server/change-detection/index.ts | 4 ++ code/core/src/core-server/dev-server.ts | 8 +++- code/core/src/core-server/index.ts | 1 + 5 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 code/core/src/core-server/change-detection/active-service-registry.ts diff --git a/code/core/src/core-server/change-detection/ChangeDetectionService.ts b/code/core/src/core-server/change-detection/ChangeDetectionService.ts index 1458b10080ba..752ca0a368f0 100644 --- a/code/core/src/core-server/change-detection/ChangeDetectionService.ts +++ b/code/core/src/core-server/change-detection/ChangeDetectionService.ts @@ -17,6 +17,7 @@ import { CHANGE_DETECTION_STATUS_TYPE_ID } from 'storybook/internal/types'; import type { StoryIndexGenerator } from '../utils/StoryIndexGenerator.ts'; import type { ChangeDetectionAdapter, FileChangeEvent } from './adapters/index.ts'; +import { setActiveChangeDetectionService } from './active-service-registry.ts'; import { ChangeDetectionResolverFactory, DependencyGraphBuilder, @@ -489,10 +490,48 @@ export class ChangeDetectionService { } } + /** + * Returns the live reverse-dependency index, or `undefined` if the graph + * hasn't finished its cold-start build yet (or change detection is unavailable). + * + * The returned instance is the same reference patched by `IncrementalPatcher` + * on file changes — callers read it lazily at query time, not snapshotted. + * + * @experimental + */ + getReverseIndex(): ReverseIndexImpl | undefined { + return this.reverseIndex; + } + + /** + * Returns a map from absolute story file path → set of story IDs declared in + * that file, derived from the current story index. + * + * Useful for callers (e.g. addons) that consume {@link getReverseIndex} output: + * the reverse-index entries are keyed by absolute file path, but consumers + * typically need story IDs. + * + * @experimental + */ + async getStoryIdsByFile(): Promise>> { + const generator = await this.options.storyIndexGeneratorPromise; + const storyIndex = await generator.getIndex(); + return getStoryIdsByAbsolutePath(this.storyIdsByFileCache, storyIndex, this.workingDir); + } + + /** @experimental Working directory used to resolve relative paths. */ + getWorkingDir(): string { + return this.workingDir; + } + async dispose(): Promise { this.disposed = true; this.rerunAfterCurrentScan = false; + // Clear the active-service registry so in-process consumers stop seeing + // a disposed instance after dev-server shutdown. + setActiveChangeDetectionService(undefined); + if (this.debounceTimer) { clearTimeout(this.debounceTimer); this.debounceTimer = undefined; diff --git a/code/core/src/core-server/change-detection/active-service-registry.ts b/code/core/src/core-server/change-detection/active-service-registry.ts new file mode 100644 index 000000000000..a9eab1365832 --- /dev/null +++ b/code/core/src/core-server/change-detection/active-service-registry.ts @@ -0,0 +1,27 @@ +import type { ChangeDetectionService } from './ChangeDetectionService.ts'; + +let activeService: ChangeDetectionService | undefined; + +/** + * Records the change-detection service started by the current Storybook dev server + * so that in-process consumers (addon presets) can reach it without going through a + * preset hook. Dev server is single-instance, so only one service is ever active. + * + * @internal + */ +export function setActiveChangeDetectionService(service: ChangeDetectionService | undefined): void { + activeService = service; +} + +/** + * Returns the change-detection service for the current dev-server process, or + * `undefined` when change detection is disabled / not yet started / disposed. + * + * Read at request time, not at preset load time — the service is constructed + * after presets register. + * + * @experimental + */ +export function getActiveChangeDetectionService(): ChangeDetectionService | undefined { + return activeService; +} diff --git a/code/core/src/core-server/change-detection/index.ts b/code/core/src/core-server/change-detection/index.ts index 1bd5583d15aa..0f78ad1f29d6 100644 --- a/code/core/src/core-server/change-detection/index.ts +++ b/code/core/src/core-server/change-detection/index.ts @@ -6,6 +6,10 @@ export { type ChangeDetectionReadiness, } from './readiness.ts'; export { ChangeDetectionService } from './ChangeDetectionService.ts'; +export { + getActiveChangeDetectionService, + setActiveChangeDetectionService, +} from './active-service-registry.ts'; export type { ChangeDetectionAdapter, FileChangeEvent, diff --git a/code/core/src/core-server/dev-server.ts b/code/core/src/core-server/dev-server.ts index e085a4446255..ef4633fb8469 100644 --- a/code/core/src/core-server/dev-server.ts +++ b/code/core/src/core-server/dev-server.ts @@ -9,7 +9,10 @@ import polka from 'polka'; import { isTelemetryModuleEnabled, telemetry } from '../telemetry/index.ts'; import type { ChangeDetectionAdapter } from './change-detection/index.ts'; -import { ChangeDetectionService } from './change-detection/index.ts'; +import { + ChangeDetectionService, + setActiveChangeDetectionService, +} from './change-detection/index.ts'; import { getStatusStoreByTypeId } from './stores/status.ts'; import type { StoryIndexGenerator } from './utils/StoryIndexGenerator.ts'; import { doTelemetry } from './utils/doTelemetry.ts'; @@ -54,6 +57,9 @@ export async function storybookDevServer( workingDir, presets: options.presets, }); + // Expose to in-process consumers (addon presets) via the active-service registry. + // Dev server is single-instance, so only one service is ever active. + setActiveChangeDetectionService(changeDetectionService); app.use(compression({ level: 1 })); diff --git a/code/core/src/core-server/index.ts b/code/core/src/core-server/index.ts index 783c928b5baa..329003291471 100644 --- a/code/core/src/core-server/index.ts +++ b/code/core/src/core-server/index.ts @@ -67,6 +67,7 @@ export type { ParseFileArgs, } from './change-detection/index.ts'; export { ChangeDetectionService } from './change-detection/ChangeDetectionService.ts'; +export { getActiveChangeDetectionService as experimental_getActiveChangeDetectionService } from './change-detection/active-service-registry.ts'; export { getTestProviderStoreById as experimental_getTestProviderStore, fullTestProviderStore as internal_fullTestProviderStore,