Skip to content

Angular: Record two compodoc signal gaps as harness fixtures - #35628

Closed
valentinpalkovic wants to merge 2 commits into
nextfrom
valentin/angular-signal-gap-fixtures
Closed

valentinpalkovic wants to merge 2 commits into
nextfrom
valentin/angular-signal-gap-fixtures

Conversation

@valentinpalkovic

Copy link
Copy Markdown
Contributor

What I did

code/lib/docgen-harness records what today's Angular docgen actually produces, so that when we replace it we can see exactly what changed.
This adds two more recordings, both about signal inputs.

Compodoc does not read signals through the TypeScript type checker.
It matches the initializer's source text against the literal names input, output and model.
Two shapes therefore get lost:

  1. An aliased import. Write import { input as ngInput } and aliased = ngInput('hello'), and compodoc stops seeing an input at all — the member is demoted to an untyped property. Angular itself resolves it as a normal working input, so only the docs are wrong.
  2. A non-literal default. input([1, 2, 3]) and input(makeDefault()) keep their raw default text but record no type. input({ a: 1 }) is read as the options bag, so it records neither a type nor a default. input.required() records no type either.

Both fixtures are real captures, not hand-written ones: compodoc 2.0.0, the version we pin, for the docs side, and real ngc output for the ɵcmp input maps.
Each gap gets a red marker in angular-legacy-gaps.test.ts, so it turns green on its own once a replacement resolves these correctly.

Test fixtures only — no production code is touched.

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

Manual testing

cd code && yarn vitest run --config lib/docgen-harness/vitest.config.ts lib/docgen-harness

Expect 11 files passing, 167 passed and 26 expected failures.
The two new expected failures are a signal input behind an aliased import is still recognized as an input and non-literal signal input defaults still resolve real type/default info.
They are red on purpose: they describe what a correct engine should say, and today's engine does not say it.

Documentation

  • Add or update documentation reflecting your changes

The two gaps are listed under "Known legacy gaps (angular)" in code/lib/docgen-harness/README.md.

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: build

Compodoc does not read signals through the type checker. It matches the
initializer's source text against the literal names input, output and model,
so two shapes get lost.

An aliased import is the first. Write `import { input as ngInput }` and the
name no longer matches, so the member is demoted to an untyped property.
Angular resolves it as a normal input, so only the docs are wrong.

A non-literal default is the second. An array or a call keeps its raw text but
records no type, a sole object literal is read as the options bag and records
neither, and `input.required()` records no type either.

Both are recorded as fixtures with a red marker in angular-legacy-gaps.test.ts.
The captures are real: compodoc 2.0.0, the version we pin, for the docs, and
ngc for the AOT input maps.
@valentinpalkovic valentinpalkovic added the build Internal-facing build tooling & test updates label Jul 28, 2026
@valentinpalkovic valentinpalkovic added the ci:normal Run our default set of CI jobs (choose this for most PRs). label Jul 31, 2026
@valentinpalkovic valentinpalkovic self-assigned this Jul 31, 2026
@storybook-app-bot

storybook-app-bot Bot commented Jul 31, 2026 •

Copy link
Copy Markdown
Contributor

Package Benchmarks

Commit: 7d62ae5, ran on 13 August 2026 at 17:41:01 UTC

No significant changes detected, all good. 👏

@valentinpalkovic valentinpalkovic added the qa:skip Pull Requests that do not need any QA. (e.g. documentation) label Aug 3, 2026
@valentinpalkovic
valentinpalkovic marked this pull request as ready for review August 3, 2026 10:40
@valentinpalkovic
valentinpalkovic requested a review from a team August 3, 2026 10:40
@coderabbitai

coderabbitai Bot commented Aug 3, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 37 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: db413946-19c5-4aa6-adeb-681b2b080d6d

📥 Commits

Reviewing files that changed from the base of the PR and between 4d267f2 and 7d62ae5.

📒 Files selected for processing (19)
  • code/lib/docgen-harness/README.md
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-aliased-import/aot-cmp.ts
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-aliased-import/argtypes-filtered.snapshot
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-aliased-import/argtypes.snapshot
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-aliased-import/compodoc-input.json
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-aliased-import/input.stories.ts
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-aliased-import/signal-aliased-import.component.ts
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-aliased-import/snippet-PropsAsWritten.snapshot
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-aliased-import/tsconfig.json
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/aot-cmp.ts
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/argtypes-filtered.snapshot
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/argtypes.snapshot
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/compodoc-input.json
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/input.stories.ts
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/signal-non-literal-defaults.component.ts
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/snippet-PropsAsWritten.snapshot
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/tsconfig.json
  • code/lib/docgen-harness/src/angular/angular-legacy-gaps.test.ts
  • code/lib/docgen-harness/src/angular/angular-render.test.ts

Walkthrough

Added Angular harness fixtures for aliased signal imports and non-literal signal-input defaults. Added AOT, Compodoc, Storybook, snapshot, and TypeScript metadata. Added legacy-gap tests and documentation.

Changes

Angular signal legacy gaps

Layer / File(s) Summary
Aliased signal import fixture
code/lib/docgen-harness/src/angular/__testfixtures__/signal-aliased-import/*
Adds a component using an aliased input import, with AOT and Compodoc metadata, Storybook data, snapshots, and TypeScript configuration.
Non-literal signal defaults fixture
code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/*
Adds signal inputs with array, function-derived, object, and required defaults, plus matching metadata, stories, snapshots, and configuration.
Legacy-gap validation
code/lib/docgen-harness/src/angular/angular-legacy-gaps.test.ts, code/lib/docgen-harness/src/angular/angular-render.test.ts, code/lib/docgen-harness/README.md
Adds failing tests for input recognition and default metadata, excludes both fixtures from JIT rendering tests, and documents the gaps.

Possibly related PRs

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/aot-cmp.ts (1)

1-5: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Replace provenance and parser-detail comments with maintenance rationale.

These comments expose capture provenance or internal parser mechanics. Keep only the stable reason that the fixture or test exists.

  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/aot-cmp.ts#L1-L5: State that signal inputs require AOT metadata because JIT does not populate the maps read by the recorder.
  • code/lib/docgen-harness/src/angular/angular-legacy-gaps.test.ts#L74-L76: State that legacy Compodoc does not recognize aliased signal input imports.
  • code/lib/docgen-harness/src/angular/angular-legacy-gaps.test.ts#L81-L84: State that legacy Compodoc loses type and default metadata for non-literal signal input defaults.

As per coding guidelines, comments should explain maintenance rationale for future maintainers, not investigation transcripts, and must not commit provenance claims.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/aot-cmp.ts`
around lines 1 - 5, Replace the provenance and parser-detail comments with
concise maintenance rationale: in
code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/aot-cmp.ts
lines 1-5, state that signal inputs require AOT metadata because JIT does not
populate the maps read by the recorder; in
code/lib/docgen-harness/src/angular/angular-legacy-gaps.test.ts lines 74-76,
state that legacy Compodoc does not recognize aliased signal input imports; and
in lines 81-84, state that legacy Compodoc loses type and default metadata for
non-literal signal input defaults.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@code/lib/docgen-harness/README.md`:
- Around line 139-140: Clarify the README entries so the
`signal-aliased-import/` case explicitly refers to an aliased Angular import
such as `import { input as ngInput }`, while the existing entry around the
aliased signal inputs identifies Angular input metadata aliases. Ensure the two
documented behaviors are clearly distinguished rather than appearing
contradictory.

In
`@code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/signal-non-literal-defaults.component.ts`:
- Line 18: Update requiredValue to call input.required with an explicit string
type parameter so type metadata is generated, then update
angular-legacy-gaps.test.ts to assert string type metadata and no default value
for requiredValue.

---

Nitpick comments:
In
`@code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/aot-cmp.ts`:
- Around line 1-5: Replace the provenance and parser-detail comments with
concise maintenance rationale: in
code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/aot-cmp.ts
lines 1-5, state that signal inputs require AOT metadata because JIT does not
populate the maps read by the recorder; in
code/lib/docgen-harness/src/angular/angular-legacy-gaps.test.ts lines 74-76,
state that legacy Compodoc does not recognize aliased signal input imports; and
in lines 81-84, state that legacy Compodoc loses type and default metadata for
non-literal signal input defaults.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5d3ce6ab-4739-40ae-96f8-60145ad41f9a

📥 Commits

Reviewing files that changed from the base of the PR and between 5ffa70f and fe5b443.

📒 Files selected for processing (19)
  • code/lib/docgen-harness/README.md
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-aliased-import/aot-cmp.ts
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-aliased-import/argtypes-filtered.snapshot
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-aliased-import/argtypes.snapshot
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-aliased-import/compodoc-input.json
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-aliased-import/input.stories.ts
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-aliased-import/signal-aliased-import.component.ts
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-aliased-import/snippet-PropsAsWritten.snapshot
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-aliased-import/tsconfig.json
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/aot-cmp.ts
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/argtypes-filtered.snapshot
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/argtypes.snapshot
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/compodoc-input.json
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/input.stories.ts
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/signal-non-literal-defaults.component.ts
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/snippet-PropsAsWritten.snapshot
  • code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/tsconfig.json
  • code/lib/docgen-harness/src/angular/angular-legacy-gaps.test.ts
  • code/lib/docgen-harness/src/angular/angular-render.test.ts

Comment thread code/lib/docgen-harness/README.md

config = input({ a: 1 });

requiredValue = input.required();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C 3 'input\.required' code/lib/docgen-harness/src/angular
rg -n -C 5 'requiredValue|nonLiteralDefaultsArgTypes' \
  code/lib/docgen-harness/src/angular/angular-legacy-gaps.test.ts \
  code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults

Repository: storybookjs/storybook

Length of output: 20036


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- fixture and test ---'
cat -n code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/signal-non-literal-defaults.component.ts
sed -n '70,92p' code/lib/docgen-harness/src/angular/angular-legacy-gaps.test.ts

printf '%s\n' '--- requiredValue snapshot entries ---'
for f in \
  code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/argtypes.snapshot \
  code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/argtypes-filtered.snapshot \
  code/lib/docgen-harness/src/angular/__testfixtures__/signal-io/argtypes.snapshot \
  code/lib/docgen-harness/src/angular/__testfixtures__/signal-io/argtypes-filtered.snapshot
do
  echo "### $f"
  awk '/"requiredValue"|"count"/{p=1} p{print} p && /^  },$/{p=0}' "$f"
done

printf '%s\n' '--- Angular input.required declarations and project versions ---'
rg -n -C 3 'required\s*[:=].*input|input\.required|InputSignal' code/lib/docgen-harness package.json code/package.json 2>/dev/null | head -220
rg -n '"`@angular/core`"|"angular"' package.json code/package.json code/lib/docgen-harness/package.json 2>/dev/null | head -80

Repository: storybookjs/storybook

Length of output: 9889


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
import re

fixture = Path("code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/signal-non-literal-defaults.component.ts").read_text()
snapshot = Path("code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/argtypes.snapshot").read_text()
tests = Path("code/lib/docgen-harness/src/angular/angular-legacy-gaps.test.ts").read_text()

decl = re.search(r"requiredValue\s*=\s*input\.required(?:<([^>]+)>)?\(\s*\)", fixture)
assert decl, "requiredValue declaration not found"
print("requiredValue generic:", decl.group(1) or "<none>")

entry = re.search(r'  "requiredValue": \{(.*?)\n  \},', snapshot, re.S)
assert entry, "requiredValue snapshot entry not found"
body = entry.group(1)
summary = re.search(r'"summary":\s*([^,\n]+)', body)
print("requiredValue snapshot summaries:", summary.group(1) if summary else "<none>")
print("required flag present:", '"required": true' in body)
print("requiredValue asserted in gap test:", "requiredValue" in tests)

assert decl.group(1) is None
assert summary is None or summary.group(1).strip() == "undefined"
assert '"required": true' in body
assert "requiredValue" not in tests
PY

printf '%s\n' '--- exact snapshot entry ---'
sed -n '57,76p' code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/argtypes.snapshot

Repository: storybookjs/storybook

Length of output: 673


Give requiredValue a concrete source type.

input.required() produces no type metadata here. The snapshot records an undefined type summary. Use input.required<string>(), then assert requiredValue has string type metadata and no default value in angular-legacy-gaps.test.ts.

Proposed fix
-  requiredValue = input.required();
+  requiredValue = input.required<string>();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
requiredValue = input.required();
requiredValue = input.required<string>();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@code/lib/docgen-harness/src/angular/__testfixtures__/signal-non-literal-defaults/signal-non-literal-defaults.component.ts`
at line 18, Update requiredValue to call input.required with an explicit string
type parameter so type metadata is generated, then update
angular-legacy-gaps.test.ts to assert string type metadata and no default value
for requiredValue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build Internal-facing build tooling & test updates 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