Skip to content

Add client-side syntax highlighting for code blocks in lessons - #130

Merged
ebouchut merged 4 commits into
devfrom
feat/lesson-syntax-highlighting
Aug 2, 2026
Merged

Add client-side syntax highlighting for code blocks in lessons#130
ebouchut merged 4 commits into
devfrom
feat/lesson-syntax-highlighting

Conversation

@ebouchut

@ebouchut ebouchut commented Aug 2, 2026

Copy link
Copy Markdown
Owner

This PR adds client-side syntax highlighting for code blocks in lessons.
It uses a pinned, self-hosted highlight.js bundle.

Why

Fenced code blocks in lessons are rendered monochrome, even though the
renderer has emitted code class="language-java" since ADR-0013, where
the sanitizer deliberately kept the class on code "for a future
syntax highlighter".
This PR adds the highlighter.

How

Client-side highlighting on the same pattern as the Mermaid feature
(ADR-0016: the server keeps shipping sanitized, text-only code blocks
and the browser upgrades them. Decision recorded in
ADR-0017.

  • docs(plan): implementation plan
    (docs/plans/2026-07-31-lesson-syntax-highlighting.md)
  • docs(adr): ADR-0017, highlight.js over Prism, a server-side
    highlighter, or nothing
  • build(deps): pinned org.webjars.npm:highlightjs__cdn-assets
    11.11.1, zero transitives. The cdn-assets artifact is deliberate:
    since v11 the plain highlight.js WebJar ships only bundler modules
    and no browser build
  • feat(frontend): lesson-highlight.js loads the bundle lazily, only
    when the lesson contains a language-* fence other than
    language-mermaid, and highlights only languages the bundle knows;
    unknown hints and bare fences stay monochrome by design (no
    auto-detect guessing). Token colors map to the existing surface-safe
    accent tokens, so both themes pass WCAG AA with no vendor CSS to fork

Verification

  • Full test suite (78) and Checkstyle green. The existing renderer test
    pinning language-java survival through sanitization is untouched.
  • Verified in the browser on a seeded lesson: java, python, sql, and
    bash fences gain colored tokens in both themes; an unknown-language
    fence and a bare fence stay monochrome; a mermaid fence is skipped by
    the highlighter and still renders as a diagram; axe (WCAG 2.1 A/AA)
    reports zero violations in both themes; no horizontal page scroll.

Note

No sanitizer, renderer, or cache change: the whole diff is one JS
file, one CSS block, one dependency, two template lines, and docs.

Fenced code blocks in lessons render monochrome even though the
renderer has emitted language-tagged markup since ADR-0013. The plan
adds a client-side highlighter on the ADR-0016 pattern: pinned
self-hosted highlight.js, lazy-loaded, explicit languages only, token
colors mapped to the surface-safe theme accents.

Refs #128
ADR-0017 closes the seam ADR-0013 left open (the sanitizer keeps the
code class for a future syntax highlighter) with the same shape as
ADR-0016: the browser upgrades sanitized markup, the server changes
nothing. highlight.js is chosen over Prism (needs a bundler or
per-language tags for equal coverage) and over any server-side
highlighter (would force span classes through the sanitizer and bake
presentation into the content-addressed cache). Token colors map to
the theme accents already proven surface-safe, so both themes pass AA
by construction.

Refs #128
The bundle ships self-hosted through
org.webjars.npm:highlightjs__cdn-assets, version pinned where
Dependabot can see it (highlight.js has had ReDoS advisories). The
cdn-assets artifact is deliberate: since v11 the plain highlight.js
webjar contains only bundler modules and no browser build. Jar content
verified (highlight.min.js with the common languages baked in) and the
POM declares zero transitive dependencies, confirmed with
dependency:tree. Lesson pages require authentication, so the existing
catch-all rule already authorizes the /webjars path.

Refs #128
Language-tagged code blocks rendered monochrome even though the
renderer has emitted the language-* class since ADR-0013, kept through
sanitization for exactly this feature. lesson-highlight.js now closes
that seam on the ADR-0017 decision: it loads the self-hosted
highlight.js bundle lazily, only when the lesson contains a
language-tagged fence other than mermaid, and highlights only blocks
whose language the bundle recognizes. Unknown hints and bare fences
stay monochrome by design (no auto-detect guessing), and mermaid
fences remain the diagram feature's territory.

Token colors come from a small hand-written mapping to the theme
accent tokens already proven to clear 4.5:1 on the surface background
in both themes, so highlighted code follows the design system and any
future token retuning with no vendor CSS to fork. The lesson form
hints that fences take a language tag.

Fixes #128
@ebouchut ebouchut self-assigned this Aug 2, 2026
@ebouchut ebouchut added frontend course Course/Lesson labels Aug 2, 2026
@ebouchut ebouchut moved this to In Progress in learn-dev-project Aug 2, 2026
@ebouchut ebouchut moved this from In Progress to In Review in learn-dev-project Aug 2, 2026
@ebouchut ebouchut added this to the v1.0- Certification - DWWM milestone Aug 2, 2026
@codecov

codecov Bot commented Aug 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.71%. Comparing base (da15d16) to head (4342f95).

Additional details and impacted files
@@            Coverage Diff            @@
##                dev     #130   +/-   ##
=========================================
  Coverage     81.71%   81.71%           
  Complexity      202      202           
=========================================
  Files            38       38           
  Lines           864      864           
  Branches         53       53           
=========================================
  Hits            706      706           
  Misses          124      124           
  Partials         34       34           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ebouchut
ebouchut merged commit f9984ef into dev Aug 2, 2026
7 checks passed
@ebouchut
ebouchut deleted the feat/lesson-syntax-highlighting branch August 2, 2026 20:07
@github-project-automation github-project-automation Bot moved this from In Review to Done in learn-dev-project Aug 2, 2026
@ebouchut ebouchut added documentation Improvements or additions to documentation feature dependencies labels Aug 2, 2026
@ebouchut ebouchut linked an issue Aug 2, 2026 that may be closed by this pull request
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

course Course/Lesson dependencies documentation Improvements or additions to documentation feature frontend

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Syntax-highlight lesson code blocks by language

1 participant