A single-file static viewer for issues.json build output from Rari (when run with --issues). No build step — open index.html from a local HTTP server and browse, filter, group, and export the issue set.
The deployment at https://caugner.github.io/mdn-flawless/ shows the issues.json from the last production build of https://developer.mozilla.org/.
python3 -m http.server
# or
npx http-server .Then open http://localhost:8000/ (or http://localhost:8080/). The page streams issues.json with a live progress bar and flattens it into a searchable table.
- Full-text search across message, file, URL, redirect, source, slug, basepath, macro, and sidebar (space-separated tokens, AND semantics).
- Faceted dropdowns with live counts: Category, Repository, Locale, Macro (templ), Sidebar, Source position (with/without line info).
- The Category filter groups options into Sources (entries where the linter
sourceitself is the category, e.g.broken-link,templ-ill-cased-arg) and Messages (parsed from the error text, e.g.Parse error). Selecting a group header filters by the whole kind (URL hash:category=__sources__/__messages__). - The Macro filter groups macros by type (Link, Sidebar, List, Component, Banner, Badge, Embed, Other / Unclassified). Each type heading is a bold divider with the total issue count, and selecting its "(all …)" option filters by the whole type (reflected in the URL hash as e.g.
templ=__link__). - "File path contains" substring filter.
- Click any pill (repo, locale, macro, sidebar, category) in a row to filter by that value.
- Reset clears all filters; the button highlights whenever any filter is active.
- Group by Category, URL, Slug, or File path.
- Group rows are sortable by key or count, and expand inline to reveal their issues.
- Sortable columns (File, Category, Message); keyboard-accessible headers.
- Search-term highlighting via
<mark>. - File cell links to the GitHub blob with
?plain=1and preciseL#C#-L#C#anchors (1-based, derived from the 0-based source spans). - Slug links to the live MDN page using normalized locale casing (e.g.
pt-br→pt-BR). - Pagination (50 / 200 / 500 / 2000 per page) with prev/next and a page indicator.
- Copy MD — Markdown table of the filtered list (or grouped summary), with an active-filter list and a link back to the live view. The Category column is omitted when a specific category filter is active.
- Copy CSV — same data as CSV (grouped or flat).
- Copy JSON — same data as a pretty-printed JSON array, one object per issue.
- Row selection — tick the checkbox column to copy only the chosen rows; the label switches between "Copy all N …" and "Copy N selected … as". Shift-click extends a range; the header checkbox toggles all (with a tri-state indicator). Selection clears on filter, sort, or grouping changes.
- Sticky header, dark mode via
prefers-color-scheme. - Gradient MDN-M favicon (favicon.svg).
- URL hash mirrors all filters — links are shareable, and back/forward updates the view.
aria-livestats line shows filtered/total issue count plus file and slug counts.
Each row in issues.json is flattened into a single record with the following fields. See flatten() in index.html.
| Field | Description |
|---|---|
repo |
Derived from the path: content, translated-content, translated-content-de (when locale is de), or curriculum. |
filePath |
Path to the source .md file, normalized to start at content/, translated-content/, or curriculum/curriculum/ (absolute prefix from the linter run is stripped). |
file |
The file the linter actually parsed. Usually equal to filePath. |
line / col / endLine / endCol |
1-based source position, with endCol inclusive. Used as-is for GitHub anchors (L11C96-L11C155), except endCol, which is incremented because GitHub's end anchor is exclusive. |
| Field | Description |
|---|---|
source |
The linter check that produced the issue (e.g. templ-broken-link, templ-redirected-link, broken-link). |
message |
Human-readable error text. May be empty for some sources (e.g. broken-link), in which case source acts as the category. |
category |
Coarse bucket extracted from the start of message: longest matching known prefix, else the part before :, else the first 4 words. Sources named with three or more kebab segments (e.g. templ-ill-cased-arg) are specific enough on their own, so they are categorized by source alone instead of by message (whose embedded argument would otherwise create one category per argument). Coarser sources like image-check keep their per-message categories. |
sourceCategory |
What the Category filter uses: source: category when the message drives the category, otherwise the category alone (the source name, or the message category when there is no source). Keeps e.g. templ-broken-link and broken-link distinguishable even when their messages categorize the same. |
| Field | Description |
|---|---|
locale |
MDN locale (en-US, de, pt-BR, …). Normalized to MDN URL casing when linking out. |
slug |
Document slug, e.g. Glossary/Leading. Linked to developer.mozilla.org/{locale}/docs/{slug}. |
basepath |
Base path span reported by the linter. Searchable, not displayed as a column. |
templ |
Rari template (macro) being expanded when the issue was found (e.g. glossary, cssxref). |
sidebar |
Sidebar context, if any. Filterable via the Sidebar dropdown and displayed as a pill in the row. |
| Field | Description |
|---|---|
url |
The URL the linter was checking (e.g. the target of a broken link). |
redirect |
For redirect issues, the URL it actually redirects to. |
See LICENSE.