Skip to content

feat(highcharts): migrate Highcharts from Python to JavaScript (Phase 2, deprecation window) #8242

@MarkusNeusinger

Description

@MarkusNeusinger

Summary

Migrate Highcharts from its current Python entry (highcharts-core wrapper) to a native JavaScript entry, executed as a deprecation window so existing links don't break. This is Phase 2 of docs/concepts/library-expansion.md and the second of three issues splitting the JavaScript rollout:

This is a meta / infrastructure issue, not a spec request — do not apply the spec-request label.

Depends on #8241. This issue reuses the javascript language entry, the Node + Playwright render harness, the framework metadata field, the per-library extension handling, and all the workflow/frontend/backend plumbing stood up there. Do not start until #8241 has merged (or land it as a stacked PR on the same branch).


Why move it

Per docs/concepts/library-expansion.md §6 (the "most-used variant" rule) and §1:

| 8 | Highcharts | JavaScript | Python | JavaScript | npm ~1 M / wk vs highcharts-core ~5 k / wk |

The native highcharts.js outweighs the Python highcharts-core wrapper by ~200× weekly downloads — far past the ≥ 3× threshold — so the rule mandates the canonical entry move to JavaScript. Highcharts is the industry standard in finance/news dashboards; the JS audience is who actually uses it.

License note (unchanged): Commercial, free for non-commercial use. Keep the license tag and surface it prominently on the plot pages — same as today.


The careful bit: deprecation window (§6 + §9)

§6's "Exception — deprecation window": when a library moves languages, both entries may co-exist for one release cycle so existing links/bookmarks/SEO don't break, then the superseded entry is dropped.

Execution:

  1. Flip the registry (core/constants.py): highcharts entry's language_id "python""javascript", framework: "none", refresh version + description to the JS library (verify version against feat(javascript): add JavaScript runtime + render harness + Chart.js, D3.js, ECharts (Phase 1) #8241's package-lock.json). New impls generate under implementations/javascript/highcharts.js.
  2. Keep the Python impls on disk and served. Do not delete plots/*/implementations/python/highcharts.py in this PR — they keep serving for one release.
  3. 301-redirect old deep links: /{spec}/python/highcharts/{spec}/javascript/highcharts, so bookmarks and SEO are preserved. (Recommended approach. Alternative: a one-release deprecation banner on the Python pages pointing at the JS variant. State which in the PR.)
  4. LIB_TO_LANG['highcharts'] = 'javascript' in app/src/constants/index.ts. This deliberately points the library→language map at JS while the Python files still exist on disk; the redirect (step 3) bridges the gap. Document as time-boxed.
  5. Generation targets JS only: ensure bulk-generate.yml / daily-regen.yml regenerate highcharts as the JavaScript variant; the Python files are frozen (served, not regenerated).

The acceptable fallback, if dual-serve + redirect is more than the team wants in one PR: flip the canonical entry to JS and immediately stop serving the Python pages, accepting that old /python/highcharts links 404. Recommended: the 301 redirect — cheap and preserves SEO. Decide and state in the PR.


Scope

1. Registry (core/constants.py)

2. Workflows

3. Prompt

  • Rewrite prompts/library/highcharts.md from Python to JavaScript. Current file uses from highcharts_core.chart import Chart and an inline selenium screenshot blob — replace entirely with:
    • The JS Highcharts API: Highcharts.chart('container', { ... }).
    • The harness mount contract from feat(javascript): add JavaScript runtime + render harness + Chart.js, D3.js, ECharts (Phase 1) #8241 (draw into #container; harness handles HTML scaffold + Playwright screenshot — no inline HTML/screenshot code in the snippet).
    • ANYPLOT_THEME light/dark chrome mapping (Highcharts theme / chart.backgroundColor / axis & label colors).
    • Canvas hard rule (3200×1800 / 2400×2400) via the harness viewport × deviceScaleFactor.
    • Commercial-license note kept prominent (free for non-commercial use).
    • //-comment header block (// Library: Highcharts <ver> | Node 22).
    • Forbidden patterns: no highcharts-core (that's the Python wrapper we're leaving), no CDN <script src> (use the pinned npm bundle), no Highcharts modules that require a separate commercial add-on beyond the base license terms.

4. Frontend (app/src/)

5. Backend (api/)

  • api/routers/specs.py: /api/specs/{spec}/highcharts/code?language=javascript returns the JS impl; the Python impl stays reachable for the deprecation window (e.g. ?language=python still 200s until the window closes, or is 301'd — match the frontend decision).
  • api/routers/debug.py, libraries.py: Highcharts now reports language_id: javascript; verify counters/columns follow.
  • Confirm /stats library count is unchanged (Highcharts is a move, not an add — still counts once).

6. Tests

  • tests/unit/core/test_constants.py: assert highcharts language_id == "javascript" and framework == "none".
  • Any test that pinned Highcharts as Python (fixtures, language-mapping assertions) gets updated.
  • A redirect test: /{spec}/python/highcharts → 301 → /{spec}/javascript/highcharts (or the chosen approach).
  • Frontend: LIB_TO_LANG / code-viewer test for highcharts → javascript.

7. Docs

  • docs/concepts/library-expansion.md: §1 table — Highcharts "In anyplot as" flips to JavaScript; §8 mark Phase 2 shipped; §9 record the deprecation-window execution (which approach: redirect vs. immediate cutover).
  • docs/reference/repository.md: note the temporary dual-location (python/highcharts.py frozen + javascript/highcharts.js canonical) during the window.

Acceptance criteria

  • core/constants.py: highcharts.language_id == "javascript", framework == "none", version/description refreshed for the JS library.
  • prompts/library/highcharts.md rewritten to the JavaScript Highcharts API + harness mount contract + commercial-license note.
  • gh workflow run impl-generate.yml -f specification_id=scatter-basic -f library=highcharts produces a passing JS Highcharts impl (plot-light.png + plot-dark.png + interactive HTML) in GCS.
  • /scatter-basic/javascript/highcharts loads code + preview in light & dark; ?language=javascript 200s.
  • Old /scatter-basic/python/highcharts 301-redirects to the JS variant (or the chosen §"deprecation window" approach is implemented and stated in the PR).
  • Python highcharts.py files remain on disk and (per the chosen approach) reachable for the deprecation window — not deleted in this PR.
  • /libraries shows Highcharts as a JavaScript library with the commercial-license badge; /stats library count unchanged (move, not add).
  • uv run pytest tests/unit tests/integration green; frontend yarn test --run, yarn tsc --noEmit, yarn lint clean.
  • docs/concepts/library-expansion.md §1/§8/§9 updated; Phase 2 marked shipped.

Out of scope (separate follow-up, one release later)

  • Closing the deprecation window: delete plots/*/implementations/python/highcharts.py, drop the 301 redirect, remove highcharts-core (and any now-unused selenium-for-highcharts deps) from pyproject.toml. Track as a dedicated follow-up issue so the window actually closes — per §6 it's exactly one release cycle.
  • JS Highcharts modules requiring extra commercial add-ons beyond the base license — only the base library surface is in scope.

Part of the JavaScript rollout split: foundation in #8241, MUI X in its sibling issue. Reviewed against docs/concepts/library-expansion.md §§1/6/8/9 and the Julia rollout (#7613).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestinfrastructureWorkflow, backend, or frontend issue

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions