`CodeBlock` picked `github-light` only when the theme was exactly `light`, but
`Theme` also has `auto`, the value for anyone who has not opened the theme
menu, and `theme()` is `null` during prerendering. Both fell to `github-dark`,
so the samples in the Signals, Control Flow and Deferrable Views tabs on
https://angular.dev rendered on a dark slab inside a light page.
Resolve the theme in `ThemeManager`, which already owns the `auto` translation.
`resolvedTheme` returns `light` when `theme()` is `null`, which happens only
during prerendering, so `window` is never read. The device scheme moves into a
signal so `auto` also reacts to OS scheme changes.
(cherry picked from commit 8576f161ae)
The tutorials README documents how tutorial content, routes and the shared
common project are laid out, and several of those statements no longer match
the pipeline.
Links: eight links were written as `/src/content/...`. GitHub rewrites a
root-relative markdown link to `/<owner>/<repo>/blob/<branch>/<path>`, so they
resolved to `angular/angular/blob/main/src/content/...` and returned 404. They
now use the repo-root path, matching the convention already used in
`adev/src/app/editor/README.md`.
Routes: the step examples claimed the number prefix is dropped, giving
`/tutorials/learn-angular/components-in-angular`. `routes.mts` emits the step
directory name verbatim and uses the number only for ordering, and the
production sitemap lists only the numbered form, so the two examples and the
bullet describing the step URL are corrected.
Common project: `adev/src/content/tutorials/common` was removed in #53511 and
the shared project now lives in `adev/shared-docs/pipeline/tutorials/common`.
The section also documents the per-tutorial `common` directory that
`tutorial_index.mts` applies on top of the shared one, and drops the reference
to `app.module.ts`, which the standalone common project does not have.
Update dependencies: the script covered five of the eight projects that carry
a package-lock.json. `signals/common`, `signal-forms/common` and the shared
common are added; all eight are already updated together by lock file
maintenance.
The README is excluded from `generate_guides`, so no rendered page changes.
Building `//adev/src/content/tutorials/...` with and without this change
produces byte-identical output across all 213 generated files.
(cherry picked from commit 8037e4ac08)
`docs-alert` was the only marked extension in the pipeline without a `start`
hook, so marked never cut `inlineText` short at an alert and swallowed any
directive that was not at the start of the inline source. Writing the alert on
its own line without a blank line before it left the literal text in the body.
On https://angular.dev/guide/http/testing two alerts render as boxes and a
third shows as `IMPORTANT:` in the paragraph text. Also affects
https://angular.dev/errors/NG3003 and the first step of the first app tutorial.
The same renderer handles JSDoc, so one API page changes too:
https://angular.dev/api/upgrade/static/downgradeModule has three `NOTE:`
continuation lines inside bullets that now render as alerts.
`docs-video` and `docs-pill` already declare `start` the same way.
(cherry picked from commit 4043800ef2)
`visibleLines="26-131"` is not valid JSON, so `expandRangeStringValues` threw
and returned an empty list. The rendered attribute was empty, and the viewer
treats that as no range at all, so no ExampleViewer was created:
https://angular.dev/tutorials/first-app/08-ngFor showed all 128 lines of
`home.ts` with no collapse and no expand control, including the `@for` block
the reader has not written yet.
The file is 128 lines and the property this step adds ends at 127. The sibling
snippet on the same page already uses the `[start,end]` form.
(cherry picked from commit d3ccf5ca82)
The marker was written `# docregion`, but the hash matcher expects
`# #docregion`, one hash for the comment and one for the marker. It was not
recognised, so it was never stripped and rendered as the first line of the
Apache config on https://angular.dev/guide/i18n/deploy.
The sibling `nginx.conf`, shown on the same page, already has the correct form.
(cherry picked from commit 93f17e0bdf)
`watchPreferredColorScheme` applied the OS scheme unconditionally, while
`setTheme`, `loadThemePreference` and the bootstrap script in index.html all
only follow it for `auto`. Choosing Light and then letting the OS switch to
dark repainted the site dark while the theme menu still reported Light, until
a reload restored it.
(cherry picked from commit b7d432794e)
`isKnownRoute` exempted both families behind TODOs waiting on route extraction
for those packages. That extraction had already landed when the TODOs were
written in #66254: cdk pages since #60853 and aria pages since the cross-repo
workflow. `defined-routes.json` carries 70 `api/cdk` and 39 `api/aria` routes
today, and all 45 such link targets in the guides resolve, so the build stays
green without the exemptions.
The gap was not theoretical. `guide/aria/select.md` and
`guide/aria/multiselect.md` linked `api/cdk/overlay/CdkConnectedOverlay`, which
has never been a route, and it shipped as a 404 for six months. Link validation
landed four months into that and said nothing, because of this exemption. It
took a user filing #68914 and an outside contributor fixing it in #68915.
Pointing an existing `api/cdk` link at a symbol that does not exist passes the
build today and fails it with this change.
(cherry picked from commit b0cda277da)
`relative-link.pipe.spec.ts` and `is-active-navigation-item.pipe.spec.ts`
arrived with this package's BUILD file in #57132, but no test target came with
them and `lib` excludes `**/*.spec.ts`, so nothing has ever compiled them.
`bazel query` reports both as not declared in the package.
They pass unmodified. `getRelativeUrl` has no other coverage in the repo, and
both pipes are used by the search dialog, the navigation list and the not
found page.
(cherry picked from commit d3b0bb1d8c)
`getTagSinceVersion` matched `\d+(\.\d+)?` anywhere in the tag comment. That
works for `@developerPreview`, `@experimental` and `@stable`, whose comment is
only a version, but `@deprecated` also carries a message, so any number in the
prose won. https://angular.dev/api/common/getLocaleCurrencyCode reads
"deprecated since v4217", taken from "a map of locale to ISO 4217 currency
codes", and eighteen sibling pages take v18 from the "i18n" in "relying on the
`Intl` API for i18n".
Anchoring the match, and allowing the `since`/`from`/`as of` prefixes the
comments use, leaves all seventy-nine correctly versioned comments untouched.
`generate_manifest` carries its own copy of the regex, so the API list badges
had the same values.
Those `@angular/common` comments never stated a version, so they now say `18.0`
explicitly, the release `d34c033902` (#54483) first shipped in, matching the
`@deprecated 18.0` already on `FormatWidth` in the same file. Nine tags in that
file had no version at all and were showing no badge; they are from the same
commit and now say `18.0` too.
(cherry picked from commit 0bdbbcf4a8)
`WARNING:` is not an `AlertSeverityLevel`, so the paragraph rendered as plain
body text on https://angular.dev/guide/forms/signals/cross-field-logic while
the three other alerts on the page rendered normally. `CRITICAL` is the level
kitchen-sink.md defines for warning the reader off a footgun.
The five `@Component({/* ... */})` collapses are the formatter's. The file has
drifted out of prettier since it landed, and `ng-dev format changed --check`
checks whole changed files.
(cherry picked from commit 0029c3ba5a)
Five more defects in the example viewer, following #70508.
The DOM was queried before Angular rendered it. `setCodeLinesVisibility()`
walks the rendered lines but ran synchronously on tab change, so it measured
the outgoing tab and the incoming file showed in full. The selected tab was
also lost when the code block was hidden and reshown, because the recreated
tab group had no `[selectedIndex]` while `snippetCode` survived, leaving the
strip and the code disagreeing.
`expandable` was computed once at startup by counting hidden DOM nodes, so a
collapsed tab offered no way to expand it, and recomputing that count on tab
change would drop the control whenever the block was expanded, since nothing
is hidden then. Both paths now share one rule: a file is expandable when it
has a `visibleLinesRange` and either the block is expanded or the range
actually hides lines, so a range that covers its whole file still gets no
inert control.
Array indices were also mixed with 1-based line numbers: the gap check tested
`index - 1` for the preceding line, drawing a `...` separator inside
contiguous ranges, and the gutter tested `index` while the code tested
`index + 1`, shifting every line number by one.
Five new specs cover these, using the comma-separated range format the
pipeline emits; each fails with its fix reverted. The tab label also moves
from 0.8125rem to 0.875rem to match the code beside it.
(cherry picked from commit 26afa313f3)
When navigation items contain external URLs (e.g. https:// links for documentation or third-party resources), mapNavigationItemsToRoutes previously registered them as Angular Router route definitions. In recent versions of @angular/build, the static prerender worker asserts that discovered routes do not return empty content during SSG prerendering, causing production builds and CI adev-deploy to fail on these routes.
This change filters out external links in mapNavigationItemsToRoutes so only valid internal application paths are registered as Angular routes.
(cherry picked from commit 502fa130aa)
Two tutorial steps list a file in `openFiles` that does not exist, and a
missing entry is dropped without complaint. `first-app/05-inputs` asks for
`housinglocations.ts` when the file is `housinglocation.ts`; since
`hiddenFiles` is everything not in `openFiles`, the interface that step
teaches was marked hidden rather than opened.
`signals/5-component-communication-with-signals` asks for
`quantity-selector.ts`, which exists in neither `src` nor `answer`. Every
openFiles entry in the tutorials now resolves.
(cherry picked from commit 45148dae44)
The code block lives inside `@if (showCode())`, so hiding it destroys the DOM and
showing it builds a fresh copy with no hidden lines. Nothing reapplied
`setCodeLinesVisibility()`, so a collapsed block came back showing the whole file.
Reapply it once the block is rendered again. It already branches on `expanded()`,
so a block that was expanded stays expanded.
(cherry picked from commit 90b9e081f5)
`reactive-forms` and `form-validation` were excluded from `embeddable` in
full, with a TODO to fix them. The examples are fine; four partial snapshots
quoted by the guides are not, since each shares the final template of the
component it precedes, which references members it does not have yet.
Excluding those four files clears all 30 errors and puts 23 app files back in
the preview pool, so both guides' final components can be previewed for the
first time.
(cherry picked from commit 431b170fd5)
The block quotes a `.ts` file but declares `language="html"`, and shiki's
HTML grammar does not know Angular control flow, so the whole `@for` line
renders unstyled. Use `angular-ts`, matching the other blocks in the
tutorial.
(cherry picked from commit c03e872ed9)
Three ways a callout could be misparsed:
- A title quoted with `'` or a backtick was dropped, leaving an empty
heading. Two callouts lose their title on angular.dev today, on
guide/forms/template-driven-forms and guide/i18n/prepare. The first has
to use single quotes because its title contains `"pristine"`.
- A title containing `>` was dropped, because the attribute capture
stopped at the first `>` even inside a quoted value.
- The severity was matched anywhere in the tag, so a title such as
"Why this is important" silently rendered an important callout.
Scan attributes with quoting in mind, accept all three quote characters
as #69268 did for docs-code-block, and match the severity flags against
the tag with attribute values removed. The i18n callout also spelled the
attribute `header`, which the extension has never read.
(cherry picked from commit b70edd2768)
`input.svg` and `output.svg` are leftovers that #70335 missed. Their
last reference was deleted by #54829 when the AIO guides were removed,
and nothing in the repo mentions them or their directory. Removing both
empties `adev/src/assets/images/guide/inputs-outputs`.
(cherry picked from commit a92f6057d3)
RESOURCE_COMPLETED_BEFORE_PRODUCING_VALUE had no guide, no JSDoc on
RxResourceOptions.stream, and — since the code was positive rather
than negative — could never get an auto-linked docs page even if one
existed. Flip it to -991, add the NG0991 reference page, and document
the "stream must emit a value or an error before completing"
requirement on stream's JSDoc and in the RxJS interop guide.
Also documents and tests that an unguarded template read of an
errored resource's .value() propagates to the global ErrorHandler,
and recommends guarding with .hasValue() as defense in depth.
httpResource can throw the same error, but for a different reason:
its internal request Observable isn't something app code writes
directly, so an empty completion there is almost always an
HttpInterceptor swallowing the response (catchError(() => EMPTY))
rather than a stream authored in the resource() call itself. The page
covers both APIs with guidance matched to what's actually going on
for each.
(cherry picked from commit 8975b4346d)
There's a short window where Angular can't send errors to ErrorHandler
yet: while it's still building the root module or root component. It
needs that root instance to look up the ErrorHandler you provided, so
an error thrown before it exists just becomes a normal uncaught error
instead.
This mostly bites people using Angular elements, where a custom element
tag already sitting in the page gets upgraded (and its component built)
the moment you call customElements.define, which can happen very early.
Added a short section to the error handling guide explaining why this
happens and the usual ways around it: setTimeout, APP_BOOTSTRAP_LISTENER,
or moving element registration to ngDoBootstrap.
Fixes#29211
(cherry picked from commit ca38305976)
Associate each recommendation with its checkbox so assistive technology has a descriptive label and non-interactive text toggles the control. Keep embedded links independently operable.
(cherry picked from commit d8e74e7d39)
The 34 pages using `<docs-decorative-header>` render their title
through `getPageTitle()` without passing the markdown file path, so
the "Edit this page" link is silently dropped. Every other page keeps
it. Compare https://v19.angular.dev/guide/components, which still has
the pencil, against https://angular.dev/guide/components, which does
not.
`filePath` was required until #63536 made it optional, so API
descriptions with no editable source could render a title without a
link. That removed the compile error forcing the decorative header to
supply it, and the argument was lost with nothing to catch it.
Pass the path again and cover both header variants with tests, since
the edit link had no coverage at all.
(cherry picked from commit acdac1cb89)
An unclosed `<docs-step>` or `<docs-card>` produces no error, just wrong
output, so the two cases fixed in the previous commit went unnoticed for
years.
Validate that the paired custom elements balance before parsing. A
mismatch now names the file and the counts instead of silently
swallowing a section.
(cherry picked from commit d9afca095b)
`reactive-forms.md` and `app-shell.md` each open a `<docs-step>` that is
never closed. The tokenizers match up to the *next* closing tag instead
of failing, so the unclosed tag pulls in the content that follows and
leaves the block after it unparsed in the output.
On https://angular.dev/guide/forms/reactive-forms the "Creating nested
form groups" section shows raw source: "To create a nested group in
`profileForm`, add a nested `address` element", backticks and all. Its
heading is swallowed into the unclosed step instead of being an h3, and
the page renders 20 of its 21 steps. On
https://angular.dev/ecosystem/service-workers/app-shell the third step
is missing entirely.
`reactive-forms.md` has been broken since #52536, `app-shell.md` since
#55550.
(cherry picked from commit 0752282c8f)
The tutorial's example files shifted without the README line references
following, so several steps point at the wrong code. In two cases every
requested line is past the end of the file; on the inputs step this renders
as a code block with no lines visible at all.
(cherry picked from commit 46b02cc181)
Both indices point past the end of their block, so the intended lines are
never highlighted. The reactive forms block renders with no highlight at all,
and the first example in output-interop.md highlights nothing while its
sibling block is unaffected.
(cherry picked from commit cd3c8cdd3a)
The common tutorial scaffold's .gitignore opens with a link to
help.github.com/ignore-files/, which 404s. That directory is copied into every
tutorial and playground, so the dead link ships to anyone who opens one.
(cherry picked from commit 843a65cba0)
An example-config.json marked a directory as a doc example and told aio's
example tooling which boilerplate to use and what to run against it. #56496
removed that tooling in June 2024. Eight of these fifteen files are empty and no
code has read any of them since; the name survives only in the zip and
StackBlitz exclude lists, which skip it rather than open it.
(cherry picked from commit ddfd8a8e9b)
The `built-in-directives` and `structural-directives` example apps are no
longer referenced. Two guide rewrites moved their pages to inline code fences
and dropped the last references without removing the apps: #69134 for
structural directives, and #69822 for built-in directives, whose page is gone
entirely. Both apps sat inside the `embeddable` glob, so they were still
compiled as preview components on every build.
The example e2e suites are excluded from every consumer by design: previews
ignore `*.e2e-spec.ts` and `*.po.ts`, and the zip and StackBlitz pipelines
both list the suffix in `EXCLUDE_FILES`. They could not run in any case,
since every spec declares a `driver` and never assigns it before calling
`driver.get('')`, left over from an abandoned protractor to selenium
migration.
The eslint configuration in the same directory is also unused. Nothing in the
repository depends on eslint, and `tsconfig.eslint.json` extends a path that
no longer exists.
(cherry picked from commit 90fc9475f2)
`guide/http/security` and `reference/concepts` both still exist as content but
neither is routed, so each falls through to the 404 shell.
`guide/http/security` was navigable from November 2023 until #54365 removed its
entry in February 2024. #55029 then copied its XSRF sections into the security
guide, which already covered XSSI, and #55060 repointed the remaining links, so
it now redirects to `/best-practices/security`.
`reference/concepts` was added by #54365 and removed by #58694 in November
2024, leaving it navigable for nine months without a redirect. The same commit
also removed `guide/ngmodules`, the route its only card linked to, so both now
redirect to `/guide/ngmodules/overview`, alongside the four `guide/ngmodules/*`
paths already redirected there.
Both pages are removed, along with the Bazel package that existed only to build
the concepts page, and the stale `llms-list.md` entry for the HttpClient page.
The security guide takes its place in that list, so `llms-full.txt` keeps its
XSSI coverage and picks up CSP, Trusted Types and sanitization with it.
(cherry picked from commit 7da60d1920)
The `msapplication` tile configuration serves no purpose now, so the
`browserconfig.xml` it points at, the five tile images and the two meta tags
in `index.html` are removed together.
`shared-docs/icons/twitter.svg` is also unused, left behind when the footer
moved to X and Bluesky. Its three siblings in that directory are all still
referenced.
(cherry picked from commit a67d4027e2)
Two headings on the same page can generate the same anchor id, and every
link to it then resolves to whichever comes first. Nothing caught this
because the route manifest keeps anchors in a `Set`, so a repeat collapses
into one entry before any check runs, and the existing link validation only
asks whether an anchor exists, which a duplicate satisfies.
The generator now inspects each page's headings while they are still an
ordered list and fails with the offending pages and anchors. The scanning
and the duplicate check move to `heading.mts` so they are covered by tests
next to `getIdFromHeading`, which should keep this from coming back.
(cherry picked from commit 5e8a70a010)
Eight guides have headings that generate the same anchor id twice or more.
Because an id resolves to the first element that claims it, the table of
contents lists two entries pointing at the same place, the second section
cannot be reached from the ToC at all, and the copy link button on the
later heading hands out a URL for the earlier one.
On `guide/forms/reactive-forms` the two "Display the component" steps sit
5176px apart and both ToC entries scroll to the first.
Give the later heading on each page an explicit id with the `{#custom-id}`
syntax the pipeline already supports. Only later duplicates are changed, so
every anchor that resolves today keeps pointing at the same heading.
(cherry picked from commit 698a14d735)
Most of these came over from the angular.io docs and were orphaned as adev
rewrote or dropped the guides that used them. Two are newer: a devtools
screenshot that was added but never referenced, and the logo left behind
when the Firebase Studio launcher was removed. All of them are still
copied into the build and served from angular.dev.
No markdown, template, stylesheet, TypeScript file or build target
references any of them, by filename or through a path built at runtime,
and the images are globbed into the build rather than listed, so nothing
else needs updating. Removes 78 files, 5.15 MB in total, and empties
nineteen directories.
(cherry picked from commit 355a9d83e3)