fix(jsxref): build Web/JavaScript index to resolve names#715
Merged
Conversation
Replace the two per-call `RariApi::get_page_nowarn()` probes in `jsxref`
with a single lookup against a lazy `HashMap<String, IndexSet<String>>`
of all `Web/JavaScript/Reference/*` page slugs.
Each page is indexed under its full sub-path, its `Global_Objects/`-
stripped form, and — for pages under a `JavascriptNamespace` parent
(`Intl`, `Temporal`) — its namespace-stripped form. The path structure
naturally separates a namespace class (`Collator`) from its constructor
(`Collator/Collator`) and members (`Collator/compare`).
Authors can now reference:
- `{{jsxref("Collator", "Intl.Collator")}}` → `Intl/Collator`
- `{{jsxref("Collator/compare")}}` → `Intl/Collator/compare`
without the `Intl/` prefix, fixing `templ-redirected-link` flaws in
translated-content where the prefix was omitted.
`{{jsxref("null")}}`, `{{jsxref("typeof")}}`, `{{jsxref("instanceof")}}`
and similar bare operator references resolve via a leaf shortcut for
each `Web/JavaScript/Reference/Operators/<leaf>` page.
Fixes a regression introduced by the index where translated content
using bare operator names produced `templ-broken-link` flaws — the old
code's per-call `get_page_nowarn` would follow a `Global_Objects/null`
redirect, while the index only contained the canonical `Operators/null`
slug.
Adds bare-leaf shortcuts for `Statements/<keyword>` pages so
`{{jsxref("const")}}`, `{{jsxref("let")}}`, `{{jsxref("return")}}` etc.
resolve without a `Statements/` prefix.
A handful of keywords (`function`, `class`, `import`, `async_function`)
exist as both a statement and an operator expression. Instead of
picking one with a heuristic, `resolve_js_ref` refuses to resolve when
a bucket holds multiple canonical sub-paths and emits a
`templ-invalid-arg` tracing event listing the candidates, so the
author can add the qualifying category prefix.
Drops the `.to_lowercase()` from index keys and from lookup. JavaScript
naming distinguishes classes (`Set`, `Function`, `Map`) from
methods/keywords (`set`, `function`, `class`) by case, and authors use
that distinction consistently. The previous case-insensitive scheme
collapsed both into one bucket and reported ~826 spurious "ambiguous"
flaws for PascalCase class references like `{{jsxref("Set")}}` (446
occurrences) and `{{jsxref("Function")}}` (380 occurrences) across
content and translated-content.
Also replaces the dynamic `JavascriptNamespace` page-type scan with a
hardcoded list of *class-style* namespaces (`Intl`, `Temporal`).
Static-API namespaces (`Reflect`, `Atomics`, `Math`, `JSON`) are now
excluded: their direct children are methods, not classes, and aliasing
e.g. `Reflect.set` under bare `set` collided with the global `Set`
class.
Only genuinely ambiguous bare references — lowercase `function`,
`class`, `import`, `async_function` — still trip the
`templ-invalid-arg` flaw.
Lookups remain case-sensitive by default (so `Set` ≠ `set` and
`Function` ≠ `function`), but a wrong-case input that has a single
canonical match — e.g. `{{jsxref("Undefined")}}` for
`Global_Objects/undefined` — now resolves via a case-insensitive
fallback. The resolver still flags it with a new `templ-ill-cased-arg`
tracing event listing the canonical sub-path so authors can fix the
casing.
Multiple case-folded matches (e.g. some hypothetical `Foo`/`foo` pair)
fall back to the existing `templ-invalid-arg` refusal.
Adds the new `IssueType::TemplIllCasedArg` variant with a dedicated
explanation that references both the supplied arg and the canonical
form.
Pairs the case-preserved primary map with a derived lowercase map in a `JsRefIndex` struct, both populated once when `build_index` runs. The case-insensitive fallback in `resolve_from_index` is now O(1) instead of an O(N) scan across all ~6k primary keys on every miss.
Switch `JsRefIndex` value type from `String` to `Arc<str>` so the canonical sub-path heap buffer is shared between `primary` and `lowercase`, and across the multiple primary keys that point to the same page (e.g. `Statements/const` and the bare `const` leaf). Cuts the per-page allocations done by `index_one` and `from_primary` to one `Arc::from` plus refcount bumps. Lookup behavior is unchanged; `resolve_from_index` still returns `&str` via `Arc::as_ref`.
jsxref to resolve names via a Web/JavaScript/Reference index
Contributor
|
fb02ef6 was deployed to: https://rari-pr715.review.mdn.allizom.net/ |
This was referenced May 22, 2026
Merged
Open
[pt-br] Replace
{{domxref}} with {{jsxref}} for DOMString and USVString
mdn/translated-content#36177
Merged
Merged
[zh-cn] Replace
{{domxref}} with {{jsxref}} for DOMString and USVString
mdn/translated-content#36179
Merged
caugner
added a commit
to mdn/translated-content
that referenced
this pull request
May 22, 2026
…ator shorthands Use the bare-keyword shortform for the 5 operator keywords `null`, `this`, `delete`, `new`, `instanceof` per the convention introduced in mdn/content#44221. The shortform resolves cleanly on current rari thanks to the `Reference/<kw>` -> `Reference/Operators/<kw>` redirects that PR added, and resolves natively under the index-aware rari from mdn/rari#715. Only collapses the redundant-display pattern (`("Operators/X", "X")`); longforms with custom display text (`"delete x"`, `"deleted"`, `"x instanceof y"`) are preserved.
caugner
added a commit
to mdn/translated-content
that referenced
this pull request
May 22, 2026
Mirrors the en-US redirects added in mdn/content#44221 for the 5 operator-keyword shorthands (`null`, `this`, `delete`, `new`, `instanceof`). Without these per-locale redirects, the bare-keyword `{{jsxref("null")}}` shortform produces a 404 under the deployed rari; with them, it falls back via redirect to the canonical `Reference/Operators/<kw>` page. The index-aware rari from mdn/rari#715 resolves the shortform directly without needing the redirect.
caugner
added a commit
to mdn/translated-content
that referenced
this pull request
May 22, 2026
…ator shorthands Use the bare-keyword shortform for the 5 operator keywords `null`, `this`, `delete`, `new`, `instanceof` per the convention introduced in mdn/content#44221. The shortform resolves cleanly on current rari thanks to the `Reference/<kw>` -> `Reference/Operators/<kw>` redirects that PR added, and resolves natively under the index-aware rari from mdn/rari#715. Only collapses the redundant-display pattern (`("Operators/X", "X")`); longforms with custom display text (`"delete x"`, `"deleted"`, `"x instanceof y"`) are preserved.
This was referenced Jul 15, 2026
caugner
added a commit
to mdn/translated-content
that referenced
this pull request
Jul 16, 2026
Resolve `jsxref` macro arguments that no longer point at an existing `Web/JavaScript/Reference/*` page. An upcoming rari change (mdn/rari#715) resolves these against an index instead of probing candidate URLs and following redirects, which surfaces such stale references as broken links.
caugner
added a commit
to mdn/translated-content
that referenced
this pull request
Jul 16, 2026
Resolve `jsxref` macro arguments that no longer point at an existing `Web/JavaScript/Reference/*` page. An upcoming rari change (mdn/rari#715) resolves these against an index instead of probing candidate URLs and following redirects, which surfaces such stale references as broken links.
caugner
added a commit
to mdn/translated-content
that referenced
this pull request
Jul 16, 2026
Resolve `jsxref` macro arguments that no longer point at an existing `Web/JavaScript/Reference/*` page. An upcoming rari change (mdn/rari#715) resolves these against an index instead of probing candidate URLs and following redirects, which surfaces such stale references as broken links.
caugner
marked this pull request as ready for review
July 16, 2026 10:21
mfuji09
pushed a commit
to mdn/translated-content
that referenced
this pull request
Jul 16, 2026
Resolve `jsxref` macro arguments that no longer point at an existing `Web/JavaScript/Reference/*` page. An upcoming rari change (mdn/rari#715) resolves these against an index instead of probing candidate URLs and following redirects, which surfaces such stale references as broken links.
LeoMcA
approved these changes
Jul 17, 2026
LeoMcA
left a comment
Member
There was a problem hiding this comment.
Overall looks good! A handful of things I noticed:
Move name normalization (`()` strip, `.prototype.` collapse, member `.` → `/`) out of `jsxref_parts` and into `resolve_js_ref`. The `.` → `/` mapping only makes sense against the `/`-separated sub-paths the index is keyed by, so the index should own it — indexing and normalization now evolve together. Convert only a *lone* `.`; leave runs intact so triple-dot statements resolve by their bare leaf (`for...of` no longer mangles to `for///of`). No current en-US or translated content uses the bare triple-dot forms, so build issue counts are unchanged. The dotted-member index tests now feed raw names (`Array.prototype.map`) through `normalize` instead of pre-slashed keys, so they exercise the normalization they describe.
Replace the packed negated condition with named `prev_is_dot` / `next_is_dot` neighbor checks and an `in_dot_run` intermediate, so the member-separator rule reads directly. No behavior change.
caugner
added a commit
to mdn/translated-content
that referenced
this pull request
Jul 17, 2026
Resolve `jsxref` macro arguments that no longer point at an existing `Web/JavaScript/Reference/*` page. An upcoming rari change (mdn/rari#715) resolves these against an index instead of probing candidate URLs and following redirects, which surfaces such stale references as broken links.
LeoMcA
approved these changes
Jul 17, 2026
LeoMcA
approved these changes
Jul 17, 2026
caugner
added a commit
to mdn/translated-content
that referenced
this pull request
Jul 17, 2026
Resolve `jsxref` macro arguments that no longer point at an existing `Web/JavaScript/Reference/*` page. An upcoming rari change (mdn/rari#715) resolves these against an index instead of probing candidate URLs and following redirects, which surfaces such stale references as broken links.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Update
jsxrefto resolve names against a lazy in-memory index of all en-USWeb/JavaScript/Reference/*page slugs, instead of two per-callRariApi::get_page_nowarnprobes. The index:Statements/for...of).Global_Objects/-stripped form (Array,Array/from,undefined), theOperators/*andStatements/*bare leaves (null,typeof,const,return), and a namespace strip for the class-style namespacesIntlandTemporal(Collator→Intl/Collator,Collator/compare→Intl/Collator/compare).Set/setandFunction/functionare distinguishable), falling back to a precomputed lowercase map on miss to keep the case-folded fallback O(1).When a case-sensitive miss has exactly one case-folded match, the lookup resolves but emits a new
templ-ill-cased-argflaw pointing at the canonical casing. When a bucket has multiple case-sensitive candidates (today: lowercasefunction,class,import,async_function), the resolver refuses and emitstempl-invalid-arg.A fragment embedded directly in the argument (e.g.
{{jsxref("Array.prototype.map#examples")}}) is split off before normalization and the index lookup, then re-appended to the URL, so the bare name still resolves via the index. When both an embedded fragment and the separateanchorargument are given, the embedded fragment wins andanchoris ignored (emittingtempl-invalid-arg); emptyanchorarguments are filtered first. This mirrorscssxref(#682).Motivation
{{jsxref("Collator", "Intl.Collator")}}) that the old code couldn't resolve to a canonical path and emitted astempl-redirected-link.get_page_nowarnprobes followed redirects silently, masking stale slugs in content and inflatingtempl-redirected-linknoise (2,588 onmain).Additional details
build --grep jsxrefacross en-US + all translated locales (es,fr,ja,ko,pt-br,ru,zh-cn,zh-tw), counting onlyjsxref-sourced issues, against current content (2026-07-16, after the prerequisite cleanups below merged):maintempl-redirected-linktempl-broken-linktempl-ill-cased-arg(new)templ-invalid-arg(new)(Excludes 2 unrelated
must be a stringargument-type errors, identical on both sides.)The remaining diagnostics are genuine and were previously masked behind redirect chains:
templ-ill-cased-arg(16): wrong-case references such asoperators/import(canonicalOperators/import).templ-invalid-arg(7): the genuinely ambiguous{{jsxref("function")}}(bothOperators/functionandStatements/functionexist); the resolver refuses rather than guessing. Each also produces atempl-broken-linkto/Reference/functionvia the fallback. Fixed in content by fix: link{{jsxref("Function")}}in callback parameter descriptions content#44732 (disambiguates these 7 to{{jsxref("Function")}}).templ-broken-linkare real stale slugs in translated content (e.g.Gramatica_lexica,StopIteration,ParallelArray,Object.prototype.watch()) that will be fixed in translated-content via Fix stalejsxrefreferences surfaced by index-based resolution translated-content#37059 (one draft PR per locale).Related issues and pull requests
Relates to #672, #682 (same indexing pattern applied to
domxrefandcssxref).Follow-up translated-content cleanup for the remaining stale
templ-broken-linkreferences surfaced above (one draft PR per locale):jsxrefreferences surfaced by index-based resolution translated-content#37059Prerequisite translated-content cleanups (all merged):
jsxrefmacro args translated-content#36163jsxrefmacro args translated-content#36164jsxrefmacro args translated-content#36165jsxrefmacro args translated-content#36166jsxrefmacro args translated-content#36167jsxrefmacro args translated-content#36168jsxrefmacro args translated-content#36169jsxrefmacro args translated-content#36170