Skip to content

Conversation

@hatemhosny
Copy link
Collaborator

@hatemhosny hatemhosny commented Jul 16, 2025

What type of PR is this? (check all applicable)

  • ✨ Feature
  • πŸ› Bug Fix
  • πŸ“ Documentation Update
  • 🎨 Style
  • ♻️ Code Refactor
  • πŸ”₯ Performance Improvements
  • βœ… Test
  • πŸ€– Build
  • πŸ” CI
  • πŸ“¦ Chore (Release)
  • ⏩ Revert
  • 🌐 Internationalization / Translation

Description

This PR continues on the previous PR (#857 - that added self-hosting using docker).
It allows running the app in docker while offline, with no internet connection.

LiveCodes depends on a large number of external modules to support a wide range of features (e.g. code editors, compilers, formatters, etc). These modules are loaded from CDNs (e.g. jsDelivr, unpkg, etc). So, in spite of being a client-side app, LiveCodes requires an internet connection to load these modules.

This PR allows LiveCodes to run without an internet connection. This can be achieved by setting the environment variable LOCAL_MODULES=true (it is set to false by default). In this case, all modules are downloaded during build (~ 1.5 GB), and are served locally.

The downloaded modules are cached in a docker layer and only re-downloaded when modules (in vendors.ts) change. This way, the code stays the source of truth.

See docs: https://local-modules.livecodes.pages.dev/docs/advanced/docker#local-modules

Related Tickets & Documents

#857

Closes #807

Mobile & Desktop Screenshots/Recordings

livecodes-local-modules.mp4
livecodes-offline-custom-modules.mp4

Added tests?

  • πŸ‘ yes
  • πŸ™… no, because they aren't needed
  • πŸ™‹ no, because I need help

Added to documentations?

  • πŸ““ docs (./docs)
  • πŸ“• storybook (./storybook)
  • πŸ“œ README.md
  • πŸ™… no documentation needed

I would appreciate it if you could have a look whenever suits you
@mtantawy @zyf722 @Seth0x41 @aabouzaid @BassemHalim @mrgb7 @sharno

Summary by CodeRabbit

  • New Features

    • Experimental "Local Modules" offline mode (LOCAL_MODULES) and Go (Wasm) language + starter templates.
  • Improvements

    • Updated runtime versions (Node, Pyodide/Python); refined vendor/resource URL resolution and conditional polyfill inclusion.
    • New build/runtime options for host, port and memory (NODE_OPTIONS).
  • Bug Fixes

    • Cache-control/static-serving rules adjusted to better cache module assets.
  • Documentation

    • Added offline modules guide and new language docs (Go, Markdown, MDX).
  • Chores

    • Added module download/copy scripts, dev-dependencies and vendor license entries; minor lint/config tweaks.

@netlify
Copy link

netlify bot commented Jul 16, 2025

βœ… Deploy Preview for livecodes ready!

Name Link
πŸ”¨ Latest commit e11fc0d
πŸ” Latest deploy log https://app.netlify.com/projects/livecodes/deploys/68d96c1602681c0008c123af
😎 Deploy Preview https://deploy-preview-858--livecodes.netlify.app
πŸ“± Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions
Copy link
Contributor

github-actions bot commented Jul 16, 2025

Size Change: +3.56 kB (+0.37%)

Total Size: 960 kB

Filename Size Change
./build/livecodes/codemirror.js 8.23 kB +1.9 kB (+30.01%) 🚨
ℹ️ View Unchanged
Filename Size Change
./build/404.html 997 B -6 B (-0.6%)
./build/app.html 250 B 0 B
./build/index.html 2.48 kB +7 B (+0.28%)
./build/livecodes/app.css 22.4 kB -4 B (-0.02%)
./build/livecodes/app.js 111 kB +96 B (+0.09%)
./build/livecodes/assets.js 8.65 kB +31 B (+0.36%)
./build/livecodes/assets/noop.js 18 B 0 B
./build/livecodes/assets/templates/diagrams-starter.html 2.19 kB 0 B
./build/livecodes/backup.js 3.75 kB +39 B (+1.05%)
./build/livecodes/blockly.js 13.3 kB +34 B (+0.26%)
./build/livecodes/broadcast.js 1.19 kB +2 B (+0.17%)
./build/livecodes/bundle-types.js 4.42 kB +46 B (+1.05%)
./build/livecodes/code-to-image.js 9.15 kB +40 B (+0.44%)
./build/livecodes/codejar.js 17.6 kB -14 B (-0.08%)
./build/livecodes/compile.page.js 2.42 kB +36 B (+1.51%)
./build/livecodes/compile.worker.js 14.3 kB +11 B (+0.08%)
./build/livecodes/compiler-utils.js 3.19 kB +16 B (+0.5%)
./build/livecodes/custom-editor-utils.js 198 B 0 B
./build/livecodes/deploy.js 6.89 kB +20 B (+0.29%)
./build/livecodes/editor-settings.js 17.8 kB +38 B (+0.21%)
./build/livecodes/embed-ui.js 5.59 kB +38 B (+0.68%)
./build/livecodes/embed.js 89.4 kB -80 B (-0.09%)
./build/livecodes/export.js 3.91 kB +21 B (+0.54%)
./build/livecodes/firebase.js 22.7 kB 0 B
./build/livecodes/format.worker.js 13.4 kB +4 B (+0.03%)
./build/livecodes/google-fonts.js 7.12 kB 0 B
./build/livecodes/headless.js 78.3 kB -56 B (-0.07%)
./build/livecodes/i18n-ar-language-info.json 5.23 kB 0 B
./build/livecodes/i18n-ar-translation.json 9.33 kB 0 B
./build/livecodes/i18n-de-language-info.json 5.25 kB 0 B
./build/livecodes/i18n-de-translation.json 9.44 kB 0 B
./build/livecodes/i18n-en-language-info.json 4.54 kB 0 B
./build/livecodes/i18n-en-translation.json 8.03 kB 0 B
./build/livecodes/i18n-es-language-info.json 5 kB 0 B
./build/livecodes/i18n-es-translation.json 9.17 kB 0 B
./build/livecodes/i18n-fa-language-info.json 5.35 kB 0 B
./build/livecodes/i18n-fa-translation.json 9.48 kB 0 B
./build/livecodes/i18n-fr-language-info.json 5.17 kB 0 B
./build/livecodes/i18n-fr-translation.json 9.42 kB 0 B
./build/livecodes/i18n-hi-language-info.json 5.78 kB 0 B
./build/livecodes/i18n-hi-translation.json 9.95 kB 0 B
./build/livecodes/i18n-it-language-info.json 5.04 kB 0 B
./build/livecodes/i18n-it-translation.json 9.26 kB 0 B
./build/livecodes/i18n-ja-language-info.json 5.57 kB 0 B
./build/livecodes/i18n-ja-translation.json 9.61 kB 0 B
./build/livecodes/i18n-pt-language-info.json 5.05 kB 0 B
./build/livecodes/i18n-pt-translation.json 9.35 kB 0 B
./build/livecodes/i18n-ru-language-info.json 5.56 kB 0 B
./build/livecodes/i18n-ru-translation.json 10.3 kB 0 B
./build/livecodes/i18n-ur-language-info.json 5.81 kB 0 B
./build/livecodes/i18n-ur-translation.json 9.78 kB 0 B
./build/livecodes/i18n-zh-CN-language-info.json 4.9 kB 0 B
./build/livecodes/i18n-zh-CN-translation.json 8.64 kB 0 B
./build/livecodes/i18n.js 20.2 kB +18 B (+0.09%)
./build/livecodes/import-src.js 16 kB -18 B (-0.11%)
./build/livecodes/import.js 14.5 kB +19 B (+0.13%)
./build/livecodes/index.js 5.41 kB +41 B (+0.76%)
./build/livecodes/lang-art-template-compiler.js 1.68 kB +24 B (+1.45%)
./build/livecodes/lang-assemblyscript-compiler.js 290 B 0 B
./build/livecodes/lang-assemblyscript-script.js 386 B 0 B
./build/livecodes/lang-astro-compiler.js 2.37 kB +30 B (+1.28%)
./build/livecodes/lang-clio-compiler.js 1.58 kB +27 B (+1.74%)
./build/livecodes/lang-commonlisp-script.js 123 B 0 B
./build/livecodes/lang-cpp-script.js 1.76 kB +17 B (+0.97%)
./build/livecodes/lang-cpp-wasm-script.js 2.87 kB +36 B (+1.27%)
./build/livecodes/lang-csharp-wasm-script.js 2.22 kB +42 B (+1.93%)
./build/livecodes/lang-diagrams-compiler-esm.js 5.12 kB +31 B (+0.61%)
./build/livecodes/lang-dot-compiler.js 1.69 kB +38 B (+2.29%)
./build/livecodes/lang-ejs-compiler.js 1.66 kB +29 B (+1.78%)
./build/livecodes/lang-eta-compiler.js 1.67 kB +19 B (+1.15%)
./build/livecodes/lang-fennel-compiler.js 1.63 kB +24 B (+1.49%)
./build/livecodes/lang-gleam-compiler.js 3.1 kB +11 B (+0.36%)
./build/livecodes/lang-go-wasm-script.js 3.29 kB +37 B (+1.14%)
./build/livecodes/lang-haml-compiler.js 1.68 kB +25 B (+1.51%)
./build/livecodes/lang-handlebars-compiler.js 1.96 kB +37 B (+1.93%)
./build/livecodes/lang-imba-compiler.js 147 B 0 B
./build/livecodes/lang-java-script.js 4.08 kB +32 B (+0.79%)
./build/livecodes/lang-jinja-compiler.js 1.67 kB +19 B (+1.15%)
./build/livecodes/lang-julia-script.js 3.31 kB +8 B (+0.24%)
./build/livecodes/lang-liquid-compiler.js 1.7 kB +16 B (+0.95%)
./build/livecodes/lang-lua-wasm-script.js 205 B 0 B
./build/livecodes/lang-malina-compiler.js 2.98 kB +25 B (+0.85%)
./build/livecodes/lang-mustache-compiler.js 1.67 kB +20 B (+1.22%)
./build/livecodes/lang-nunjucks-compiler.js 1.96 kB +28 B (+1.45%)
./build/livecodes/lang-perl-script.js 268 B 0 B
./build/livecodes/lang-php-wasm-script.js 347 B 0 B
./build/livecodes/lang-postgresql-compiler-esm.js 1.76 kB +34 B (+1.97%)
./build/livecodes/lang-prolog-script.js 204 B 0 B
./build/livecodes/lang-pug-compiler.js 371 B 0 B
./build/livecodes/lang-python-wasm-script.js 1.89 kB -31 B (-1.61%)
./build/livecodes/lang-r-script-esm.js 2.46 kB +28 B (+1.15%)
./build/livecodes/lang-rescript-compiler-esm.js 2.2 kB +40 B (+1.85%)
./build/livecodes/lang-rescript-formatter.js 1.54 kB +21 B (+1.38%)
./build/livecodes/lang-riot-compiler.js 2.84 kB +31 B (+1.1%)
./build/livecodes/lang-ruby-wasm-script.js 1.73 kB +25 B (+1.46%)
./build/livecodes/lang-scss-compiler.js 1.73 kB +20 B (+1.17%)
./build/livecodes/lang-solid-compiler.js 263 B 0 B
./build/livecodes/lang-sql-compiler.js 1.67 kB +27 B (+1.65%)
./build/livecodes/lang-sql-script.js 1.99 kB +42 B (+2.15%)
./build/livecodes/lang-svelte-compiler.js 4.71 kB +23 B (+0.49%)
./build/livecodes/lang-tcl-script.js 1.85 kB +28 B (+1.54%)
./build/livecodes/lang-teal-compiler.js 1.75 kB +30 B (+1.75%)
./build/livecodes/lang-twig-compiler.js 1.67 kB +24 B (+1.46%)
./build/livecodes/lang-vento-compiler.js 1.7 kB +15 B (+0.89%)
./build/livecodes/lang-vue-compiler.js 6.11 kB +21 B (+0.35%)
./build/livecodes/lang-vue2-compiler.js 3.5 kB +34 B (+0.98%)
./build/livecodes/lang-wat-compiler.js 348 B 0 B
./build/livecodes/lang-wat-script.js 1.6 kB +20 B (+1.26%)
./build/livecodes/language-info.js 7.71 kB +9 B (+0.12%)
./build/livecodes/monaco-lang-astro.js 947 B 0 B
./build/livecodes/monaco-lang-clio.js 639 B 0 B
./build/livecodes/monaco-lang-imba.js 7.35 kB 0 B
./build/livecodes/monaco-lang-wat.js 2.46 kB 0 B
./build/livecodes/monaco.js 10.1 kB +4 B (+0.04%)
./build/livecodes/open.js 6.24 kB +27 B (+0.43%)
./build/livecodes/processor-lightningcss-compiler.js 1.89 kB +10 B (+0.53%)
./build/livecodes/processor-postcss-compiler.js 2.05 kB +26 B (+1.28%)
./build/livecodes/processor-tailwindcss-compiler.js 5.23 kB +23 B (+0.44%)
./build/livecodes/processor-unocss-compiler.js 355 B 0 B
./build/livecodes/processor-windicss-compiler.js 450 B 0 B
./build/livecodes/quill.css 697 B 0 B
./build/livecodes/quill.js 5.78 kB +31 B (+0.54%)
./build/livecodes/resources.js 3.43 kB 0 B
./build/livecodes/result-utils.js 1.17 kB 0 B
./build/livecodes/share.js 3.84 kB +30 B (+0.79%)
./build/livecodes/snippets.js 6.08 kB +39 B (+0.65%)
./build/livecodes/sync-ui.js 3.28 kB +25 B (+0.77%)
./build/livecodes/sync.js 3.57 kB +46 B (+1.31%)
./build/livecodes/sync.worker.js 29.7 kB +10 B (+0.03%)
./build/livecodes/templates.js 25.4 kB -1 B (0%)
./build/sdk/livecodes.js 3.96 kB 0 B
./build/sdk/livecodes.umd.js 4.02 kB 0 B
./build/sdk/package.json 293 B 0 B
./build/sdk/react.js 4.24 kB 0 B
./build/sdk/vue.js 4.36 kB 0 B

compressed-size-action

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Jul 16, 2025

Deploying livecodes with Β Cloudflare Pages Β Cloudflare Pages

Latest commit: e11fc0d
Status:Β βœ…Β  Deploy successful!
Preview URL: https://b6ede0dc.livecodes.pages.dev
Branch Preview URL: https://local-modules.livecodes.pages.dev

View logs

@coderabbitai
Copy link

coderabbitai bot commented Jul 18, 2025

Walkthrough

Adds an experimental Local Modules mode (build-time downloader and runtime local /modules/ resolution), broad vendor URL refactors, Go (Wasm) language + starter and docs/i18n, async I/O server refactors, Docker/build arg additions, various client imports switched to dynamic module-service URLs, and ancillary lint/docs/test updates.

Changes

Cohort / File(s) Change Summary
Build & runtime configs
\.nvmrc, Dockerfile, docker-compose.yml
Bumped Node to v24.4.1; added build args/env: HOST_NAME, PORT, LOCAL_MODULES, NODE_OPTIONS; conditional build step to run npm run download-modules when LOCAL_MODULES=true; Docker base image updated.
Module caching & build scripts
scripts/download-modules.js, package.json, scripts/build.js, scripts/utils.js
New downloadModules script to download/cache vendor modules, fonts, and Pyodide into .cache/modules; new npm scripts download-modules and copy:modules; build scripts replace livecodes.io with self-hosted HOST_NAME/PORT and respect LOCAL_MODULES.
Services & module resolution
src/livecodes/services/modules.ts, src/livecodes/vendors.ts
Added local modules mode (LOCAL_MODULES); getUrl/getCdnUrl route through local /modules/ when enabled; new getLocalUrl helper; vendors refactored to many *BaseUrl and version/path updates.
Client imports & loaders
src/livecodes/main.ts, src/livecodes/html/app.html, src/livecodes/... (editor, languages, fonts, monaco, types, compile.worker.ts, editor-languages.ts, utils.ts, bundle-types.ts, etc.)
Replaced many *Url β†’ *BaseUrl; switched dynamic imports to use modulesService.getUrl(...) or constructed base paths (append index.js/CSS); conditional {{polyfillScript}} injection disabled when LOCAL_MODULES=true; removed FontAwesome injection for Python WASM; added Go (Wasm) language modules and loaders.
New language: Go (Wasm)
src/livecodes/languages/go-wasm/*, src/livecodes/templates/starter/go-wasm-starter.ts, src/livecodes/languages/languages.ts, src/sdk/models.ts
Added Go (Wasm) language spec, runtime script worker (Yaegi via wasm), starter template, registered language and template names, SDK type additions, and template registration.
Docs & i18n
docs/docs/advanced/docker.mdx, docs/docs/languages/*, docs/src/components/*, src/livecodes/i18n/locales/**
Added "Local Modules" docs and LOCAL_MODULES env var; added/expanded Markdown/MDX/Go/Go-Wasm docs; added i18n entries across locales for go-wasm and wasm starter templates; updated Pyodide version in docs.
Server async refactors & headers
server/src/app.ts, server/src/broadcast/index.ts, server/src/sandbox.ts, server/src/utils.ts, src/_headers
Switched several sync fs calls to async fs.promises; updated broadcast/sandbox to async flows; changed cache-control targets to prefer /modules/* for long-term immutable caching.
Compile & CSS processors
src/livecodes/compiler/compile-blocks.ts, src/livecodes/languages/tailwindcss/*
Skip injecting compiled CSS for certain processors (tailwindcss/unocss/windicss) in post-processing; added helper addCodeInStyleBlocks and integrated it into tailwind processor flows.
Client UI & templates
src/livecodes/templates/starter/*, docs/src/components/TemplateList.tsx, docs/src/components/LanguageSliders.tsx, src/livecodes/UI/command-menu-actions.ts
Added go-wasm starter template registrations and UI entries (templates list, language sliders, command menu).
Misc & housekeeping
eslint.config.mjs, src/livecodes/styles/inc-menu.scss, README.md, vendor-licenses.md, tests (src/livecodes/config/__tests__/*)
Added **/.cache to ESLint ignores; small SCSS gradient tweak; updated languages badge; added Yaegi licenses; new/updated tests for config param propagation and validation; formatting/devdeps updates in package.json.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Builder as Docker build
    participant Downloader as download-modules.js
    participant Image as Build image (.cache/modules)
    participant Server as App server (runtime)
    participant Browser as Browser

    Builder->>Downloader: If LOCAL_MODULES=true -> run download-modules
    Downloader-->>Image: Populate .cache/modules (fonts, libs, pyodide, files)
    Image->>Server: Include /modules assets in image
    Browser->>Server: Request app + /modules/...
    Server->>Browser: Serve /modules/* with immutable cache headers
    Browser->>Browser: modulesService.getUrl(...) resolves to /modules/... -> app loads resources offline
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

"I’m a little rabbit with a caching knack,
I hopped to distant CDNs and brought them back.
Fonts, Pyodide, scripts tucked in my lair,
Now the burrow serves modules β€” no net to spare.
Happy hops and offline builds! πŸ₯•"

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning While the core LOCAL_MODULES offline support meets the linked issue’s requirements, the pull request also introduces substantial unrelated changesβ€”such as Go-Wasm language integration (new language modules, templates, and extensive i18n updates), Python WASM version upgrades, ESLint ignore pattern updates, Node version bumps, and various refactoringsβ€”that fall outside the scope of issue [807]. Please split out the unrelated Go-Wasm support, language documentation and i18n updates, version upgrades, and linting or refactoring changes into separate pull requests so that this PR remains focused solely on LOCAL_MODULES offline support for issue [807].
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
βœ… Passed checks (3 passed)
Check name Status Explanation
Description Check βœ… Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check βœ… Passed The title β€œLocal modules!” succinctly captures the primary feature introduced by the pull requestβ€”adding support for serving and caching external vendor modules locally in an offline or self-hosted modeβ€”without extraneous details or noise. It is concise, clear, and directly related to the main change.
Linked Issues Check βœ… Passed The pull request fully implements the objective of issue [807] by introducing a LOCAL_MODULES flag, adding a download-modules script that caches all external vendor modules (~1.5 GB), updating the modulesService to resolve module requests to the local cache path, and adjusting Docker and application code to serve these modules without external network calls, thereby enabling a self-hosted offline setup for HTML, CSS, and JavaScript.
✨ Finishing touches
  • πŸ“ Generate Docstrings
πŸ§ͺ Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch local-modules

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❀️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (2)
docs/docs/languages/python-wasm.mdx (1)

104-104: Doc version bump looks correct

Pyodide 0.28.0 ships Python 3.13.2, so the wording is accurate. Ensure the live demo URLs (pyodideBaseUrl values) were updated everywhere else; mismatched versions silently break runtime loading.

docs/docs/advanced/docker.mdx (1)

184-186: Consider the suggested style improvements

The static analysis tool suggests some minor improvements for clarity:

  • Replace "a large number of" with "many" or "numerous" for conciseness
  • Add periods after "etc" in American English style
  • Consider replacing "in spite of" with "despite" for brevity
-LiveCodes depends on a large number of external modules to support a wide range of features (e.g. code editors, compilers, formatters, etc).
-These modules are loaded from CDNs (e.g. [jsDelivr](https://www.jsdelivr.com/), [unpkg](https://unpkg.com/), etc).
-So, in spite of being a client-side app, LiveCodes requires an internet connection to load these modules.
+LiveCodes depends on numerous external modules to support a wide range of features (e.g. code editors, compilers, formatters, etc.).
+These modules are loaded from CDNs (e.g. [jsDelivr](https://www.jsdelivr.com/), [unpkg](https://unpkg.com/), etc.).
+So, despite being a client-side app, LiveCodes requires an internet connection to load these modules.
πŸ“œ Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 4082e05 and cc5cb78.

β›” Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
πŸ“’ Files selected for processing (30)
  • .nvmrc (1 hunks)
  • Dockerfile (2 hunks)
  • docker-compose.yml (2 hunks)
  • docs/docs/advanced/docker.mdx (2 hunks)
  • docs/docs/languages/python-wasm.mdx (1 hunks)
  • eslint.config.mjs (1 hunks)
  • package.json (3 hunks)
  • scripts/build.js (3 hunks)
  • scripts/download-modules.js (1 hunks)
  • scripts/utils.js (4 hunks)
  • server/src/app.ts (1 hunks)
  • src/404.html (1 hunks)
  • src/_headers (1 hunks)
  • src/livecodes/compiler/compile.worker.ts (2 hunks)
  • src/livecodes/editor/codemirror/codemirror.ts (1 hunks)
  • src/livecodes/editor/codemirror/editor-languages.ts (1 hunks)
  • src/livecodes/editor/fonts.ts (11 hunks)
  • src/livecodes/editor/monaco/monaco.ts (2 hunks)
  • src/livecodes/html/app.html (1 hunks)
  • src/livecodes/languages/clojurescript/lang-clojurescript.ts (1 hunks)
  • src/livecodes/languages/diagrams/lang-diagrams-compiler-esm.ts (3 hunks)
  • src/livecodes/languages/postgresql/lang-postgresql-compiler-esm.ts (2 hunks)
  • src/livecodes/languages/python-wasm/lang-python-wasm-script.ts (1 hunks)
  • src/livecodes/languages/rescript/lang-rescript-compiler-esm.ts (2 hunks)
  • src/livecodes/languages/rescript/lang-rescript-formatter.ts (1 hunks)
  • src/livecodes/languages/utils.ts (2 hunks)
  • src/livecodes/main.ts (3 hunks)
  • src/livecodes/services/modules.ts (4 hunks)
  • src/livecodes/types/bundle-types.ts (2 hunks)
  • src/livecodes/vendors.ts (12 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (14)
src/livecodes/languages/rescript/lang-rescript-formatter.ts (3)
src/sdk/models.ts (1)
  • LanguageFormatter (1265-1267)
src/livecodes/utils/utils.ts (1)
  • getAbsoluteUrl (83-84)
src/livecodes/vendors.ts (1)
  • rescriptCdnUrl1 (388-390)
src/livecodes/languages/clojurescript/lang-clojurescript.ts (1)
src/livecodes/vendors.ts (1)
  • cherryCljsBaseUrl (54-54)
src/livecodes/editor/codemirror/codemirror.ts (2)
src/livecodes/services/modules.ts (2)
  • modulesService (35-87)
  • getAppCDN (89-97)
src/livecodes/vendors.ts (1)
  • codeMirrorBasePath (96-96)
src/livecodes/languages/postgresql/lang-postgresql-compiler-esm.ts (1)
src/livecodes/vendors.ts (1)
  • pgliteBaseUrl (328-328)
src/livecodes/languages/rescript/lang-rescript-compiler-esm.ts (1)
src/livecodes/vendors.ts (4)
  • rescriptCdnUrl1 (388-390)
  • rescriptCdnUrl2 (391-393)
  • rescriptCdnUrl3 (394-396)
  • rescriptCdnUrl4 (397-399)
src/livecodes/editor/codemirror/editor-languages.ts (2)
src/livecodes/services/modules.ts (2)
  • modulesService (35-87)
  • getAppCDN (89-97)
src/livecodes/vendors.ts (1)
  • codeMirrorBasePath (96-96)
src/livecodes/languages/utils.ts (1)
src/livecodes/vendors.ts (1)
  • vendorsBaseUrl (13-14)
src/livecodes/main.ts (2)
src/livecodes/services/modules.ts (1)
  • modulesService (35-87)
src/livecodes/vendors.ts (1)
  • codeMirrorBasePath (96-96)
src/livecodes/compiler/compile.worker.ts (2)
src/livecodes/services/modules.ts (2)
  • modulesService (35-87)
  • getAppCDN (89-97)
src/livecodes/vendors.ts (1)
  • codeMirrorBasePath (96-96)
src/livecodes/editor/fonts.ts (1)
src/livecodes/vendors.ts (19)
  • fontAnonymousProBaseUrl (138-138)
  • fontAstigmataBaseUrl (140-142)
  • fontCascadiaCodeBaseUrl (146-146)
  • fontComicMonoBaseUrl (152-152)
  • fontCourierPrimeBaseUrl (154-154)
  • fontDejaVuMonoBaseUrl (160-160)
  • fontFantasqueBaseUrl (162-164)
  • fontFiraCodeBaseUrl (166-166)
  • fontHackBaseUrl (172-172)
  • fontHermitBaseUrl (174-174)
  • fontIosevkaBaseUrl (188-188)
  • fontJetbrainsMonoBaseUrl (190-192)
  • fontMonoidBaseUrl (208-208)
  • fontOpenDyslexicBaseUrl (218-218)
  • fontRobotoMonoBaseUrl (224-224)
  • fontSourceCodeProBaseUrl (230-232)
  • fontSpaceMonoBaseUrl (234-234)
  • fontUbuntuMonoBaseUrl (240-240)
  • fontVictorMonoBaseUrl (242-242)
src/livecodes/languages/diagrams/lang-diagrams-compiler-esm.ts (2)
src/livecodes/utils/utils.ts (1)
  • loadScript (175-216)
src/livecodes/vendors.ts (2)
  • mermaidCdnUrl (298-298)
  • hpccJsCdnBaseUrl (258-258)
src/livecodes/editor/monaco/monaco.ts (1)
src/livecodes/vendors.ts (1)
  • monacoVolarBaseUrl (312-312)
src/livecodes/types/bundle-types.ts (1)
src/livecodes/vendors.ts (1)
  • vendorsBaseUrl (13-14)
src/livecodes/vendors.ts (1)
src/livecodes/services/modules.ts (1)
  • modulesService (35-87)
πŸͺ› LanguageTool
docs/docs/advanced/docker.mdx

[style] ~184-~184: To reduce wordiness, try specifying a number or using β€œmany” or β€œnumerous” instead.
Context: ...s (EXPERIMENTAL) LiveCodes depends on a large number of external modules to support a wide rang...

(LARGE_NUMBER_OF)


[style] ~184-~184: In American English, abbreviations like β€œetc.” require a period.
Context: ...g. code editors, compilers, formatters, etc). These modules are loaded from CDNs (e...

(ETC_PERIOD)


[style] ~185-~185: In American English, abbreviations like β€œetc.” require a period.
Context: ...ivr.com/), unpkg, etc). So, in spite of being a client-side a...

(ETC_PERIOD)


[style] ~186-~186: β€˜in spite of’ might be wordy. Consider a shorter alternative.
Context: ... unpkg, etc). So, in spite of being a client-side app, LiveCodes requ...

(EN_WORDINESS_PREMIUM_IN_SPITE_OF)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: Redirect rules - livecodes
  • GitHub Check: Header rules - livecodes
  • GitHub Check: Pages changed - livecodes
  • GitHub Check: type-check (18.x)
  • GitHub Check: build (18.x)
  • GitHub Check: build
  • GitHub Check: tests (18.x, 2)
  • GitHub Check: tests (18.x, 4)
  • GitHub Check: tests (18.x, 3)
  • GitHub Check: tests (18.x, 1)
  • GitHub Check: tests (18.x, 5)
  • GitHub Check: type-check (18.x)
  • GitHub Check: build (18.x)
πŸ”‡ Additional comments (53)
.nvmrc (1)

1-1: Ensure Node 24 Readiness Across Your Toolchain

It looks like none of your package.json files declare an engines.node field, so there’s no automatic guard against running on the wrong Node version. Before merging this bump to v24.4.1, please double-check the following:

β€’ Add or update engines.node in each package.json (root, docs, server, storybook) to >=24 so npm/yarn will warn on unsupported environments.
β€’ Verify your CI/production images (Dockerfiles, GitHub Actions workflows, etc.) have been updated to pull Node 24.x.
β€’ Confirm all major dependencies (including any native-addon prebuilds, husky hooks, linters, test runners) officially support Node 24.

src/404.html (1)

145-147: Link target changed – confirm no regressions

Docs now points to /docs instead of /docs/overview.
Make sure the doc site’s default route handles this (otherwise users will land on a blank page in SPAs when JS is disabled).

No code change needed if /docs already redirects/serves the TOC; otherwise consider keeping the old deep link.

eslint.config.mjs (1)

34-35: πŸ‘ Good call adding .cache to ESLint ignore list

This prevents ESLint from grinding through ~1.5 GB of vendored modules in offline mode.
No further action required.

src/livecodes/languages/rescript/lang-rescript-formatter.ts (1)

3-10: Respect baseUrl when resolving the compiler URL

rescriptCdnUrl1 may already resolve to a local path, but if a caller purposely overrides baseUrl (e.g. embedding LiveCodes in a sub-folder), the new logic ignores it.
Safer variant:

-    importScripts(getAbsoluteUrl(rescriptCdnUrl1, baseUrl));
+    const url = getAbsoluteUrl(rescriptCdnUrl1, baseUrl);
+    importScripts(url);

This keeps the current behaviour while still letting baseUrl win when the constant is relative.

Likely an incorrect or invalid review comment.

server/src/app.ts (1)

43-43: LGTM! Cache control path updated correctly for local modules.

The change from /assets/ to /modules/ aligns with the local modules feature implementation and maintains appropriate long-term caching for immutable module resources.

src/livecodes/languages/postgresql/lang-postgresql-compiler-esm.ts (2)

3-3: LGTM! Import updated to use base URL pattern.

The change from pgliteUrl to pgliteBaseUrl aligns with the standardized approach for vendor URL management in the local modules feature.


14-14: LGTM! Dynamic import correctly uses base URL with explicit file path.

The change to pgliteBaseUrl + 'index.js' provides explicit control over the module path and supports both local and remote module resolution.

src/livecodes/languages/clojurescript/lang-clojurescript.ts (1)

26-28: LGTM! Import paths standardized to use base URL pattern.

The changes from local paths ('lib/...') to cherryCljsBaseUrl + 'lib/...' ensure consistency with other cherry-cljs imports and support the local modules feature.

src/livecodes/languages/python-wasm/lang-python-wasm-script.ts (1)

2-2: Ensure FontAwesome stylesheet is still loaded for matplotlib icons

The removal of the fontAwesomeUrl import and its dynamic stylesheet injection in
src/livecodes/languages/python-wasm/lang-python-wasm-script.ts (prepareEnv) means we no longer see where the FontAwesome CSS is applied. Although src/livecodes/vendors.ts still exports fontAwesomeBaseUrl, I didn’t find any other injection of the stylesheet elsewhere in the TS/JS code.

Please confirm (either via a UI smoke-test or by inspecting your global startup modules) that the FontAwesome stylesheet is still being loaded so matplotlib icons continue to render properly.

β€’ File: src/livecodes/languages/python-wasm/lang-python-wasm-script.ts (prepareEnv)
β€’ File: src/livecodes/vendors.ts (exporting fontAwesomeBaseUrl)

src/_headers (2)

1-2: LGTM! Header configuration updated for new asset organization.

The change from /assets/* to /livecodes/* aligns with the broader reorganization of static asset serving paths.


4-5: LGTM! Cache control configured correctly for local modules.

The /modules/* path now receives immutable caching, which is appropriate for versioned modules and aligns with the server-side cache control changes in server/src/app.ts.

src/livecodes/html/app.html (1)

366-366: Good template abstraction for conditional polyfill loading.

The replacement of the hardcoded polyfill script with the {{polyfillScript}} template placeholder enables dynamic control over polyfill inclusion based on the LOCAL_MODULES environment variable. This supports the offline functionality effectively.

src/livecodes/editor/monaco/monaco.ts (2)

27-27: Correct import alias update for URL standardization.

The change from monacoVolarUrl to monacoVolarBaseUrl aligns with the broader effort to standardize vendor URLs from full file URLs to base URLs.


268-268: Proper dynamic import path construction.

The explicit concatenation of 'index.js' to the base URL correctly implements the new pattern where base URLs are used with explicit file suffixes appended at import sites.

src/livecodes/editor/codemirror/codemirror.ts (3)

44-44: Correct imports for dynamic URL resolution.

Adding getAppCDN and modulesService imports enables dynamic URL resolution based on configuration, supporting the local modules feature.


46-46: Proper import change for URL standardization.

The change from codeMirrorBaseUrl to codeMirrorBasePath aligns with the pattern of using base paths that are dynamically resolved to URLs.


51-51: Effective dynamic URL construction.

The dynamic construction of codeMirrorBaseUrl using modulesService.getUrl(codeMirrorBasePath, getAppCDN()) properly enables local vs CDN module resolution based on configuration.

src/livecodes/languages/utils.ts (2)

3-3: Correct import change for URL standardization.

The change from highlightjsUrl to vendorsBaseUrl aligns with the broader effort to standardize vendor URLs from specific file URLs to base URLs.


100-101: Proper dynamic import path construction.

The explicit concatenation of 'highlight.js/highlight.js' to the vendorsBaseUrl correctly implements the new pattern where base URLs are used with explicit file paths appended at import sites.

src/livecodes/editor/codemirror/editor-languages.ts (3)

15-15: Correct imports for dynamic URL resolution.

Adding getAppCDN and modulesService imports enables dynamic URL resolution based on configuration, supporting the local modules feature.


16-16: Proper import change for URL standardization.

The change from codeMirrorBaseUrl to codeMirrorBasePath aligns with the pattern of using base paths that are dynamically resolved to URLs.


21-21: Effective dynamic URL construction.

The dynamic construction of codeMirrorBaseUrl using modulesService.getUrl(codeMirrorBasePath, getAppCDN()) properly enables local vs CDN module resolution for CodeMirror language modules.

src/livecodes/languages/rescript/lang-rescript-compiler-esm.ts (2)

9-12: LGTM! URL import standardization looks good.

The change from importing a single base URL to four explicit URL constants aligns with the broader standardization effort across the codebase. This improves clarity by making the exact resources being loaded more explicit.


63-63: LGTM! Explicit URL array improves clarity.

The change from base URL concatenation to an explicit array of full URLs makes the required ReScript compiler modules more transparent and easier to understand. This follows the same pattern being applied across other language compilers in the codebase.

src/livecodes/types/bundle-types.ts (1)

3-3: LGTM! Base URL standardization implemented correctly.

The change from using a specific URL constant to dynamically constructing the import path using vendorsBaseUrl aligns with the broader URL standardization effort across the codebase. This approach provides better flexibility for the local modules feature while maintaining the same functionality.

Also applies to: 65-65

package.json (3)

30-31: LGTM! New scripts support the local modules feature.

The copy:modules and download-modules scripts are well-integrated additions that support the new local modules functionality. These scripts align with the PR objectives to enable offline operation by downloading and serving external modules locally.


125-126: LGTM! Dependencies added for module archive extraction.

The decompress and decompress-tarbz2 devDependencies are appropriate additions for handling compressed module archives (like Pyodide releases) as part of the local modules download process.


164-166: LGTM! Formatting improvements enhance readability.

The reformatting of the prettier plugins and jest configuration arrays from single-line to multi-line format improves readability and makes future modifications easier to track in diffs.

Also applies to: 171-189

src/livecodes/editor/fonts.ts (2)

2-33: LGTM! Font URL imports standardized correctly.

The conversion from specific font URL constants to base URL constants follows the established pattern across the codebase. This standardization improves consistency and supports the local modules feature.


47-227: LGTM! Dynamic font URL construction implemented properly.

The changes to construct font URLs by concatenating base URLs with appropriate CSS filenames is well-implemented. The different CSS filenames (e.g., 'index.css', 'fira_code.css', 'hack.css') correctly reflect the actual structure of each font package.

src/livecodes/compiler/compile.worker.ts (2)

5-5: LGTM! Module service integration for dynamic URL resolution.

The addition of getAppCDN and modulesService imports, along with the change from codeMirrorBaseUrl to codeMirrorBasePath, properly sets up the dynamic URL resolution pattern needed for the local modules feature.

Also applies to: 7-7


270-270: LGTM! Dynamic URL construction implemented correctly.

The change from static URL concatenation to using modulesService.getUrl(codeMirrorBasePath, getAppCDN()) properly implements the dynamic URL resolution pattern. This enables the worker to load CodeMirror resources from either CDN or local modules depending on the configuration.

src/livecodes/main.ts (3)

8-8: LGTM - Import change aligns with URL standardization.

The import change from codeMirrorBaseUrl to codeMirrorBasePath is consistent with the broader refactoring to use base paths with dynamic URL resolution.


80-80: LGTM - Dynamic URL resolution supports local modules.

The change from static import to dynamic URL resolution using modulesService.getUrl(codeMirrorBasePath, appCDN) properly supports the new local modules feature while maintaining backward compatibility.


109-119: LGTM - Conditional polyfill script supports offline mode.

The conditional logic correctly omits the external polyfill script when LOCAL_MODULES is 'true', which is appropriate for offline operation. The string comparison is consistent with how the environment variable is handled elsewhere in the codebase.

Dockerfile (3)

1-1: LGTM - Node.js and Alpine version updates.

The updates from node:24.1.0-alpine3.21 to node:24.4.1-alpine3.22 bring security patches and improvements. These are reasonable version bumps.

Also applies to: 42-42


15-16: LGTM - New build arguments support local modules feature.

The addition of HOST_NAME, PORT, LOCAL_MODULES, and NODE_OPTIONS build arguments properly supports the new local modules functionality and self-hosted deployments.

Also applies to: 24-25


27-33: LGTM - Efficient conditional module download.

The file copying strategy and conditional download step are well-designed:

  • Essential files are copied first to enable the download script
  • The conditional npm run download-modules only runs when LOCAL_MODULES="true"
  • This approach optimizes Docker layer caching
scripts/build.js (4)

39-39: LGTM - JSDoc type annotation improves code documentation.

The addition of JSDoc type annotation /** @type {string} */ for the content parameter enhances code documentation and type safety.


53-59: LGTM - Well-implemented URL replacement function.

The useSelfHostedURL function correctly:

  • Guards against missing HOST_NAME environment variable
  • Constructs HTTPS URLs with proper port handling (omits port 443)
  • Uses replaceAll for complete URL replacement

76-76: LGTM - Proper application of URL replacement to index.html.

The change from addBaseUrl to useSelfHostedURL for index.html correctly applies the self-hosted URL replacement functionality.


79-87: LGTM - Consistent URL replacement for web manifest.

The site.webmanifest processing correctly applies the same URL replacement logic, ensuring consistency across all build artifacts.

scripts/utils.js (3)

75-75: LGTM - Consistent LOCAL_MODULES environment variable handling.

The localModules variable follows the same pattern as other boolean environment variables, using String(process.env.LOCAL_MODULES) === 'true' for proper boolean conversion.

Also applies to: 90-90


109-109: LGTM - Environment variable properly exposed to build process.

The LOCAL_MODULES environment variable is correctly destructured and included in the build-time environment variables map, making it available during the build process.

Also applies to: 125-125


130-137: LGTM - Improved module export formatting.

The reformatting from single-line to multi-line export object improves code readability without changing functionality.

src/livecodes/languages/diagrams/lang-diagrams-compiler-esm.ts (3)

19-19: LGTM - Import change aligns with URL standardization.

The change from hpccJsCdnUrl to hpccJsCdnBaseUrl is consistent with the broader refactoring to use base paths in vendors.ts.


183-183: LGTM - Improved Mermaid loading with loadScript utility.

The change from direct import(mermaidCdnUrl) to loadScript(mermaidCdnUrl, 'mermaid') provides better error handling and supports both browser and web worker environments, which is beneficial for the local modules feature.


204-204: LGTM - Explicit file path construction for Graphviz.

The change from import(hpccJsCdnUrl) to import(hpccJsCdnBaseUrl + 'index.js') correctly constructs the full file path from the base URL, which is consistent with the new approach of using base paths and explicit file references.

docs/docs/advanced/docker.mdx (1)

172-174: LGTM! Clear documentation for the local modules feature.

The documentation effectively explains the experimental local modules feature with appropriate warnings and limitations.

src/livecodes/services/modules.ts (1)

69-73: LGTM! Well-implemented local CDN integration.

The local modules URL is properly integrated into the CDN checking mechanism, placed strategically between the preferred CDN and the npm CDN list.

src/livecodes/vendors.ts (3)

3-10: Excellent documentation of URL handling conventions!

The comments clearly explain the URL handling rules and exceptions, which will help maintain consistency in future updates.


388-399: LGTM! Clean separation of ReScript CDN URLs.

The split from a single base URL to four individual URLs provides better granularity for the module download process.


141-142: Ensure the GitHub hash points to a stable release

I wasn’t able to find any tag or release matching commit 6d0ee00a07fb1932902f0b81a504d075d47bd52f in hatemhosny/astigmata-font. Pinning to a raw SHA is stable long-term but carries risk if the repo history is ever rewritten. Please:

  • Confirm this SHA belongs to an immutable, release-ready commit (e.g. part of a maintained release branch).
  • If possible, switch to referencing an official tag (for example, vX.Y.Z) instead of the bare SHA.

Location:
β€’ src/livecodes/vendors.ts, lines 141–142

Comment on lines +13 to +15
const transformVendorsModule = (/** @type {string} */ content) =>
'const modulesService = { getUrl: (mod) => mod };\n' +
content.replace('import', '// import').replace('process.env.SDK_VERSION', `"${sdkPkg.version}"`);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve import statement replacement to avoid unintended replacements

The current string replacement might inadvertently replace the word "import" in other contexts (e.g., within strings or comments).

const transformVendorsModule = (/** @type {string} */ content) =>
  'const modulesService = { getUrl: (mod) => mod };\n' +
-  content.replace('import', '// import').replace('process.env.SDK_VERSION', `"${sdkPkg.version}"`);
+  content.replace(/^import/m, '// import').replace('process.env.SDK_VERSION', `"${sdkPkg.version}"`);
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const transformVendorsModule = (/** @type {string} */ content) =>
'const modulesService = { getUrl: (mod) => mod };\n' +
content.replace('import', '// import').replace('process.env.SDK_VERSION', `"${sdkPkg.version}"`);
const transformVendorsModule = (/** @type {string} */ content) =>
'const modulesService = { getUrl: (mod) => mod };\n' +
content
.replace(/^import/m, '// import')
.replace('process.env.SDK_VERSION', `"${sdkPkg.version}"`);
πŸ€– Prompt for AI Agents
In scripts/download-modules.js around lines 13 to 15, the current replacement of
the word "import" with "// import" is too broad and may replace occurrences
inside strings or comments unintentionally. To fix this, update the code to
parse the content properly and only comment out actual import statements, for
example by using a regular expression that matches import statements at the
start of lines or by using a JavaScript parser to identify import declarations
before replacing them.

Comment on lines +121 to +132
const getLocalUrl = (modName: string, modulesBaseUrl = '/modules/') => {
modName = modName
.replace('https://unpkg.com/', '')
.replace('unpkg:', '')
.replaceAll('https://', '')
.replaceAll(':', '_')
.replaceAll('?', '_');
if (modName.includes('pyodide')) {
modName = modName.replace('cdn.jsdelivr.net/', '');
}
return `${modulesBaseUrl}${modName}`;
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ’‘ Verification agent

🧩 Analysis chain

Consider edge cases in URL transformation

The getLocalUrl function handles URL transformations well, but ensure that the special handling for pyodide URLs doesn't accidentally match other URLs containing "pyodide" as a substring.


🏁 Script executed:

#!/bin/bash
# Description: Check for other URLs that might contain "pyodide" and could be affected

# Search for URLs containing "pyodide" in the vendors file
rg -i "pyodide" src/livecodes/vendors.ts -A 2 -B 2

Length of output: 164


Narrow pyodide URL matching in getLocalUrl

Use a more precise condition to avoid accidentally matching any module name that merely contains β€œpyodide.” For example:

β€’ File: src/livecodes/services/modules.ts, function getLocalUrl
β€’ Update the pyodide check from a substring match to a path‐specific check:

- if (modName.includes('pyodide')) {
-   modName = modName.replace('cdn.jsdelivr.net/', '');
- }
+ // Only strip the JSDelivr prefix when the URL is actually under /pyodide/
+ if (modName.startsWith('cdn.jsdelivr.net/pyodide/')) {
+   modName = modName.replace('cdn.jsdelivr.net/', '');
+ }

This change ensures you only transform true pyodide CDN URLs, preventing false positives on other modules whose names may include β€œpyodide.”

πŸ€– Prompt for AI Agents
In src/livecodes/services/modules.ts around lines 121 to 132, the current
pyodide URL check uses a broad substring match that can incorrectly match module
names containing "pyodide". Refine this check to specifically detect pyodide CDN
URLs by matching the exact path or hostname pattern instead of a simple
substring. Update the condition to only apply the replacement when the URL
clearly corresponds to the pyodide CDN, preventing unintended modifications of
other module names.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

♻️ Duplicate comments (3)
scripts/download-modules.js (3)

43-44: Fix typo in variable name

There's a typo in the variable name verdorModulesContent - it should be vendorModulesContent.

-  const verdorModulesContent = transformVendorsModule(fs.readFileSync(srcVendorsModule, 'utf8'));
-  fs.writeFileSync(cacheVendorsModule, verdorModulesContent, 'utf8');
+  const vendorModulesContent = transformVendorsModule(fs.readFileSync(srcVendorsModule, 'utf8'));
+  fs.writeFileSync(cacheVendorsModule, vendorModulesContent, 'utf8');

13-15: Improve import statement replacement to avoid unintended replacements

The current string replacement might inadvertently replace the word "import" in other contexts (e.g., within strings or comments).

const transformVendorsModule = (/** @type {string} */ content) =>
  'const modulesService = { getUrl: (mod) => mod };\n' +
-  content.replace('import', '// import').replace('process.env.SDK_VERSION', `"${sdkPkg.version}"`);
+  content.replace(/^import/m, '// import').replace('process.env.SDK_VERSION', `"${sdkPkg.version}"`);

198-199: Fix undefined variable in error message

The error message references an undefined module variable. Should use file instead.

-              console.error(`Failed to download module (${module}): ${result.message}`);
+              console.error(`Failed to download module (${file}): ${result.message}`);
🧹 Nitpick comments (3)
scripts/download-modules.js (3)

65-67: Improve robustness of URL manipulation

The string replacement for @seth0x41/doppio might fail if the URL structure changes or if similar patterns exist elsewhere.

-      if (baseUrl.includes('@seth0x41/doppio')) {
-        baseUrl = baseUrl.replace('https://unpkg.com/', '').replace('unpkg:', '');
-      }
+      if (baseUrl.includes('@seth0x41/doppio')) {
+        baseUrl = baseUrl.replace(/^https:\/\/unpkg\.com\//, '').replace(/^unpkg:/, '');
+      }

149-173: Optimize font file processing

The font file processing logic is duplicated for different font providers. Consider extracting this into a reusable function.

+            const processFontCSS = (content, fullPath, originalDomain, relativePath) => {
+              const urlPattern = /https:\/\/[^'"\)]*/g;
+              const fontUrls = Array.from(content.matchAll(new RegExp(urlPattern))).flat();
+              const promises = fontUrls.map(fontUrl => {
+                const fontPath = fontUrl.replace('https://', modulesDir);
+                return fetchAndSaveFile(fontUrl, fontPath);
+              });
+              const patched = content.replaceAll(originalDomain, relativePath);
+              fs.writeFileSync(fullPath, patched);
+              return Promise.all(promises);
+            };
+
             if (fullPath.includes('fonts.googleapis.com/css')) {
               const content = fs.readFileSync(fullPath, 'utf8');
-              const fontUrls = Array.from(content.matchAll(new RegExp(urlPattern))).flat();
-              for (const fontUrl of fontUrls) {
-                const fontPath = fontUrl.replace('https://', modulesDir);
-                await fetchAndSaveFile(fontUrl, fontPath);
-              }
-              const patched = content.replaceAll(
-                'https://fonts.gstatic.com/',
-                '../fonts.gstatic.com/',
-              );
-              fs.writeFileSync(fullPath, patched);
+              await processFontCSS(content, fullPath, 'https://fonts.gstatic.com/', '../fonts.gstatic.com/');
             }
             if (fullPath.includes('fonts.cdnfonts.com/css')) {
               const content = fs.readFileSync(fullPath, 'utf8');
-              const fontUrls = Array.from(content.matchAll(new RegExp(urlPattern))).flat();
-              for (const fontUrl of fontUrls) {
-                const fontPath = fontUrl.replace('https://', modulesDir);
-                await fetchAndSaveFile(fontUrl, fontPath);
-              }
-              const patched = content.replaceAll('https://fonts.cdnfonts.com/', '../');
-              fs.writeFileSync(fullPath, patched);
+              await processFontCSS(content, fullPath, 'https://fonts.cdnfonts.com/', '../');
             }

286-341: Consider using existing queue libraries

The custom async queue implementation is well-written but could be replaced with established libraries like p-queue for better maintainability and features.

πŸ“œ Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between cc5cb78 and 21b47b8.

πŸ“’ Files selected for processing (1)
  • scripts/download-modules.js (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: type-check (18.x)
  • GitHub Check: tests (18.x, 2)
  • GitHub Check: tests (18.x, 1)
  • GitHub Check: tests (18.x, 3)
  • GitHub Check: build (18.x)
  • GitHub Check: tests (18.x, 5)
  • GitHub Check: tests (18.x, 4)
  • GitHub Check: type-check (18.x)
  • GitHub Check: build (18.x)


// download Pyodide
if (pyodideBaseUrl) {
const pyodideVersion = pyodideBaseUrl.split('/v')[1].split('/')[0] || '0.28.0';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ› οΈ Refactor suggestion

Add validation for Pyodide version extraction

The version extraction logic could fail if the URL format changes, leading to incorrect version handling.

-    const pyodideVersion = pyodideBaseUrl.split('/v')[1].split('/')[0] || '0.28.0';
+    const versionMatch = pyodideBaseUrl.match(/\/v([^\/]+)/);
+    const pyodideVersion = versionMatch ? versionMatch[1] : '0.28.0';
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const pyodideVersion = pyodideBaseUrl.split('/v')[1].split('/')[0] || '0.28.0';
const versionMatch = pyodideBaseUrl.match(/\/v([^\/]+)/);
const pyodideVersion = versionMatch ? versionMatch[1] : '0.28.0';
πŸ€– Prompt for AI Agents
In scripts/download-modules.js at line 183, the current Pyodide version
extraction from the URL assumes a fixed format and may fail if the URL structure
changes. Add validation to check if the split operations successfully extract a
valid version string before using it. If the extraction fails, fallback to a
default version like '0.28.0' to ensure robust version handling.

Comment on lines +345 to +347
if (require.main === module) {
downloadModules({ dryRun: process.argv.includes('--dry-run') });
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ› οΈ Refactor suggestion

Add proper exit handling

The script should handle the async operation completion properly and exit with appropriate codes.

if (require.main === module) {
-  downloadModules({ dryRun: process.argv.includes('--dry-run') });
+  downloadModules({ dryRun: process.argv.includes('--dry-run') })
+    .then(() => process.exit(0))
+    .catch(err => {
+      console.error('Script failed:', err);
+      process.exit(1);
+    });
}
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (require.main === module) {
downloadModules({ dryRun: process.argv.includes('--dry-run') });
}
if (require.main === module) {
downloadModules({ dryRun: process.argv.includes('--dry-run') })
.then(() => process.exit(0))
.catch(err => {
console.error('Script failed:', err);
process.exit(1);
});
}
πŸ€– Prompt for AI Agents
In scripts/download-modules.js around lines 345 to 347, the script calls the
async function downloadModules but does not handle its completion or errors
properly. Modify the code to await the downloadModules call, then explicitly
call process.exit(0) on success and process.exit(1) on failure, ensuring the
script exits with appropriate status codes after the async operation finishes.

Comment on lines +127 to +128
const fullPath =
modulesDir + module.replaceAll('https://', '').replaceAll(':', '_').replaceAll('?', '_');
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ› οΈ Refactor suggestion

Improve file path sanitization

The current path sanitization using replaceAll might not handle all edge cases and could create naming conflicts.

-      const fullPath =
-        modulesDir + module.replaceAll('https://', '').replaceAll(':', '_').replaceAll('?', '_');
+      const sanitizedModule = module
+        .replace(/^https?:\/\//, '')
+        .replace(/[<>:"|?*]/g, '_')
+        .replace(/\/+/g, '/');
+      const fullPath = path.join(modulesDir, sanitizedModule);
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const fullPath =
modulesDir + module.replaceAll('https://', '').replaceAll(':', '_').replaceAll('?', '_');
const sanitizedModule = module
.replace(/^https?:\/\//, '')
.replace(/[<>:"|?*]/g, '_')
.replace(/\/+/g, '/');
const fullPath = path.join(modulesDir, sanitizedModule);
πŸ€– Prompt for AI Agents
In scripts/download-modules.js around lines 127 to 128, the current file path
sanitization uses multiple replaceAll calls which may not cover all edge cases
and could lead to naming conflicts. Replace this with a more robust sanitization
approach by using a single regular expression to replace all characters that are
invalid or problematic in file paths (such as slashes, colons, question marks,
and other special characters) with underscores or another safe character to
ensure unique and valid file names.

Comment on lines 75 to 76
const modInfoUrl = `https://data.jsdelivr.com/v1/package/${type}/${mod}/flat`;
const modInfo = await fetch(modInfoUrl).then((res) => res.json());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ› οΈ Refactor suggestion

Add error handling for API requests

The jsDelivr API request lacks error handling, which could cause the script to fail silently or crash.

-      const modInfoUrl = `https://data.jsdelivr.com/v1/package/${type}/${mod}/flat`;
-      const modInfo = await fetch(modInfoUrl).then((res) => res.json());
+      const modInfoUrl = `https://data.jsdelivr.com/v1/package/${type}/${mod}/flat`;
+      const response = await fetch(modInfoUrl);
+      if (!response.ok) {
+        console.warn(`Failed to fetch module info for ${mod}: ${response.status}`);
+        continue;
+      }
+      const modInfo = await response.json();
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const modInfoUrl = `https://data.jsdelivr.com/v1/package/${type}/${mod}/flat`;
const modInfo = await fetch(modInfoUrl).then((res) => res.json());
const modInfoUrl = `https://data.jsdelivr.com/v1/package/${type}/${mod}/flat`;
const response = await fetch(modInfoUrl);
if (!response.ok) {
console.warn(`Failed to fetch module info for ${mod}: ${response.status}`);
continue;
}
const modInfo = await response.json();
πŸ€– Prompt for AI Agents
In scripts/download-modules.js around lines 75 to 76, the fetch call to the
jsDelivr API does not have error handling, which may cause the script to fail
silently or crash if the request fails. Wrap the fetch call in a try-catch block
or use .catch to handle errors gracefully. In case of an error, log a meaningful
message and handle the failure appropriately to prevent the script from crashing
unexpectedly.

coderabbitai bot added a commit that referenced this pull request Jul 18, 2025
Docstrings generation was requested by @hatemhosny.

* #858 (comment)

The following files were modified:

* `scripts/download-modules.js`
* `src/livecodes/languages/python-wasm/lang-python-wasm-script.ts`
* `src/livecodes/types/bundle-types.ts`
@sonarqubecloud
Copy link

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 23

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/livecodes/html/language-info.html (1)

201-201: Broken C++ link: use isocpp.org (not isoclang.org)

Fix the Standard C++ Foundation link.

Apply:

-      <a href="https://isoclang.org/" target="_blank" rel="noopener">Standard C++ Foundation</a>
+      <a href="https://isocpp.org/" target="_blank" rel="noopener">Standard C++ Foundation</a>
🧹 Nitpick comments (7)
src/livecodes/core.ts (1)

1435-1443: Use combinedConfig when updating editors (clarity/consistency)

Function already computes combinedConfig; passing it avoids relying on external setConfig state.

-  if (reload) {
-    await updateEditors(editors, getConfig());
-  }
+  if (reload) {
+    await updateEditors(editors, combinedConfig);
+  }

This should be a no-op today but makes the function self-contained against future callers.

src/livecodes/i18n/locales/en/language-info.lokalise.json (1)

299-310: New Go (Wasm) entries β€” minor consistency nits.

  • Name casing across file alternates between β€œWasm” and β€œWASM”; consider standardizing (e.g., β€œWasm”) for all languages.
  • Several entries in this file use β€œLiveCodes Documentations”; consider β€œLiveCodes Documentation” for English.

If you want, I can open a follow-up PR to harmonize casing/wording across locales.

src/livecodes/vendors.ts (2)

122-123: doppioJvmBaseUrl moved to unpkg β€” good, but add fallback if CDN blocked.

Given LOCAL_MODULES goals, ensure scripts/download-modules.js picks this up and caches it properly from unpkg.


437-441: Use a stable Tailwind v4 or stick to v3 until v4 is fully validated
Tailwind 4.0.0 is published on npm (Jan 21, 2025) and serves from jsDelivr (200 OK) but isn’t the latest stable release (v4.1.13 is tagged β€œlatest”). Either bump to the latest v4 patch or remain on 3.4.x behind a feature flag until you’ve confirmed full v4 compatibility.

- export const tailwindcssBaseUrl = /* @__PURE__ */ getUrl('[email protected]/');
+ // for v4: update to latest patch
+ export const tailwindcssBaseUrl = /* @__PURE__ */ getUrl('[email protected]/');
docs/src/components/TemplateList.tsx (1)

78-81: Harden external link and improve image accessibility

Add rel to target _blank, alt text, and lazy loading to thumbnails.

-          <a href={appUrl + '/?template=' + t.name} target="_blank">
-            <img src={appUrl + '/livecodes/assets/templates/' + t.thumbnail} />
+          <a href={appUrl + '/?template=' + t.name} target="_blank" rel="noopener noreferrer">
+            <img
+              src={appUrl + '/livecodes/assets/templates/' + t.thumbnail}
+              alt={t.title}
+              loading="lazy"
+            />
src/livecodes/i18n/locales/fr/language-info.lokalise.json (1)

225-233: Minor FR copy consistency

Prefer β€œApprenez …” and β€œle modΓ¨le” to match existing entries.

-  "goWasm.link": {
-    "translation": "<tag-1><tag-2>Site officiel de Go</tag-2></tag-1> <tag-3><tag-4>Yaegi</tag-4></tag-3> <tag-5> <tag-6>Apprendre X en Y minutes, où X=Go</tag-6> </tag-5> <tag-7> <tag-8>LiveCodes Documentations</tag-8> </tag-7> <tag-9> <tag-10>Charger un modèle de démarrage</tag-10> </tag-9>"
-  },
+  "goWasm.link": {
+    "translation": "<tag-1><tag-2>Site officiel de Go</tag-2></tag-1> <tag-3><tag-4>Yaegi</tag-4></tag-3> <tag-5> <tag-6>Apprenez X en Y minutes, où X=Go</tag-6> </tag-5> <tag-7> <tag-8>Documentations LiveCodes</tag-8> </tag-7> <tag-9> <tag-10>Charger le modèle de démarrage</tag-10> </tag-9>"
+  },
src/livecodes/templates/starter/go-wasm-starter.ts (1)

45-53: Avoid overlapping runs; disable/enable buttons while executing

Prevent rapid clicks from starting concurrent runs and give clearer UX.

-    incrementBtn.onclick = async () => {
+    incrementBtn.onclick = async () => {
+      incrementBtn.disabled = true;
       const currentCount = document.querySelector("#counter").textContent;
       const {output, error} = await livecodes.goWasm.run(currentCount);
       if (error) {
         console.error('Error:', error);
       } else {
         document.querySelector("#counter").textContent = output;
       }
+      incrementBtn.disabled = false;
     };
 
-    greetBtn.onclick = async () => {
+    greetBtn.onclick = async () => {
+      greetBtn.disabled = true;
       const name = document.querySelector("#name-input").value;
       if (!name.trim()) {
         alert('Please enter your name');
-        return;
+        return (greetBtn.disabled = false);
       }
       const {output, error} = await livecodes.goWasm.run(name);
       if (error) {
         console.error('Error:', error);
       } else {
         document.querySelector("#greeting").textContent = output;
       }
+      greetBtn.disabled = false;
     };

Also applies to: 55-67

πŸ“œ Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between cec4187 and e11fc0d.

πŸ“’ Files selected for processing (83)
  • README.md (1 hunks)
  • docs/docs/languages/go-wasm.mdx (1 hunks)
  • docs/docs/languages/go.mdx (1 hunks)
  • docs/docs/languages/markdown.mdx (1 hunks)
  • docs/docs/languages/mdx.mdx (1 hunks)
  • docs/src/components/LanguageSliders.tsx (1 hunks)
  • docs/src/components/TemplateList.tsx (1 hunks)
  • scripts/build.js (4 hunks)
  • src/livecodes/UI/command-menu-actions.ts (1 hunks)
  • src/livecodes/compiler/compile-blocks.ts (1 hunks)
  • src/livecodes/config/__tests__/build-config.spec.ts (1 hunks)
  • src/livecodes/config/__tests__/validate-config.spec.ts (1 hunks)
  • src/livecodes/config/build-config.ts (1 hunks)
  • src/livecodes/config/validate-config.ts (1 hunks)
  • src/livecodes/core.ts (8 hunks)
  • src/livecodes/editor/monaco/monaco.ts (3 hunks)
  • src/livecodes/html/language-info.html (1 hunks)
  • src/livecodes/i18n/locales/ar/language-info.lokalise.json (1 hunks)
  • src/livecodes/i18n/locales/ar/language-info.ts (1 hunks)
  • src/livecodes/i18n/locales/ar/translation.lokalise.json (2 hunks)
  • src/livecodes/i18n/locales/ar/translation.ts (1 hunks)
  • src/livecodes/i18n/locales/de/language-info.lokalise.json (1 hunks)
  • src/livecodes/i18n/locales/de/language-info.ts (1 hunks)
  • src/livecodes/i18n/locales/de/translation.lokalise.json (2 hunks)
  • src/livecodes/i18n/locales/de/translation.ts (1 hunks)
  • src/livecodes/i18n/locales/en/language-info.lokalise.json (1 hunks)
  • src/livecodes/i18n/locales/en/language-info.ts (1 hunks)
  • src/livecodes/i18n/locales/en/translation.lokalise.json (2 hunks)
  • src/livecodes/i18n/locales/en/translation.ts (1 hunks)
  • src/livecodes/i18n/locales/es/language-info.lokalise.json (1 hunks)
  • src/livecodes/i18n/locales/es/language-info.ts (1 hunks)
  • src/livecodes/i18n/locales/es/translation.lokalise.json (2 hunks)
  • src/livecodes/i18n/locales/es/translation.ts (1 hunks)
  • src/livecodes/i18n/locales/fa/language-info.lokalise.json (1 hunks)
  • src/livecodes/i18n/locales/fa/language-info.ts (1 hunks)
  • src/livecodes/i18n/locales/fa/translation.lokalise.json (2 hunks)
  • src/livecodes/i18n/locales/fa/translation.ts (1 hunks)
  • src/livecodes/i18n/locales/fr/language-info.lokalise.json (1 hunks)
  • src/livecodes/i18n/locales/fr/language-info.ts (1 hunks)
  • src/livecodes/i18n/locales/fr/translation.lokalise.json (2 hunks)
  • src/livecodes/i18n/locales/fr/translation.ts (1 hunks)
  • src/livecodes/i18n/locales/hi/language-info.lokalise.json (1 hunks)
  • src/livecodes/i18n/locales/hi/language-info.ts (1 hunks)
  • src/livecodes/i18n/locales/hi/translation.lokalise.json (2 hunks)
  • src/livecodes/i18n/locales/hi/translation.ts (1 hunks)
  • src/livecodes/i18n/locales/it/language-info.lokalise.json (1 hunks)
  • src/livecodes/i18n/locales/it/language-info.ts (1 hunks)
  • src/livecodes/i18n/locales/it/translation.lokalise.json (2 hunks)
  • src/livecodes/i18n/locales/it/translation.ts (1 hunks)
  • src/livecodes/i18n/locales/ja/language-info.lokalise.json (1 hunks)
  • src/livecodes/i18n/locales/ja/language-info.ts (1 hunks)
  • src/livecodes/i18n/locales/ja/translation.lokalise.json (2 hunks)
  • src/livecodes/i18n/locales/ja/translation.ts (1 hunks)
  • src/livecodes/i18n/locales/pt/language-info.lokalise.json (1 hunks)
  • src/livecodes/i18n/locales/pt/language-info.ts (1 hunks)
  • src/livecodes/i18n/locales/pt/translation.lokalise.json (2 hunks)
  • src/livecodes/i18n/locales/pt/translation.ts (1 hunks)
  • src/livecodes/i18n/locales/ru/language-info.lokalise.json (1 hunks)
  • src/livecodes/i18n/locales/ru/language-info.ts (1 hunks)
  • src/livecodes/i18n/locales/ru/translation.lokalise.json (2 hunks)
  • src/livecodes/i18n/locales/ru/translation.ts (1 hunks)
  • src/livecodes/i18n/locales/ur/language-info.lokalise.json (1 hunks)
  • src/livecodes/i18n/locales/ur/language-info.ts (1 hunks)
  • src/livecodes/i18n/locales/ur/translation.lokalise.json (2 hunks)
  • src/livecodes/i18n/locales/ur/translation.ts (1 hunks)
  • src/livecodes/i18n/locales/zh-CN/language-info.lokalise.json (1 hunks)
  • src/livecodes/i18n/locales/zh-CN/language-info.ts (1 hunks)
  • src/livecodes/i18n/locales/zh-CN/translation.lokalise.json (2 hunks)
  • src/livecodes/i18n/locales/zh-CN/translation.ts (1 hunks)
  • src/livecodes/languages/go-wasm/index.ts (1 hunks)
  • src/livecodes/languages/go-wasm/lang-go-wasm-script.ts (1 hunks)
  • src/livecodes/languages/go-wasm/lang-go-wasm.ts (1 hunks)
  • src/livecodes/languages/languages.ts (2 hunks)
  • src/livecodes/languages/tailwindcss/processor-tailwindcss-compiler.ts (2 hunks)
  • src/livecodes/languages/tailwindcss/utils.ts (1 hunks)
  • src/livecodes/templates/starter/cpp-wasm-starter.ts (1 hunks)
  • src/livecodes/templates/starter/go-wasm-starter.ts (1 hunks)
  • src/livecodes/templates/starter/index.ts (2 hunks)
  • src/livecodes/utils/utils.ts (1 hunks)
  • src/livecodes/vendors.ts (13 hunks)
  • src/sdk/models.ts (4 hunks)
  • src/sdk/vue.ts (1 hunks)
  • vendor-licenses.md (1 hunks)
βœ… Files skipped from review due to trivial changes (3)
  • vendor-licenses.md
  • docs/docs/languages/go-wasm.mdx
  • README.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/livecodes/editor/monaco/monaco.ts
🧰 Additional context used
🧬 Code graph analysis (12)
src/livecodes/config/__tests__/build-config.spec.ts (2)
src/livecodes/config/build-config.ts (1)
  • loadParamConfig (147-386)
src/livecodes/config/default-config.ts (1)
  • defaultConfig (3-73)
src/livecodes/languages/go-wasm/lang-go-wasm.ts (2)
src/sdk/models.ts (1)
  • LanguageSpecs (1197-1210)
scripts/build.js (1)
  • baseUrl (40-40)
src/livecodes/languages/tailwindcss/processor-tailwindcss-compiler.ts (3)
src/livecodes/languages/tailwindcss/utils.ts (1)
  • addCodeInStyleBlocks (1-13)
src/sdk/models.ts (1)
  • CompilerFunction (1307-1322)
src/livecodes/compiler/import-map.ts (1)
  • replaceStyleImports (244-267)
src/livecodes/languages/go-wasm/lang-go-wasm-script.ts (2)
src/livecodes/vendors.ts (1)
  • yaegiWasmBaseUrl (110-110)
src/livecodes/utils/utils.ts (1)
  • createWorkerFromContent (291-297)
src/livecodes/templates/starter/go-wasm-starter.ts (1)
src/sdk/models.ts (1)
  • Template (1374-1381)
src/livecodes/templates/starter/index.ts (1)
src/livecodes/templates/starter/go-wasm-starter.ts (1)
  • goWasmStarter (3-177)
src/livecodes/config/validate-config.ts (1)
src/sdk/models.ts (1)
  • Editor (1093-1166)
src/livecodes/languages/languages.ts (1)
src/livecodes/languages/go-wasm/lang-go-wasm.ts (1)
  • goWasm (4-19)
src/livecodes/config/build-config.ts (2)
src/livecodes/main.ts (1)
  • params (12-12)
src/livecodes/utils/utils.ts (1)
  • addProp (673-686)
scripts/build.js (1)
scripts/i18n.js (2)
  • path (3-3)
  • outDir (7-7)
src/livecodes/core.ts (2)
src/sdk/models.ts (3)
  • EditorConfig (710-819)
  • Config (406-406)
  • CodeEditor (1521-1558)
src/livecodes/config/config.ts (3)
  • getEditorConfig (70-87)
  • getFormatterConfig (89-96)
  • getConfig (15-15)
src/livecodes/vendors.ts (1)
src/livecodes/services/modules.ts (1)
  • modulesService (35-87)
πŸͺ› ast-grep (0.39.5)
src/livecodes/languages/tailwindcss/utils.ts

[warning] 5-5: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(pattern, 'g')
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: Redirect rules - livecodes
  • GitHub Check: Header rules - livecodes
  • GitHub Check: Pages changed - livecodes
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: tests (18.x, 5)
  • GitHub Check: tests (18.x, 4)
  • GitHub Check: build
  • GitHub Check: tests (18.x, 3)
  • GitHub Check: tests (18.x, 2)
  • GitHub Check: tests (18.x, 1)
  • GitHub Check: build (18.x)
  • GitHub Check: build (18.x)
πŸ”‡ Additional comments (47)
src/livecodes/i18n/locales/ur/translation.lokalise.json (1)

1953-1955: Translations look accurate.

The new Urdu strings follow the existing naming pattern for starter templates (e.g., Lua/Golang Wasm entries) and keep the same terminology for β€œWasm” and β€œΨ΄Ψ±ΩˆΨΉΨ§Ψͺی.” Nicely consistent.

Also applies to: 1971-1973

src/livecodes/i18n/locales/pt/language-info.ts (1)

130-134: Go (Wasm) entry looks good

The new Go (Wasm) localization reads naturally and mirrors the surrounding entries.

src/livecodes/i18n/locales/ja/translation.ts (1)

993-999: Starter labels match the new wasm entries

Thanks for adding the JP labels for the Wasm starters; they line up with the rest of the template list.

src/sdk/vue.ts (1)

124-130: Great fix for data-height binding

Binding the attribute to height.value avoids emitting [object Object] and keeps the Vue wrapper aligned with how the SDK expects data-height to work for sizing. (livecodes.io)

docs/docs/languages/mdx.mdx (1)

3-108: Appreciate the richer MDX docs & demo

The expanded explanation plus the embedded LiveCodes example make the page much more helpful.

src/livecodes/i18n/locales/de/translation.lokalise.json (1)

1953-1973: German starter labels updated consistently

Nice job adding the new Wasm starter strings in sync with the rest of the locale file.

docs/docs/languages/go.mdx (1)

3-73: Great refresh of the Go docs.

The new demo, usage guidance, and Go (Wasm) cross-link make this page immediately useful for readers.

src/livecodes/i18n/locales/hi/language-info.ts (1)

130-134: Hindi goWasm entry looks consistent.

The new strings wire into the auto-generated locale structure without breaking placeholder patterns.

src/livecodes/i18n/locales/it/language-info.ts (1)

130-134: Italian goWasm strings slot in cleanly.

Localization metadata matches existing entries, so the starter catalog will surface correctly.

src/livecodes/i18n/locales/de/translation.ts (1)

994-1001: Starter template additions read well.

Both new labels follow the existing German phrasing pattern for Wasm starters.

src/livecodes/config/validate-config.ts (1)

141-149: Nice consolidation of editor validation.

Reusing validateEditorProps across markup/style/script keeps normalization uniform and trims duplicate checks.

src/livecodes/config/__tests__/validate-config.spec.ts (1)

160-161: Test expectation update looks right

Matches the validator’s normalization to the default JS script editor. No further changes needed here.

scripts/build.js (1)

235-236: Nice: include go‑wasm IIFE entry

Confirms assets are bundled for the new language.

Please confirm the file exists and builds: src/livecodes/languages/go-wasm/lang-go-wasm-script.ts.

src/livecodes/core.ts (6)

102-104: Exported EditorConfig import looks good

Aligns core with the public SDK types.


532-533: Initialize merged editor+formatter config β€” OK

Good place to establish the baseline for changeSettings calls.


1521-1534: Editor reload heuristic and delta detection β€” sensible

  • Checking editor backend switch and mode transitions is sound.
  • Tailwind toggle handling below also makes sense.

No change requested.

Edge case: if newConfig.editor is 'auto', confirm it won’t spuriously reload when current backend already matches auto’s resolution.


1550-1555: Propagate settings to all editors, including tools β€” good; ensure type compatibility

After widening currentEditorConfig type (above), this becomes type-safe and future‑proof.

If any editor ignores formatter keys, confirm changeSettings safely drops unknown fields.


1972-1977: getAllEditors utility β€” LGTM

Covers console/compiled editors defensively.


5568-5569: applyConfig(oldConfig) usage β€” good API design

Passing oldConfig enables precise deltas. Matches the updated signature.

src/livecodes/i18n/locales/en/language-info.lokalise.json (1)

292-294: Go (GopherJS) links updated β€” looks consistent.

Tag placeholders match notes; URLs and labels LGTM.

src/livecodes/i18n/locales/pt/language-info.lokalise.json (1)

225-233: Go (Wasm) PT translations added β€” LGTM.

Wording reads naturally; tag order matches notes. No blocking issues.

src/livecodes/templates/starter/index.ts (1)

24-24: Approve Go (Wasm) starter registration
TemplateName correctly includes 'go-wasm'; import path and registration order (Go > Go (Wasm)) are correct. Also applies to lines 115-116.

src/livecodes/vendors.ts (4)

360-363: Verify Pyodide v0.28.0 bump compatibility across init, package loading, and FS APIs.

Confirm that:

  • loadPyodide({ indexURL: pyodideBaseUrl }) still loads pyodide.js as expected.
  • livecodes.pyodide.loadPackage('micropip') and subsequent imports remain correct.
  • Fallback from runPythonAsync to runPython (v0.26.x workaround) still applies.
  • All Pyodide FS API calls (e.g. FS.mount, FS.writeFile, FS.readdir) align with v0.28.0 changes.

140-246: Confirm download-modules handles ?style.css CSS URLs correctly
HEAD checks on sample Google- and CDN-hosted font URLs return 200 with content-type: text/css and appropriate CORS. Ensure the build’s download-modules/getUrl step strips or normalizes query parameters so that cached files end in .css, are served with text/css, and support offline loading.


96-96: All imports updated; no stale codeMirrorBaseUrl references remain. Review comment resolved.


390-401: ReScript CDN loader now fetches all four URLs in correct order Verified that lang-rescript-compiler-esm.ts loads [rescriptCdnUrl1, rescriptCdnUrl2, rescriptCdnUrl3, rescriptCdnUrl4] and the formatter correctly imports only the compiler.

src/livecodes/i18n/locales/fr/translation.ts (1)

994-1001: FR starter keys added correctly

Entries for 'cpp-wasm' and 'go-wasm' match naming across locales. LGTM.

docs/src/components/TemplateList.tsx (1)

45-46: Add go‑wasm starter: looks good

Placement next to Go is consistent with other wasm variants.

src/livecodes/i18n/locales/zh-CN/translation.lokalise.json (1)

1953-1955: zh-CN wasm starters added

Keys and casing align with existing β€œLua(WASM)” style. LGTM.

Also applies to: 1971-1973

src/livecodes/i18n/locales/pt/translation.lokalise.json (1)

1953-1955: PT wasm starters added

Translations match existing β€œLua (Wasm)” pattern. LGTM.

Also applies to: 1971-1973

src/livecodes/config/__tests__/build-config.spec.ts (1)

508-515: Good coverage for dotted params; add parse-path test

This validates loadParamConfig addProp behavior. Add a companion test using getParams to ensure booleans in dotted keys are parsed as expected from query strings.

+  test('?markup.hideTitle=true parsed via getParams', () => {
+    const output: Partial<Config> = loadParamConfig(
+      defaultConfig,
+      getParams('?markup.hideTitle=true&script.title=App.jsx'),
+    );
+    expect(output.markup?.hideTitle).toBe(true);
+    expect(output.script?.title).toBe('App.jsx');
+  });
src/livecodes/i18n/locales/en/translation.ts (1)

999-1006: LGTM: adds Wasm starter labels.

Keys and labels align with existing conventions (hyphenated keys, β€œ(Wasm)” suffix).

src/livecodes/i18n/locales/it/translation.lokalise.json (1)

1953-1955: Approve IT Wasm starter translations. C++ (Wasm) and Go (Wasm) starter keys are present and consistent across all locales.

src/livecodes/config/build-config.ts (1)

368-382: Expanded parameter propagation looks solid

The dot-notation handling now covers markup/style/script/tests/customSettings/imports/types/tools prefixes, and reusing addProp cleanly maps nested keys without disrupting the earlier config assembly logic.

src/livecodes/i18n/locales/hi/translation.lokalise.json (1)

1953-1973: Consistent starter template additions β€” The new cpp-wasm and go-wasm entries mirror the existing naming/translation pattern for Hindi starters, so we stay aligned with the auto-generated locale structure.

src/livecodes/i18n/locales/ar/translation.lokalise.json (1)

1953-1973: Arabic locale keeps parity β€” Adding cpp-wasm and go-wasm with localized strings maintains parity with other locales and fits the generated file’s ordering.

src/livecodes/i18n/locales/zh-CN/translation.ts (1)

990-997: zh-CN starter labels look good β€” The new 'cpp-wasm' / 'go-wasm' translations are properly localized, keyed, and positioned alongside existing WASM starters in this generated map.

src/livecodes/i18n/locales/ar/translation.ts (1)

992-999: Arabic starter catalog stays synchronized β€” The Wasm variants are inserted with consistent naming and translation, keeping the generated TypeScript map aligned with the JSON source.

src/livecodes/i18n/locales/ru/translation.ts (1)

992-999: Russian locale parity achieved β€” cpp-wasm and go-wasm follow the established starter pattern, so the generated Russian map remains complete and ordered.

src/livecodes/i18n/locales/es/translation.lokalise.json (1)

1953-1955: Translations align with existing starter labels
The added Spanish strings keep the β€œInicio …” pattern and correctly surface the new Wasm templates.

Also applies to: 1971-1973

src/livecodes/i18n/locales/de/language-info.ts (1)

131-135: goWasm entry reads well
Copy mirrors the neighbouring entries and keeps placeholders intact, so the German locale stays consistent.

src/livecodes/i18n/locales/fr/translation.lokalise.json (1)

1953-1955: French starter labels stay consistent
The new Wasm variants follow the same β€œDΓ©marrage …” convention and plug straight into the templates list.

Also applies to: 1971-1973

src/livecodes/i18n/locales/ru/language-info.ts (1)

132-135: Russian goWasm copy looks good
Terminology, placeholder ordering, and style align with the neighbouring entries, so no further tweaks needed.

src/livecodes/html/language-info.html (2)

537-541: Docs link for Go added β€” OK

The LiveCodes docs link for Go matches the pattern used elsewhere. LGTM.


549-573: New Go (Wasm) section β€” OK

Structure, i18n keys, and starter link align with other languages. LGTM.

src/livecodes/i18n/locales/hi/translation.ts (1)

992-999: Wasm starter keys present in all locales

Verified that templates.starter.cpp-wasm and templates.starter.go-wasm exist across every locale. LGTM.

src/livecodes/languages/go-wasm/lang-go-wasm-script.ts (1)

97-106: Drop the redundant one-liner refactor. The current code already posts loaded only after initYaegi() resolves, so no behavior change is needed.

Likely an incorrect or invalid review comment.

Comment on lines +69 to +76
By default, no styes are added. Only HTML output is generated from the Markdown code.

If you want to style the result page similar to GitHub Markdown, you can use [`github-markdown-css`](https://github.com/sindresorhus/github-markdown-css).
Note that the body needs to have a `class="markdown-body"` for the styles to be applied.

```js title="Script Editor (JS)"
document.body.classList.add('markdown-body');
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟑 Minor

Fix typo in Styles section.

Line 69 should read β€œstyles” instead of β€œstyes.” Please correct the typo to keep the docs polished.

πŸ€– Prompt for AI Agents
In docs/docs/languages/markdown.mdx around lines 69 to 76, there's a typo:
"styes" should be "styles"; update the text to read "By default, no styles are
added." (preserve the rest of the paragraph and surrounding content exactly).

Comment on lines +53 to +59
const useSelfHostedURL = (/** @type {string} */ content) => {
if (!process.env.HOST_NAME) return content;
const hostname = process.env.HOST_NAME;
const port = Number(process.env.PORT) || 443;
const appUrl = `https://${hostname}${port !== 443 ? ':' + port : ''}`;
return content.replaceAll('https://livecodes.io', `${appUrl}`);
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ› οΈ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Don’t force HTTPS; build a robust origin from env (HOST_NAME/PROTOCOL/PORT)

Current logic breaks typical Docker localhost (http:80/8080) and double-prefixes if HOST_NAME includes scheme.

Recommend:

-const useSelfHostedURL = (/** @type {string} */ content) => {
-  if (!process.env.HOST_NAME) return content;
-  const hostname = process.env.HOST_NAME;
-  const port = Number(process.env.PORT) || 443;
-  const appUrl = `https://${hostname}${port !== 443 ? ':' + port : ''}`;
-  return content.replaceAll('https://livecodes.io', `${appUrl}`);
-};
+const useSelfHostedURL = (/** @type {string} */ content) => {
+  const rawHost = (process.env.HOST_NAME || '').trim();
+  if (!rawHost) return content;
+  const hasScheme = /^https?:\/\//i.test(rawHost);
+  const scheme = ((process.env.PROTOCOL || process.env.SCHEME || '').trim().toLowerCase()) || 'http';
+  const port = Number(process.env.PORT);
+  const origin = hasScheme
+    ? rawHost.replace(/\/+$/, '')
+    : `${scheme}://${rawHost}${port && ![80, 443].includes(port) ? ':' + port : ''}`;
+  return content.replaceAll('https://livecodes.io', origin);
+};

This covers http dev, https prod, and pre-schemed HOST_NAME.

Run to check remaining hard-coded origins:


🏁 Script executed:

#!/bin/bash
rg -nPI --hidden --glob '!build/**' 'https?://livecodes\.io' -C2

Length of output: 148


Running refined searches for hard-coded origins and mkdir usage:


🏁 Script executed:

#!/bin/bash
# Locate build.js path
fd --type f build.js

# Search for hard-coded livecodes.io URLs (excluding node_modules)
rg -nPI --glob '!node_modules/**' 'https?://livecodes\.io' -C2

# Check for any mkdir invocations in scripts
rg -n 'mkdir' -C3 scripts

Length of output: 4997


🏁 Script executed:

#!/bin/bash
# Find manifest writes in build.js
rg -n 'manifest' -C5 scripts/build.js
# Find any file writes to assets in build.js
rg -n 'writeFileSync' -C5 scripts/build.js

Length of output: 1660


Support flexible self-hosted origins and ensure assets directory exists

  • Before writing site.webmanifest (lines 80–87 in scripts/build.js), call mkdir(outDir + '/livecodes/assets') via the existing mkdir util so the assets folder exists.
  • Refactor useSelfHostedURL to respect an optional PROTOCOL/SCHEME env var, avoid forcing https, handle a pre-schemed HOST_NAME (prevent http://http://…), and only append non-default ports. Example:
     const useSelfHostedURL = content => {
       const rawHost = (process.env.HOST_NAME || '').trim();
       if (!rawHost) return content;
       const hasScheme = /^https?:\/\//i.test(rawHost);
       const scheme = process.env.PROTOCOL?.trim().toLowerCase()
                    || (hasScheme ? rawHost.split('://')[0].toLowerCase() : 'http');
       const hostPart = hasScheme
         ? rawHost.replace(/\/+$/, '')
         : `${rawHost}${process.env.PORT && !['80','443'].includes(process.env.PORT) ? ':' + process.env.PORT : ''}`;
       const origin = hasScheme ? hostPart : `${scheme}://${hostPart}`;
       return content.replaceAll('https://livecodes.io', origin);
     };
  • Verify there are no remaining hard-coded https://livecodes.io URLs in the build pipeline.
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const useSelfHostedURL = (/** @type {string} */ content) => {
if (!process.env.HOST_NAME) return content;
const hostname = process.env.HOST_NAME;
const port = Number(process.env.PORT) || 443;
const appUrl = `https://${hostname}${port !== 443 ? ':' + port : ''}`;
return content.replaceAll('https://livecodes.io', `${appUrl}`);
};
// scripts/build.js
// ... earlier in the file
const useSelfHostedURL = content => {
const rawHost = (process.env.HOST_NAME || '').trim();
if (!rawHost) return content;
const hasScheme = /^https?:\/\//i.test(rawHost);
const scheme = process.env.PROTOCOL?.trim().toLowerCase()
|| (hasScheme ? rawHost.split('://')[0].toLowerCase() : 'http');
const hostPart = hasScheme
? rawHost.replace(/\/+$/, '')
: `${rawHost}${process.env.PORT && !['80','443'].includes(process.env.PORT) ? ':' + process.env.PORT : ''}`;
const origin = hasScheme ? hostPart : `${scheme}://${hostPart}`;
return content.replaceAll('https://livecodes.io', origin);
};
// ... later where site.webmanifest is written
mkdir(outDir + '/livecodes/assets');
// proceed to write site.webmanifest into outDir + '/livecodes'
πŸ€– Prompt for AI Agents
In scripts/build.js around lines 53 to 59 and before lines 80–87, the build
currently forces https and may write the manifest without ensuring the assets
directory exists; first call the existing mkdir utility to create outDir +
'/livecodes/assets' before writing site.webmanifest so the assets folder exists;
then refactor useSelfHostedURL to read an optional PROTOCOL (or SCHEME) env var
and use it if present otherwise default to 'https', detect and avoid
double-scheming when HOST_NAME already includes a scheme, construct appUrl as
`${protocol}://${hostname}${portPart}` where portPart is only added when a port
is set and is not the default for that protocol, and replace hard-coded
'https://livecodes.io' occurrences via this function; finally scan the build
pipeline for any remaining hard-coded 'https://livecodes.io' strings and replace
them to use the refactored useSelfHostedURL so all origins are configurable.

Comment on lines +79 to +87
await fs.promises
.readFile(path.resolve(root, 'src/livecodes/assets/site.webmanifest'), 'utf8')
.then((siteWebManifest) =>
fs.promises.writeFile(
path.resolve(outDir, 'livecodes/assets/site.webmanifest'),
useSelfHostedURL(siteWebManifest),
'utf8',
),
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | πŸ”΄ Critical

Ensure destination directory exists before writing site.webmanifest

Writing to build/livecodes/assets/ will fail if β€˜assets’ wasn’t created.

 await Promise.all([
   // add headers
   process.env.CF_PAGES ? copyFile('src/_headers', '_headers') : Promise.resolve(),
   copyFile('src/netlify.toml', 'netlify.toml'),
   copyFile('src/favicon.ico', 'favicon.ico'),
   copyFile('src/404.html', '404.html', addBaseUrl),
-  copyFile('src/index.html', 'index.html', useSelfHostedURL),
+  copyFile('src/index.html', 'index.html', useSelfHostedURL),
   copyFile('src/livecodes/html/app-base.html', 'app.html'),
 ]);
-await fs.promises
+mkdir(path.resolve(outDir, 'livecodes/assets/'));
+await fs.promises
   .readFile(path.resolve(root, 'src/livecodes/assets/site.webmanifest'), 'utf8')
   .then((siteWebManifest) =>
     fs.promises.writeFile(
       path.resolve(outDir, 'livecodes/assets/site.webmanifest'),
       useSelfHostedURL(siteWebManifest),
       'utf8',
     ),
   );

Committable suggestion skipped: line range outside the PR's diff.

πŸ€– Prompt for AI Agents
In scripts/build.js around lines 79 to 87, the code writes
livecodes/assets/site.webmanifest but does not ensure the destination directory
exists; before writing, create the destination directory (path.resolve(outDir,
'livecodes/assets')) using fs.promises.mkdir(..., { recursive: true }) and await
it, then proceed to write the file (or chain the write after the mkdir promise)
so the write cannot fail if the assets directory is missing.

Comment on lines +91 to +93
// do not place compiled css for tailwind and similar in style blocks
if (['tailwindcss', 'unocss', 'windicss'].includes(processor.name)) continue;

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | πŸ”΄ Critical

Restore Tailwind/Uno/Windi processing

Skipping these processors means their compilers never run in postProcess, so Tailwind/Uno/Windi CSS is no longer generated or injected. Any project relying on those frameworks now renders without styling, breaking existing functionality and defeating the offline objective. Please keep the processors in the loop (or move their output elsewhere) so their CSS still reaches the runtime.

-    // do not place compiled css for tailwind and similar in style blocks
-    if (['tailwindcss', 'unocss', 'windicss'].includes(processor.name)) continue;
+    // TODO: adjust downstream handling if we need a different injection point,
+    // but we must still run these processors so their CSS is generated.
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// do not place compiled css for tailwind and similar in style blocks
if (['tailwindcss', 'unocss', 'windicss'].includes(processor.name)) continue;
// TODO: adjust downstream handling if we need a different injection point,
// but we must still run these processors so their CSS is generated.

Comment on lines +213 to 214
let currentEditorConfig: EditorConfig;
let toolsPane: ToolsPane | undefined;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ› οΈ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Type currentEditorConfig to include formatter settings too

You merge formatter fields (e.g., semicolons, singleQuote, trailingComma). Widen the type to avoid excess‑property errors and correctly type editor.changeSettings payload.

-let currentEditorConfig: EditorConfig;
+let currentEditorConfig: EditorConfig & ReturnType<typeof getFormatterConfig>;

If EditorConfig already includes those formatter props in ./models, ignore this and confirm.


🏁 Script executed:

#!/bin/bash
set -e
# locate EditorConfig declarations
rg -nP "export\\s+(?:interface|type)\\s+EditorConfig" -g "*.ts" -n
rg -nP "interface\\s+EditorConfig\\b" -g "*.ts" -n
# locate getFormatterConfig definition
rg -nP "export\\s+function\\s+getFormatterConfig" -g "*.ts" -n
rg -nP "getFormatterConfig\\s*=" -g "*.ts" -n

Length of output: 107


🏁 Script executed:

#!/bin/bash
set -e
# Show full EditorConfig definition
sed -n '700,760p' src/sdk/models.ts
# Search for getFormatterConfig references and definition
rg -nC3 'getFormatterConfig' -g '*.ts'
# Broader search for any formatter-related config functions
rg -nC3 'formatterConfig' -g '*.ts'

Length of output: 17497


Widen currentEditorConfig type to include formatter settings
Change its declaration in src/livecodes/core.ts (around lines 213–214) to include the fields returned by getFormatterConfig and avoid excess-property errors:

-let currentEditorConfig: EditorConfig;
+let currentEditorConfig: EditorConfig & ReturnType<typeof getFormatterConfig>;
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let currentEditorConfig: EditorConfig;
let toolsPane: ToolsPane | undefined;
let currentEditorConfig: EditorConfig & ReturnType<typeof getFormatterConfig>;
let toolsPane: ToolsPane | undefined;
πŸ€– Prompt for AI Agents
In src/livecodes/core.ts around lines 213–214, the declared variable
currentEditorConfig is too narrow and causes excess-property errors for the
formatter settings returned by getFormatterConfig; update its type to include
the formatter fields (for example by intersecting EditorConfig with the return
type of getFormatterConfig or by extending EditorConfig to include those
properties) so that currentEditorConfig accepts the formatter configuration
shape returned by getFormatterConfig; ensure any necessary imports/types are
adjusted accordingly.

Comment on lines +7 to +10
const content = arr[5];
if (content?.trim()) {
css += `\n${content}`;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Skip non-CSS <style> blocks before appending.

We now append every <style> block’s contents to the Tailwind CSS input, even when the block declares lang="scss"/lang="less" (or any non-CSS preprocessor). Those blocks previously had no effect; after this change they inject raw SCSS/LESS tokens into the Tailwind/PostCSS pipeline and immediately throw (e.g., $color: red; causes β€œUnexpected token $”), breaking existing projects that rely on preprocessed styles. Please gate on the lang attribute and only merge blocks that are plain CSS/PostCSS.

   for (const arr of [...html.matchAll(new RegExp(pattern, 'g'))]) {
-    const content = arr[5];
-    if (content?.trim()) {
-      css += `\n${content}`;
-    }
+    const lang = arr[3]?.trim().toLowerCase();
+    if (lang && !['css', 'postcss', 'tailwindcss'].includes(lang)) {
+      continue;
+    }
+    const content = arr[5];
+    if (content?.trim()) {
+      css += `\n${content}`;
+    }
   }
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const content = arr[5];
if (content?.trim()) {
css += `\n${content}`;
}
for (const arr of [...html.matchAll(new RegExp(pattern, 'g'))]) {
const lang = arr[3]?.trim().toLowerCase();
if (lang && !['css', 'postcss', 'tailwindcss'].includes(lang)) {
continue;
}
const content = arr[5];
if (content?.trim()) {
css += `\n${content}`;
}
}

name: 'cpp-wasm',
aliases: ['clang'],
title: 'C++ (Wasm) Starter',
title: window.deps.translateString('templates.starter.cpp-wasm', 'C++ (Wasm) Starter'),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | πŸ”΄ Critical

Guard window access so builds/tests without a DOM don’t crash

At module load time this now dereferences window, which will throw in any Node/SSR/test context that imports the starter metadata (those paths previously worked because the string was static). Please keep the translation lookup lazy by first checking typeof window !== 'undefined' (or deferring the call) so build scripts and unit tests can still require this module safely.

-  title: window.deps.translateString('templates.starter.cpp-wasm', 'C++ (Wasm) Starter'),
+  title:
+    typeof window !== 'undefined'
+      ? window.deps.translateString('templates.starter.cpp-wasm', 'C++ (Wasm) Starter')
+      : 'C++ (Wasm) Starter',
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
title: window.deps.translateString('templates.starter.cpp-wasm', 'C++ (Wasm) Starter'),
// before:
- title: window.deps.translateString('templates.starter.cpp-wasm', 'C++ (Wasm) Starter'),
// after:
title:
typeof window !== 'undefined'
? window.deps.translateString('templates.starter.cpp-wasm', 'C++ (Wasm) Starter')
: 'C++ (Wasm) Starter',
πŸ€– Prompt for AI Agents
In src/livecodes/templates/starter/cpp-wasm-starter.ts around line 6 the module
currently dereferences window at import time (window.deps.translateString(...)),
which throws in Node/SSR/test environments; change this to perform the
translation lazily by first checking typeof window !== 'undefined' before
calling window.deps.translateString, or defer the call behind a function/getter
so imports use a safe fallback (e.g., the raw English string) when window is
absent and only call translateString at runtime when a DOM/window is present.

Comment on lines 300 to 302
'go',
'go-wasm',
'php',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ› οΈ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Command menu: added β€œgo-wasm” template β€” LGTM.

Matches the starter registry; discoverability ensured.


🏁 Script executed:

#!/bin/bash
# Cross‑check that the command menu list matches starterTemplates registry.
rg -nP 'starterTemplates\s*=\s*\[' -n src/livecodes/templates/starter/index.ts -C3
rg -nP "stringUnionToArray<TemplateName>\\(\\)\\(" -n src/livecodes/UI/command-menu-actions.ts -C5

Length of output: 605


🏁 Script executed:

#!/bin/bash
# List all starter template files
ls src/livecodes/templates/starter
# Show imports and array entries in starter index
sed -n '1,200p' src/livecodes/templates/starter/index.ts
# Show the children list in the command menu actions
sed -n '250,330p' src/livecodes/UI/command-menu-actions.ts

Length of output: 7707


Align command menu entries with starter registry
The children array in src/livecodes/UI/command-menu-actions.ts includes templates (pyodide, clang) that aren’t present in starterTemplates (and will break discoverability). Remove or rename those entries so the command menu exactly mirrors src/livecodes/templates/starter/index.ts.

πŸ€– Prompt for AI Agents
In src/livecodes/UI/command-menu-actions.ts around lines 300 to 302, the
children array contains template keys (e.g., 'pyodide', 'clang') that do not
exist in src/livecodes/templates/starter/index.ts and will break
discoverability; update the children array to exactly match the keys exported by
starterTemplates in src/livecodes/templates/starter/index.ts by removing or
renaming any entries not present in that file and ensure order/membership mirror
starterTemplates so the command menu and starter registry stay in sync.

Comment on lines +631 to +655
const srcObjProp = srcObj[key];
const dstObjProp = dstObj[key];
if (typeof srcObjProp === 'function') {
continue;
} else if (!(key in dstObj)) {
diff.push(key);
} else if (srcObj[key] !== null && typeof srcObj[key] === 'object') {
const objDiff = compareObjects(srcObj[key] as any, dstObj[key] as any).map(
(k) => `${key}.${k}`,
);
diff.push(...objDiff);
} else if (srcObj[key] !== dstObj[key]) {
} else if (srcObjProp !== null && typeof srcObjProp === 'object') {
if (!dstObjProp || typeof dstObjProp !== 'object') {
diff.push(key);
} else if (Array.isArray(srcObjProp)) {
if (!Array.isArray(dstObjProp)) {
diff.push(key);
} else if (srcObjProp.length !== dstObjProp.length) {
diff.push(key);
} else {
for (let i = 0; i < srcObjProp.length; i++) {
if (srcObjProp[i] !== dstObjProp[i]) {
diff.push(`${key}[${i}]`);
}
}
}
} else {
const objDiff = compareObjects(srcObjProp, dstObjProp).map((k) => `${key}.${k}`);
diff.push(...objDiff);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | πŸ”΄ Critical

Restore type compatibility when recursing
Inside the object branch, srcObjProp/dstObjProp are still typed as unknown/object, so the recursive call fails TS compilation (object isn’t assignable to Partial<Record<string, unknown>>). Please coerce the values before recursing.

-      } else {
-        const objDiff = compareObjects(srcObjProp, dstObjProp).map((k) => `${key}.${k}`);
+      } else {
+        const objDiff = compareObjects(
+          srcObjProp as Partial<Record<string, unknown>>,
+          dstObjProp as Partial<Record<string, unknown>>,
+        ).map((k) => `${key}.${k}`);
πŸ€– Prompt for AI Agents
In src/livecodes/utils/utils.ts around lines 631 to 655, the recursive call
compareObjects(srcObjProp, dstObjProp) fails TypeScript because
srcObjProp/dstObjProp are typed as object/unknown; coerce them to the expected
type before recursing (e.g. cast to Partial<Record<string, unknown>> or the
function's accepted param type) so the compiler accepts the call, then pass the
coerced vars into compareObjects and map the results as currently done.

Comment on lines +110 to +111
export const yaegiWasmBaseUrl = /* @__PURE__ */ getUrl('[email protected]/src/');

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | πŸ”΄ Critical

🧩 Analysis chain

New yaegiWasmBaseUrl β€” confirm required assets resolution.

If the Go (Wasm) runtime expects specific paths (e.g., yaegi.wasm, glue JS), ensure they’re resolvable under LOCAL_MODULES and included by scripts/download-modules.js.


🏁 Script executed:

#!/bin/bash
# Verify consumers and expected filenames for Yaegi.
rg -nP --type=ts --type=tsx --type=js 'yaegiWasm(Base)?Url|yaegi\-wasm' -C3

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Search for yaegi URL constants and module references in codebase
rg -n 'yaegiWasmBaseUrl|yaegi-wasm' -C3 .

# Locate download-modules.js and inspect for yaegi asset inclusion
download_script=$(find . -type f -name download-modules.js)
if [ -n "$download_script" ]; then
  echo "Inspecting $download_script"
  rg -n 'yaegi' -C3 "$download_script"
else
  echo "download-modules.js not found"
fi

Length of output: 2372


Add Yaegi assets to download script: The Go Wasm worker imports ${yaegiWasmBaseUrl}wasm_exec.js and yaegi-browser.wasm; update scripts/download-modules.js to fetch these into LOCAL_MODULES.

πŸ€– Prompt for AI Agents
In src/livecodes/vendors.ts around lines 110-111 we expose yaegiWasmBaseUrl; the
download script currently doesn't fetch Yaegi assets referenced by the Go Wasm
worker. Update scripts/download-modules.js to add two entries to the
LOCAL_MODULES list: `${yaegiWasmBaseUrl}wasm_exec.js` and
`${yaegiWasmBaseUrl}yaegi-browser.wasm` (or construct the same base URL via
getUrl('[email protected]/src/') in that script), so the download step fetches
both files into the local modules folder and preserves filenames/paths expected
by the worker.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Self-hosted and fully offline?

4 participants