Skip to content

Core: Restore the args a server-docgen preview cannot type - #35907

Merged
valentinpalkovic merged 12 commits into
nextfrom
valentin/docgen-server-arg-types
Aug 17, 2026
Merged

valentinpalkovic merged 12 commits into
nextfrom
valentin/docgen-server-arg-types

Conversation

@valentinpalkovic

@valentinpalkovic valentinpalkovic commented Aug 14, 2026 •

Copy link
Copy Markdown
Contributor

Closes #

What I did

With experimentalDocgenServer enabled, the preview no longer holds a complete set of argTypes. Component metadata now lives on the server and is merged when the UI reads it, so prepareStory deliberately skips the inference pass to keep the preview's argTypes annotation-only. Consumers living in the preview still treated argTypes as "the set of args that exist", and silently dropped everything else.

                    story.argTypes under experimentalDocgenServer
                                      │
                 annotated only ──────┤ (no entry for a plain `args` key)
                                      │
        ┌─────────────────────────────┴─────────────────────────────┐
        ▼                                                           ▼
   ArgsStore                                            cleanArgsDecorator
   mapArgsToTypes / validateOptions                     kept only @Input/@Output
   drop keys with no argType                            or control/action
        │                                                           │
        ▼                                                           ▼
   url arg discarded                                    non-@Input arg stripped

The gate is in core and keyed only on the flag, so this is not Angular-specific. It applies to every renderer that enables the feature, React included:

// code/core/src/preview-api/modules/store/csf/prepareStory.ts
if (global.FEATURES?.experimentalDocgenServer && enhancer.secondPass) {
  return false;
}

1. URL args were discarded

mapArgsToTypes skips any key with no argType, and validateOptions builds its result by iterating argTypes, so a key absent from it can never come out. An arg set through the URL therefore never reached the story. The fix infers types where the validation needs them, without putting them back on the story where they would pollute the UI-read merge:

const argTypesForValidation = (story: PreparedStory<any>): ArgTypes =>
  global.FEATURES?.experimentalDocgenServer
    ? inferArgTypes({ id: story.id, argTypes: story.argTypes, initialArgs: story.initialArgs })
    : story.argTypes;

Same function, same inputs it would have had in the first pass, just called locally. This lives in core, so it covers every renderer.

2. Angular stripped args the component did not declare

cleanArgsDecorator kept an arg only when it was a component @Input/@Output or carried a control/action. Server docgen leaves the preview with no control on anything, so a public property that is not an @Input lost the value its story set.

Rather than add a third escape hatch to that filter, this deletes it. No other renderer does this: React passes every arg straight through. The behaviour arrived in 2021 with no stated rationale, and the only story it touched in that commit was a stray debug decorator:

(storyFn) => {
  const stroy = storyFn();
  console.log(stroy);
  return stroy;
},

The failure it plausibly guarded against, an invalid binding for a non-input, is prevented elsewhere: template generation starts from the component's real metadata and intersects with the props it was given.

inputs: ngComponentInputsOutputs.inputs.filter((i) => i.templateName in props)

Scoped to angular-vite. @storybook/angular keeps its decorator, so the two frameworks now differ here. That is deliberate: the webpack package has no docgen-server path, so nothing in this PR forces the change there.

The decorateStory suite was describe.skip'd as "infinitely running". It completes in under half a second, so it is enabled here. Two template expectations had silently rotted behind buildTemplate's 80-column line breaking while the suite was dark; those are corrected.

3. Two baseline re-records this PR needs to run at all

angular-vite/docgen-server-ts only runs in the daily set, so two merged changes never had their recorded baselines updated. The verification step gates every later job in that sandbox, so nothing above could be exercised until both were corrected.

Merged change Drift
props-table visibility rules dropped three internals from doc-button, added the three protected constructor dependencies to the DI component
"Stop marking a defaulted input as required in the props table" flipped table.type.required on every input carrying a default value

The second is the entire diff for 16 of the 17 files, 43 lines of exactly this:

         "type": {
-          "required": true,
+          "required": false,
           "summary": "string"
         }

Both are re-records, not behaviour changes.

Effect

Reproduced against a real angular-vite/docgen-server-ts dev sandbox, before and after, same server:

Probe Before After
example-button--primary&args=label:Hello+world "Button" "Hello world"
WithComponentWrapperDecorator "Private text:" "Private text: Child private text"

The decorator deletion changes the legacy Compodoc path too, so both were verified against live sandboxes. WithComponentWrapperDecorator renders identically on each:

Child
Input text: Child text
Output : Click here !
Private text: Child private text
Check Result
angular-vite/default-ts sandbox e2e (Compodoc) 59 passed, 0 failed
angular-vite/docgen-server-ts sandbox e2e 58 passed, 0 failed
@storybook/angular + @storybook/angular-vite unit 566 passed, 0 failed
code/core preview-api store unit 309 passed, 0 failed
baselines:sandbox --template angular-vite/docgen-server-ts baselines match

Follow-up, not fixed here

#35919 tracks removing argTypes from user-facing story annotations entirely. Three internal consumers fell into this same trap, so users reading argTypes in a play function will too. inferActionsFromArgTypesRegex is a fourth case, found by inspection with no failing test today, so it is left alone here and recorded in that issue.

The ArgTypeInference template story that first surfaced this was fixed separately on next and is no longer part of this diff.

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

ArgsStore.test.ts gains types args from their initial value when the story declares no argTypes, which fails on next with:

AssertionError: expected { a: 'Button', b: 1 } to deeply equal { a: 'Hello world', b: 42 }

Note b: the initial value 1 is what identifies the arg as numeric, so the URL string '42' is coerced back to 42. decorateStory.test.ts covers the pass-through, and addon-controls.spec.ts › should apply controls automatically when passed via url covers the URL path in the sandbox.

Manual testing

  1. yarn task sandbox --template angular-vite/docgen-server-ts --start-from auto
  2. cd ../storybook-sandboxes/angular-vite-docgen-server-ts && yarn storybook
  3. Open example/button → primary, set the label control to Hello world, then reload the page. The button must still read Hello world rather than reverting to Button.
  4. Open Core / Decorators / ComponentWrapperDecorator → With Component Wrapper Decorator. The child must read Private text: Child private text, not a bare Private text:.
  5. Repeat step 4 on an angular-vite/default-ts sandbox to confirm the Compodoc path is unchanged.

Note

A linked angular-vite sandbox currently cannot boot locally: yarn storybook dies with value `"builtin:vite-wasm-fallback"` does not match any variant of enum `BindingBuiltinPluginName` . Yarn's portal linking needs --preserve-symlinks, which makes the repo's nested rolldown@1.0.3 load the sandbox root's @rolldown/binding-darwin-arm64@1.2.0. Work around it by adding "resolutions": { "vite": "8.0.16", "rolldown": "1.0.3" } to the generated sandbox's package.json and re-running yarn install. Unrelated to this PR, and worth its own issue.

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

No user-facing API changes. The behaviour restored here is what users already get from a non-docgen-server Storybook. The angular-vite arg pass-through aligns it with every other renderer.

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Declare whether manual QA will be needed for this PR during the next release, through qa:needed or qa:skip

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

bug. These are the failures that surface once angular-vite/docgen-server-ts actually runs; they are present on next today.

@valentinpalkovic valentinpalkovic added bug ci:daily Run the CI jobs that normally run in the daily job. qa:skip Pull Requests that do not need any QA. (e.g. documentation) labels Aug 14, 2026
@coderabbitai

coderabbitai Bot commented Aug 14, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 48c8dca7-2447-460c-b071-be4027e49524

📥 Commits

Reviewing files that changed from the base of the PR and between db8bea2 and a8b32af.

📒 Files selected for processing (16)
  • code/lib/docgen-harness/src/sandbox-baselines/__baselines__/angular-vite-docgen-server-ts/example-button.json
  • code/lib/docgen-harness/src/sandbox-baselines/__baselines__/angular-vite-docgen-server-ts/example-header.json
  • code/lib/docgen-harness/src/sandbox-baselines/__baselines__/angular-vite-docgen-server-ts/example-page.json
  • code/lib/docgen-harness/src/sandbox-baselines/__baselines__/angular-vite-docgen-server-ts/stories-frameworks-angular-vite-argtypes-doc-button.json
  • code/lib/docgen-harness/src/sandbox-baselines/__baselines__/angular-vite-docgen-server-ts/stories-frameworks-angular-vite-argtypes-doc-directive.json
  • code/lib/docgen-harness/src/sandbox-baselines/__baselines__/angular-vite-docgen-server-ts/stories-frameworks-angular-vite-basics-angular-forms-customcontrolvalueaccessor-custom-cva-component.json
  • code/lib/docgen-harness/src/sandbox-baselines/__baselines__/angular-vite-docgen-server-ts/stories-frameworks-angular-vite-basics-component-with-ng-content-ng-content-about-parent.json
  • code/lib/docgen-harness/src/sandbox-baselines/__baselines__/angular-vite-docgen-server-ts/stories-frameworks-angular-vite-basics-component-with-template-template.json
  • code/lib/docgen-harness/src/sandbox-baselines/__baselines__/angular-vite-docgen-server-ts/stories-frameworks-angular-vite-basics-component-without-selector-without-selector-ng-component-outlet.json
  • code/lib/docgen-harness/src/sandbox-baselines/__baselines__/angular-vite-docgen-server-ts/stories-frameworks-angular-vite-basics-component-without-selector-without-selector.json
  • code/lib/docgen-harness/src/sandbox-baselines/__baselines__/angular-vite-docgen-server-ts/stories-frameworks-angular-vite-basics-ng-module-import-module-chip.json
  • code/lib/docgen-harness/src/sandbox-baselines/__baselines__/angular-vite-docgen-server-ts/stories-frameworks-angular-vite-basics-ng-module-import-module-for-root.json
  • code/lib/docgen-harness/src/sandbox-baselines/__baselines__/angular-vite-docgen-server-ts/stories-frameworks-angular-vite-basics-ng-module-import-module.json
  • code/lib/docgen-harness/src/sandbox-baselines/__baselines__/angular-vite-docgen-server-ts/stories-frameworks-angular-vite-core-decorators-componentwrapperdecorator-decorators.json
  • code/lib/docgen-harness/src/sandbox-baselines/__baselines__/angular-vite-docgen-server-ts/stories-frameworks-angular-vite-others-app-initializer-use-factory.json
  • code/lib/docgen-harness/src/sandbox-baselines/__baselines__/angular-vite-docgen-server-ts/stories-frameworks-angular-vite-others-issues-12009-unknown-component.json

Included review availability: 0 reviews are currently available. Based on recent review activity, included reviews refill at 3 per hour.


Walkthrough

Changes

Server Docgen Argument Handling

Layer / File(s) Summary
ArgsStore type inference and regression coverage
code/core/src/preview-api/modules/store/ArgsStore.ts, code/core/src/preview-api/modules/store/ArgsStore.test.ts
ArgsStore infers argument types during server docgen for delta validation and persisted-argument mapping. Tests cover string and numeric conversion without declared argTypes.
Angular argument passthrough and test coverage
code/frameworks/angular-vite/src/client/decorateStory.ts, code/frameworks/angular-vite/src/client/decorateStory.test.ts
decorateStory passes all story arguments without the removed cleaning decorator. Enabled tests cover controlled, action, and unclassified arguments.
Angular docgen metadata baselines
code/lib/docgen-harness/src/sandbox-baselines/__baselines__/angular-vite-docgen-server-ts/*.json
Generated baselines update required flags and add metadata for provider-injected properties.

Merge Risk: ⚪ Minimal · up to a8b32

This PR restores untyped argument propagation for server-docgen previews and updates the affected Angular rendering and story expectations. The reported automated coverage passes, and no actionable merge-blocking risk remains beyond normal checks and review.


Comment @coderabbitai help to get the list of available commands.

With experimentalDocgenServer enabled, prepareStory skips the inference pass so
argTypes stays annotation-only for mergeServiceArgTypes. Both arg validation passes
drop args they have no argType for, so a plain args entry set through the URL was
silently discarded. Infer the missing types where the validation needs them, without
putting them back on the story.
Under experimentalDocgenServer the inference passes move to the UI read, so the
preview keeps only the annotated argTypes. The template story asserted the legacy
shape and failed in every sandbox running the feature.
@valentinpalkovic
valentinpalkovic force-pushed the valentin/docgen-server-arg-types branch from 6cc94fe to 810863b Compare August 17, 2026 06:48
@storybook-app-bot

storybook-app-bot Bot commented Aug 17, 2026 •

Copy link
Copy Markdown
Contributor

Package Benchmarks

Commit: 97c63e0, ran on 17 August 2026 at 10:23:46 UTC

No significant changes detected, all good. 👏

…sibility rules

The props table now hides class internals and keeps protected members, and the sandbox
that records these baselines only runs in the daily set, so the change landed without
them. The recording drops three internals from the doc-button entry and adds the three
protected constructor dependencies to the DI component's.
@valentinpalkovic
valentinpalkovic force-pushed the valentin/docgen-server-arg-types branch from 810863b to db8bea2 Compare August 17, 2026 08:05
cleanArgsDecorator dropped any arg without a control or an action, which no other
renderer does: React passes every arg straight to the component. The behaviour
arrived in 2021 with no stated rationale, its only committed story change was a
stray console.log decorator, and the guard it plausibly protected - invalid template
bindings for non-inputs - lives in computesTemplateFromComponent, which starts from
the component's real inputs/outputs. Under server docgen nothing carries a control
at all, so a public property that is not an @input lost the value its story set.

Scoped to angular-vite; @storybook/angular keeps its decorator. The suite asserting
the strip was describe.skip'd as "infinitely running"; it runs in under half a
second, so it is enabled here and the two stale template expectations that had
drifted behind buildTemplate's line breaking are corrected.
Comment thread code/core/template/stories/argTypes.stories.ts
Comment thread code/core/template/stories/argTypes.stories.ts
@valentinpalkovic valentinpalkovic self-assigned this Aug 17, 2026
…ge drifted

"Stop marking a defaulted input as required in the props table" flipped
table.type.required from true to false on every input carrying a default value,
but the angular-vite/docgen-server-ts sandbox only runs in the daily set, so its
recorded baselines were never updated. 43 flips across 16 components. The
verification step gates every later job in that sandbox.
@valentinpalkovic valentinpalkovic added ci:normal Run our default set of CI jobs (choose this for most PRs). and removed ci:daily Run the CI jobs that normally run in the daily job. labels Aug 17, 2026
@valentinpalkovic
valentinpalkovic merged commit 4d685f9 into next Aug 17, 2026
151 of 154 checks passed
@valentinpalkovic
valentinpalkovic deleted the valentin/docgen-server-arg-types branch August 17, 2026 10:28
@github-actions github-actions Bot mentioned this pull request Aug 17, 2026
3 tasks done
huang-julien added a commit to storybookjs/sandboxes that referenced this pull request Aug 18, 2026
Check the diff here: storybookjs/storybook@f96ed20...add38a0

List of included PRs since previous version:
- storybookjs/storybook#35922 (valentin/sb-1766-angular-docgen-documentation-pass)
- storybookjs/storybook#35844 (s-robertson/u/srobertson/fix-react-component-meta-union-props)
- storybookjs/storybook#35931 (valentin/sb-1847-componentid-collision-warning)
- storybookjs/storybook#35923 (valentin/sb-1789-server-side-code-snippets-resolve-spreads-and-identifier)
- storybookjs/storybook#35940 (valentin/sb-1789-review-fixes)
- storybookjs/storybook#35900 (julien/vue-api-description)
- storybookjs/storybook#35938 (fix-publish-ansi-parsing)
- storybookjs/storybook#35929 (valentin/sb-1821-pin-oxc-resolver)
- storybookjs/storybook#35936 (chore/changelog-v10.5.9)
- storybookjs/storybook#35930 (valentin/sb-1789-review-fixes)
- storybookjs/storybook#35921 (valentin/sb-1809-bug-angular-constructor-and-generic-function-inputs-lose-the)
- storybookjs/storybook#35917 (norbert/fix-publish-staged-retries)
- storybookjs/storybook#35896 (valentin/sb-1776-angular-docs-end-to-end)
- storybookjs/storybook#35920 (julien/vue_server_docgen_options)
- storybookjs/storybook#35907 (valentin/docgen-server-arg-types)
- storybookjs/storybook#35886 (valentin/sb-1799-default-docgen-server-angular-vite)
- storybookjs/storybook#35902 (fix/vue-snippet-runtimeoverride)
- storybookjs/storybook#35825 (norbert/module-graph-skip-noop-mirror)
- storybookjs/storybook#35629 (reuben/fix-pseudo-states-cssom-rewrites)
- storybookjs/storybook#35915 (next-merge-prerelease)
- storybookjs/storybook#35906 (valentin/angular-docs-decorator-gate)
- storybookjs/storybook#35830 (version-non-patch-from-10.6.0-alpha.5)
- storybookjs/storybook#35899 (valentin/angular-required-input-with-default)
- storybookjs/storybook#35831 (norbert/spike-module-graph-hot-cold-split)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug ci:normal Run our default set of CI jobs (choose this for most PRs). qa:skip Pull Requests that do not need any QA. (e.g. documentation)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants