Create an API Reference component - #1588
Create an API Reference component#1588Alistair Matthews (alistairmatthews) wants to merge 8 commits into
Conversation
…d on the user's preferred language.
|
Feel free to continue to work on this, but do not merge until I review please. |
David Pine (IEvangelist)
left a comment
There was a problem hiding this comment.
Review summary
Source verification: microsoft/aspire main at 4a8b541c973baeb271f244603b0289c3f47933cf; generated API inputs in this PR point to microsoft/aspire@69db530a4816698cf1d5fa4557933e0ac4f127c6.
Claims: 29 normalized claims - 24 verified, 1 verified with nuance, 0 unverifiable, 4 contradicted.
Doc test: 8 changed routes exercised from PR head e24dac84f3c54cadeb88c0224b381da578d32e2f - 3 critical issues and 1 warning.
This needs another pass before merge. The component currently rewrites a string rather than resolving an API identity, emits no links, breaks inline HTML in real pages, and falls out of sync with supported aspire-lang interactions.
Blocking acceptance criteria
- Accept a canonical fully qualified API identifier and resolve its C# and TypeScript labels plus canonical reference routes from the generated API metadata, including explicit
AspireExportidentities and renames. - Render valid inline link markup. For a missing, ambiguous, or one-language-only symbol, render unlinked code with a precise warning rather than inventing an API.
- Add a separate authoring validator that fails tests/CI for unresolved or ambiguous usages and reports the file, line, supplied FQN, and useful candidates.
- Consume the existing canonical AppHost language state instead of maintaining a second attribute/listener implementation.
- Cover resolver edge cases, parsed browser markup, pointer and keyboard tabs,
PivotSelector, persisted/query initialization, link destinations, and validator diagnostics.
Editor autocomplete or a generated FQN union would be valuable, but it can remain a non-blocking follow-up once deterministic validation exists.
Phase A - Claim verification
Full claim catalog and source evidence
# Phase A - Claims verificationPR: microsoft/aspire.dev #1588
PR head: e24dac84f3c54cadeb88c0224b381da578d32e2f
Source of truth: microsoft/aspire, main, 4a8b541c973baeb271f244603b0289c3f47933cf
Generated reference input represented by the PR: microsoft/aspire@69db530a4816698cf1d5fa4557933e0ac4f127c6
Counts
| Verdict | Count |
|---|---|
| Verified | 24 |
| Verified with nuance | 1 |
| Unverifiable | 0 |
| Contradicted | 4 |
| Total | 29 |
Catalog
| ID | Location | Normalized claim | Verdict | Evidence |
|---|---|---|---|---|
| COMP-01 | ApiReference.astro:47-54, PR body |
The component renders an API-reference link. | Contradicted | The template contains no a, href, or route resolution. |
| COMP-02 | ApiReference.astro:15-44, PR body |
The prop is a fully qualified API identity that can be looked up. | Contradicted | The prop is an arbitrary string; the examples are simple names, and apiNames performs only a last-segment casing rewrite with no metadata lookup or validation. |
| COMP-03 | ApiReference.astro:25-44 |
The last dotted segment pivots between PascalCase and camelCase. | Verified | lastIndexOf('.') preserves the prefix and rewrites only the first leaf character. |
| COMP-04 | ApiReference.astro:84-88 |
C# is the fallback language when no component storage value exists. | Verified | apply(readStored()) sets data-aspire-lang to csharp when no value is found. |
| COMP-05 | ApiReference.astro:92-101 |
Pointer-clicking a Starlight aspire-lang tab updates the component language. |
Verified | The delegated click handler reads the Starlight storage key after the click. |
| COMP-06 | ApiReference.astro:103-106 |
A language change in another window updates the component. | Verified | The storage listener handles the Starlight storage key. |
| COMP-07 | ApiReference.astro:56-107 |
The component shares a guard and storage key with ContainerImages. |
Verified | Both components use window.__aspireLangPivot and starlight-synced-tabs__aspire-lang. |
| API-01 | add-aspire-existing-app.mdx:68, glossary.mdx, troubleshooting.mdx |
WithReference exists in C# and TypeScript. |
Verified | Aspire.Hosting.ResourceBuilderExtensions.WithReference; TS capability Aspire.Hosting/withReference. |
| API-02 | add-aspire-existing-app.mdx:68, glossary.mdx, troubleshooting.mdx |
WaitFor exists in C# and TypeScript. |
Verified | Aspire.Hosting.ResourceBuilderExtensions.WaitFor; TS capability Aspire.Hosting/waitFor. |
| API-03 | glossary.mdx |
WaitForCompletion exists in C# and TypeScript. |
Verified | C# WaitForCompletion; TS capability Aspire.Hosting/waitForResourceCompletion with display name waitForCompletion. |
| API-04 | glossary.mdx |
WaitForStart exists in C# and TypeScript. |
Verified | C# WaitForStart; TS capability Aspire.Hosting/waitForStart. |
| API-05 | app-host.mdx |
WithPersistentLifetime exists in C# and TypeScript. |
Verified | C# API surface and TS capability Aspire.Hosting/withPersistentLifetime. |
| API-06 | add-aspire-existing-app.mdx |
AddExecutable exists in C# and TypeScript. |
Verified | C# API surface and TS capability Aspire.Hosting/addExecutable. |
| API-07 | aspire-mcp-server.mdx |
ExcludeFromMcp exists in C# and TypeScript. |
Verified | C# API surface and TS capability Aspire.Hosting/excludeFromMcp. |
| API-08 | resource-mcp-servers.mdx |
The intended core WithMcpServer exists in C# and TypeScript. |
Verified | Core C# method and TS capability Aspire.Hosting/withMcpServer. A same-named Community Toolkit C# method exports as withInspectedMcpServer, demonstrating why FQN resolution is required. |
| API-09 | resource-mcp-servers.mdx |
The intended PostgreSQL WithPostgresMcp exists in C# and TypeScript. |
Verified | Aspire.Hosting.PostgresBuilderExtensions.WithPostgresMcp; TS capability Aspire.Hosting.PostgreSQL/withPostgresMcp. An Azure PostgreSQL API shares the simple name. |
| API-10 | app-host.mdx, faq.mdx |
AddUvicornApp exists in C# and TypeScript. |
Verified | PythonAppResourceBuilderExtensions.AddUvicornApp; TS capability Aspire.Hosting.Python/addUvicornApp. |
| API-11 | app-host.mdx |
WithUv exists in C# and TypeScript. |
Verified | C# [AspireExport]; TS capability Aspire.Hosting.Python/withUv. |
| API-12 | app-host.mdx, faq.mdx |
AddNodeApp exists in C# and TypeScript. |
Verified | C# JavaScript hosting API; TS capability Aspire.Hosting.JavaScript/addNodeApp. |
| API-13 | app-host.mdx |
WithNpm exists in C# and TypeScript. |
Verified | C# JavaScript hosting API; TS capability Aspire.Hosting.JavaScript/withNpm. Other packages also expose same-named functions, so package identity matters. |
| API-14 | deploy-first-app.mdx, faq.mdx |
AddViteApp exists in C# and TypeScript. |
Verified | C# JavaScript hosting API; TS capability Aspire.Hosting.JavaScript/addViteApp. |
| API-15 | deploy-first-app.mdx, faq.mdx |
AddJavaScriptApp exists in C# and TypeScript. |
Verified | C# JavaScript hosting API; TS capability Aspire.Hosting.JavaScript/addJavaScriptApp. |
| API-16 | faq.mdx:102 |
AddPythonApp exists as a current API. |
Verified with nuance | Both language APIs exist, but the C# overloads are [Obsolete] in PythonAppResourceBuilderExtensions.cs:179,221, recommending AddPythonScript, AddPythonModule, or AddPythonExecutable. |
| API-17 | faq.mdx:102 |
AddPythonModule exists in C# and TypeScript. |
Verified | C# method and TS capability Aspire.Hosting.Python/addPythonModule. |
| API-18 | glossary.mdx |
WithEnvironment exists in C# and TypeScript. |
Verified | Core C# overloads and TS capability Aspire.Hosting/withEnvironment. |
| API-19 | glossary.mdx |
AddPostgres is provided by Aspire.Hosting.PostgreSQL in both languages. |
Verified | Aspire.Hosting.PostgresBuilderExtensions.AddPostgres; TS capability Aspire.Hosting.PostgreSQL/addPostgres. |
| API-20 | glossary.mdx:403 |
Core IResourceBuilder<T>.WithAnnotation has a TypeScript counterpart named withAnnotation. |
Contradicted | No Aspire.Hosting/withAnnotation exists. The only generated TS withAnnotation is Aspire.Hosting.Kubernetes/withAnnotation, an incompatible KubernetesManifestResource method taking key and value. |
| API-21 | resource-mcp-servers.mdx:131 |
Calling WithMcpServer() uses the root path. |
Contradicted | McpServerResourceBuilderExtensions.WithMcpServer defaults path to /mcp. |
| API-22 | resource-mcp-servers.mdx |
WithMcpServer and WithPostgresMcp use diagnostics ASPIREMCP001 and ASPIREPOSTGRES001. |
Verified | Attributes in McpServerResourceBuilderExtensions.cs and PostgresBuilderExtensions.cs. |
Blocking source findings
- The component does not implement the promised lookup or link.
- Simple names cannot identify package/type/member identity and cannot honor explicit
AspireExportrenames. - The component invents a core TypeScript
withAnnotationAPI that does not exist. - The changed MCP page states the wrong default path.
- The changed FAQ foregrounds an obsolete C# API without noting its replacements.
Phase B - Doc-tester results
Documentation Test Report
Focus Area: PR #1588 ApiReference behavior on the eight changed get-started routes
Date: 2026-09-01
Tester: doc-tester agent
Served ref: e24dac84f3c54cadeb88c0224b381da578d32e2f
Local URL: http://localhost:4321/
Summary
| Category | Passed | Failed | Warnings |
|---|---|---|---|
| Changed routes load | 8 | 0 | 0 |
| API-reference rendering | 23 | 20 | 0 |
| API-reference links | 0 | 43 | 0 |
| Language synchronization paths | 2 | 2 | 0 |
| Code examples / CLI commands | N/A | N/A | 0 |
Critical Issues
Issue 1: API references do not link to API documentation
Location: All eight changed routes
Type: Link
Severity: Critical
What the pull request promises:
Render a link to the API reference documentation.
What actually happens:
Browser inspection found 43
.api-referenceinstances and zero descendant links. None of the rendered API names can be followed to either the C# or TypeScript API reference.
Evidence:
The changed routes contained 43 component instances in total; querySelectorAll('.api-reference a') returned zero links on every route.
Recommended Action:
- Resolve each fully qualified API identifier against the generated reference data.
- Render a canonical C# or TypeScript API-reference link for the active language.
Issue 2: Inline references break paragraph markup and disappear
Location: Seven of the eight changed routes
Type: Component rendering / accessibility
Severity: Critical
What the documentation intends:
API names should read as inline code within prose.
What actually happens:
The component places Starlight's block-level
Codeoutput inside<span>elements. The browser repairs that invalid inline structure by moving the generated<div class="expressive-code">and<figure>outside the component. Twenty of 43.api-referenceelements are empty at their intended inline position, and the same 20 API names become detached code blocks with visible copy controls.
Evidence:
On /get-started/app-host/, the sentence "To also keep the container running ... add" ends before the API name. WithPersistentLifetime() appears as a separate figure with a "Copied WithPersistentLifetime() to clipboard" button, followed by the remainder of the sentence. The same failure occurs 20 times across the changed routes.
Recommended Action:
- Render valid phrasing content, such as an
<a><code>...</code></a>structure, instead of embedding a block code component inside<span>. - Add browser coverage that asserts each reference remains inside its containing paragraph or list item and does not expose a copy button.
Issue 3: Keyboard and PivotSelector language changes leave API names stale
Location: /get-started/resource-mcp-servers/ and /get-started/deploy-first-app/
Type: Component behavior / accessibility
Severity: Critical
What the component claims:
The API name pivots with the page's C#/TypeScript language selection.
What actually happens:
A pointer click on a Starlight TypeScript tab updates the API name, but two other supported language-change paths do not. Clicking the page's
PivotSelectorchanges the URL and both local-storage keys to TypeScript whiledata-aspire-langand the visible API name remain C#. Keyboard-selecting the TypeScript Starlight tab changes the selected tab, URL, local storage, and canonicaldata-apphost-langvalue, butdata-aspire-langremains C# and the API names remain PascalCase.
Evidence:
After clicking the TypeScript PivotSelector, the URL was ?aspire-lang=typescript and storage contained aspire-lang=typescript plus starlight-synced-tabs__aspire-lang=TypeScript, while both rendered attributes remained C# and AddJavaScriptApp stayed visible. After pressing ArrowRight on the C# Starlight tab, the selected tab and data-apphost-lang became TypeScript while data-aspire-lang and WithMcpServer() stayed C#.
Recommended Action:
- Consume the site's canonical
data-apphost-langstate instead of registering a second global state attribute and partial event listener. - Cover pointer, keyboard,
PivotSelector, query-string initialization, and persisted initialization.
Warnings
Warning 1: Simple names provide no authoring or reader disambiguation
Location: All changed <ApiReference name="..."> usages
Issue: The rendered text provides no package, declaring type, overload, or destination. A new user cannot determine which WithReference, WithMcpServer, or similarly named API is intended.
Suggestion: Require a fully qualified identifier and validate it against the generated API data, while displaying the short language-appropriate label.
Passed Checks
- All eight affected routes loaded successfully from the PR head.
- A full navigation with
?aspire-lang=csharpor?aspire-lang=typescriptinitialized non-empty references to the requested language. - Clicking a Starlight TypeScript tab with a pointer updated non-empty API references.
- Reloading after a
PivotSelectorchange restored the TypeScript API labels from persisted state. - No component-specific browser warnings were emitted.
Knowledge Gap: API identity
What I needed to know: Which package, declaring type, overload family, and language-specific API page each short name refers to.
Source of my knowledge: The rendered documentation did not provide this information.
User impact: New users cannot use the reference as a path to learn the API or distinguish same-named APIs.
Recommendation:
- Make the component's link and fully qualified authoring identifier the source of this context.
Recommendations
- Priority fixes: Correct the invalid inline markup, render real API links from fully qualified identifiers, and use the canonical language state.
- Documentation gaps: Migrate every changed usage to an exact FQN and keep the displayed label concise.
- Product issues: Add resolver, component, validator, and browser tests; a static string-inclusion test cannot detect any of the critical failures above.
| name: 'ApiReference renders both C# and TypeScript casings and the language pivot script', | ||
| Component: ApiReference, | ||
| props: { name: 'AddPostgres()' }, | ||
| includes: [ |
There was a problem hiding this comment.
These substring checks all pass while the rendered component has no links, 20 usages disappear from inline prose, detached copy controls are exposed, and keyboard/PivotSelector changes leave labels stale. Please split the lookup into a pure resolver with tests for exact FQNs, overload families, export renames, ambiguity, missing symbols, and missing counterparts; then add parsed-DOM/browser coverage for inline structure, hrefs, and every supported language-change path. The authoring validator also needs focused typo/ambiguity diagnostics tests.
…creating a new one.
Build and cache indexed C# and TypeScript API metadata, validate authored references, and support package-qualified ambiguous names. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Summary
Adds an inline
<ApiReference />Astro component that resolves a canonical C# fully qualified member name and renders the corresponding C# or TypeScript API name and reference link using the site's existing AppHost language preference.When multiple packages declare the same FQN, authors can disambiguate it with the optional
packageprop:What changed
<ApiReference />usage through the MDX AST, including JSX inside expressions and exports, while ignoring examples in code fences and comments.Performance
The current generated catalogs produce 8,062 indexed API entries. In a local benchmark, building the complete index took approximately 88 ms, while one million repeated resolutions took approximately 16 ms after initialization.
The browser receives only static HTML and CSS, so adding hundreds of references across the documentation does not add client-side listeners, catalog data, or lookup work.
Validation
Third-party links and affiliations
None