From 070cdb4083362a65677ec5b4375dce8de87a2ad8 Mon Sep 17 00:00:00 2001 From: Hatem Hosny Date: Tue, 20 Oct 2026 22:04:19 +0300 Subject: [PATCH 1/5] feat(Compilers): add Java (Wasm) language support --- README.md | 2 +- docs/docs/languages/java-doppio.mdx | 80 ++++++++++++++++ docs/docs/languages/java.mdx | 23 +++-- e2e/specs/compilers.spec.ts | 30 ++++++ scripts/build.js | 3 +- src/livecodes/html/language-info.html | 38 ++++++-- .../i18n/locales/en/language-info.ts | 10 ++ src/livecodes/languages/java-doppio/index.ts | 1 + .../lang-java-doppio-script.ts} | 0 .../lang-java-doppio.ts} | 14 +-- src/livecodes/languages/java-wasm/index.ts | 1 + .../java-wasm/lang-java-wasm-script.ts | 94 +++++++++++++++++++ .../languages/java-wasm/lang-java-wasm.ts | 45 +++++++++ src/livecodes/languages/java/index.ts | 1 - src/livecodes/languages/languages.ts | 6 +- src/livecodes/models.ts | 1 + .../templates/starter/java-starter.ts | 2 +- src/livecodes/vendors.ts | 2 + src/sdk/models.ts | 4 + vendor-licenses.md | 2 + 20 files changed, 334 insertions(+), 25 deletions(-) create mode 100644 docs/docs/languages/java-doppio.mdx create mode 100644 src/livecodes/languages/java-doppio/index.ts rename src/livecodes/languages/{java/lang-java-script.ts => java-doppio/lang-java-doppio-script.ts} (100%) rename src/livecodes/languages/{java/lang-java.ts => java-doppio/lang-java-doppio.ts} (72%) create mode 100644 src/livecodes/languages/java-wasm/index.ts create mode 100644 src/livecodes/languages/java-wasm/lang-java-wasm-script.ts create mode 100644 src/livecodes/languages/java-wasm/lang-java-wasm.ts delete mode 100644 src/livecodes/languages/java/index.ts diff --git a/README.md b/README.md index 43da972dd3..d1e9a9b460 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ A [feature-rich](https://livecodes.io/docs/features/), open-source, **client-sid [![LiveCodes: npm version](https://img.shields.io/npm/v/livecodes)](https://www.npmjs.com/package/livecodes) [![LiveCodes: npm downloads](https://img.shields.io/npm/dm/livecodes)](https://www.npmjs.com/package/livecodes) [![LiveCodes: jsdelivr downloads](https://data.jsdelivr.com/v1/package/npm/livecodes/badge?style=rounded)](https://www.jsdelivr.com/package/npm/livecodes) -[![LiveCodes: languages](https://img.shields.io/badge/languages-125-blue)](https://livecodes.io/docs/languages/) +[![LiveCodes: languages](https://img.shields.io/badge/languages-126-blue)](https://livecodes.io/docs/languages/) [![LiveCodes: docs](https://img.shields.io/badge/Documentation-575757?logo=gitbook&logoColor=white)](https://livecodes.io/docs/) [![LiveCodes: llms.txt](https://img.shields.io/badge/llms.txt-575757?logo=googledocs&logoColor=white)](https://livecodes.io/docs/llms.txt) [![LiveCodes: llms-full.txt](https://img.shields.io/badge/llms--full.txt-575757?logo=googledocs&logoColor=white)](https://livecodes.io/docs/llms-full.txt) diff --git a/docs/docs/languages/java-doppio.mdx b/docs/docs/languages/java-doppio.mdx new file mode 100644 index 0000000000..864e6bdd86 --- /dev/null +++ b/docs/docs/languages/java-doppio.mdx @@ -0,0 +1,80 @@ +# Java (Doppio) + +Java is a high-level, general-purpose, memory-safe, object-oriented programming language. + +This is the original LiveCodes Java engine: [DoppioJVM](https://github.com/plasma-umass/doppio), a JVM +JDK 8 interpreter written in JavaScript. It can run older Java, but it cannot compile modern Java +source (records, `var`, text blocks, switch expressions). + +The [`java-wasm`](./java.mdx) engine (also selected by `java`) compiles modern Java to WebAssembly in +the browser and is faster and much smaller. Use `java-doppio` only when you need the JVM +interpreter's behaviour. + +## Usage + +Demo: + +import LiveCodes from '../../src/components/LiveCodes.tsx'; + +export const javaDoppioConfig = { + activeEditor: 'script', + script: { + language: 'java-doppio', + content: `public class Main { + public static void main(String[] args) { + System.out.println("Hello from DoppioJVM"); + } +} +`, + }, + mode: 'simple', + editor: 'auto', + tools: { + status: 'full', + }, +}; + + + +### Communication with JavaScript + +The Java code runs in the context of the [result page](../features/result.mdx). +A few helper properties and methods are available in the browser global `livecodes.java` object: + +- `livecodes.java.input`: the initial standard input that is passed to the Java code. +- `livecodes.java.loaded`: A promise that resolves when the Java environment is loaded. +- `livecodes.java.output`: the standard output. +- `livecodes.java.error`: the standard error. +- `livecodes.java.exitCode`: the exit code. +- `livecodes.java.run`: a function that runs the Java code with new input. + +## Language Info + +### Name + +`java-doppio` + +### Extension + +`.java` (the language itself is selected by name) + +### Editor + +`script` + +## Compiler + +[DoppioJVM](https://github.com/plasma-umass/doppio) + +### Version + +`DoppioJVM`: v0.5.0, which runs Java 8 JDK. + +## Code Formatting + +Using [@wasm-fmt/clang-format](https://github.com/wasm-fmt/clang-format), applying [Google's Java style guide](https://google.github.io/styleguide/javaguide.html). + +## Links + +- [Java](https://www.java.com/) +- [DoppioJVM](https://github.com/plasma-umass/doppio) diff --git a/docs/docs/languages/java.mdx b/docs/docs/languages/java.mdx index 37679b1bbe..74edbccf75 100644 --- a/docs/docs/languages/java.mdx +++ b/docs/docs/languages/java.mdx @@ -2,7 +2,13 @@ Java is a high-level, general-purpose, memory-safe, object-oriented programming language. -In LiveCodes, Java runs in the browser using [DoppioJVM](https://github.com/plasma-umass/doppio). +In LiveCodes, Java source is compiled to WebAssembly **in the browser**: a build of OpenJDK's `javac` +and the [TeaVM](https://teavm.org) AOT compiler run as a single WebAssembly module inside a Web +Worker. Nothing is sent to a server, and modern Java (records, `var`, text blocks, switch +expressions) is supported. + +The language is named `java-wasm`; `java` is an alias for it (it used to select the DoppioJVM engine, +which is still available as [`java-doppio`](./java-doppio.mdx)). ## Usage @@ -13,7 +19,7 @@ import LiveCodes from '../../src/components/LiveCodes.tsx'; export const javaConfig = { activeEditor: 'script', script: { - language: 'java', + language: 'java-wasm', content: `public class BinarySearchSnippet { /** * Search an item with binarySearch algorithm. @@ -58,7 +64,7 @@ export const javaConfig = { editor: 'auto', tools: { status: 'full', -}, + }, }; @@ -83,7 +89,7 @@ Example: ### Name -`java` +`java-wasm` (alias: `java`) ### Extension @@ -95,11 +101,13 @@ Example: ## Compiler -[DoppioJVM](https://github.com/plasma-umass/doppio) +A [fork of teavm-javac](https://github.com/Vsprocessing/teavm-javac) packaging OpenJDK's `javac` and +the TeaVM AOT compiler as WebAssembly, run in a Web Worker by +[`@live-codes/java-wasm`](https://github.com/live-codes/java). ### Version -`DoppioJVM`: v0.5.0, which runs Java 8 JDK. +`teavm-javac` built on TeaVM `0.14.1`, with `javac` from OpenJDK 25. ## Code Formatting @@ -119,4 +127,5 @@ https://livecodes.io/?template=java ## Links - [Java](https://www.java.com/) -- [DoppioJVM](https://github.com/plasma-umass/doppio) +- [TeaVM](https://teavm.org/) +- [teavm-javac](https://github.com/Vsprocessing/teavm-javac) diff --git a/e2e/specs/compilers.spec.ts b/e2e/specs/compilers.spec.ts index 4a106409e3..865ddd3ee9 100644 --- a/e2e/specs/compilers.spec.ts +++ b/e2e/specs/compilers.spec.ts @@ -1650,6 +1650,36 @@ document.getElementById('header').innerHTML = f"Hello, {title}"`); expect(resultText).toContain(`Hello, Python`); }); + test('Java (Wasm)', async ({ page, getTestUrl, editor }) => { + test.skip(editor === 'codejar', 'please fix'); + test.slow(); // the engine downloads ~8 MB and generates WebAssembly + + await page.goto(getTestUrl({ tools: 'console|open' })); + + const { app, waitForResultUpdate } = await getLoadedApp(page); + + await app.click(':nth-match([title="Change Language"], 3)'); + await app.click('text="Java (WebAssembly)"'); + await waitForEditorFocus(app); + await page.keyboard.insertText(` +public class Main { + public static void main(String[] args) { + System.out.println("Hello from Java"); + } +} +`); + + await waitForResultUpdate(); + await app.waitForFunction( + () => + [...document.querySelectorAll('#console-container .luna-console-log-item')].some((item) => + (item.textContent ?? '').includes('Hello from Java'), + ), + undefined, + { timeout: 120_000 }, + ); + }); + test('Ruby', async ({ page, getTestUrl, editor }) => { test.skip(editor === 'codejar', 'please fix'); diff --git a/scripts/build.js b/scripts/build.js index 0ed0c7cf3d..1952538828 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -227,7 +227,8 @@ const iifeBuild = () => 'languages/astro/lang-astro-compiler.ts', 'languages/clio/lang-clio-compiler.ts', 'languages/commonlisp/lang-commonlisp-script.ts', - 'languages/java/lang-java-script.ts', + 'languages/java-doppio/lang-java-doppio-script.ts', + 'languages/java-wasm/lang-java-wasm-script.ts', 'languages/cpp/lang-cpp-script.ts', 'languages/clang-wasm/lang-clang-wasm-script.ts', 'languages/nim/lang-nim-wasm-script.ts', diff --git a/src/livecodes/html/language-info.html b/src/livecodes/html/language-info.html index 6bf34b882e..ba0ca44e0b 100644 --- a/src/livecodes/html/language-info.html +++ b/src/livecodes/html/language-info.html @@ -1261,17 +1261,19 @@

Janet (Wasm)

-
-

Java

-
- JVM running in the browser using DoppioJVM. +
+

Java (Wasm)

+
+ Java is compiled to WebAssembly in the browser by OpenJDK's javac and the TeaVM AOT compiler. + Modern Java (records, switch expressions, text blocks) is supported, and nothing is sent to a + server.
-
+
+

Java (Doppio)

+
+ JVM running in the browser using DoppioJVM (JDK 8, interpreted in JavaScript). +
+
+

JavaScript

diff --git a/src/livecodes/i18n/locales/en/language-info.ts b/src/livecodes/i18n/locales/en/language-info.ts index 97da69a43b..8a5088cc77 100644 --- a/src/livecodes/i18n/locales/en/language-info.ts +++ b/src/livecodes/i18n/locales/en/language-info.ts @@ -258,6 +258,16 @@ const languageInfo = { link: '<1> <2>Java official website <3> <4>DoppioJVM <5> <6>Learn X in Y minutes, where X=java <7> <8>LiveCodes Documentation <9> <10>Load starter template ', name: 'Java', }, + javaDoppio: { + desc: 'JVM running in the browser using DoppioJVM (JDK 8, interpreted in JavaScript).', + link: '<1> <2>Java official website <3> <4>DoppioJVM <5> <6>Learn X in Y minutes, where X=java <7> <8>LiveCodes Documentation ', + name: 'Java (Doppio)', + }, + javaWasm: { + desc: "Java is compiled to WebAssembly in the browser by OpenJDK's javac and the TeaVM AOT compiler. Modern Java (records, switch expressions, text blocks) is supported, and nothing is sent to a server.", + link: '<1> <2>Java official website <3> <4>TeaVM <5> <6>Learn X in Y minutes, where X=java <7> <8>LiveCodes Documentation <9> <10>Load starter template ', + name: 'Java (Wasm)', + }, javascript: { desc: 'The scripting language of the web.', link: '<1> <2>JavaScript on MDN <3> <4>Learn X in Y minutes, where X=JavaScript <5> <6>LiveCodes Documentation <7> <8>Load starter template ', diff --git a/src/livecodes/languages/java-doppio/index.ts b/src/livecodes/languages/java-doppio/index.ts new file mode 100644 index 0000000000..cac1247f8f --- /dev/null +++ b/src/livecodes/languages/java-doppio/index.ts @@ -0,0 +1 @@ +export * from './lang-java-doppio'; diff --git a/src/livecodes/languages/java/lang-java-script.ts b/src/livecodes/languages/java-doppio/lang-java-doppio-script.ts similarity index 100% rename from src/livecodes/languages/java/lang-java-script.ts rename to src/livecodes/languages/java-doppio/lang-java-doppio-script.ts diff --git a/src/livecodes/languages/java/lang-java.ts b/src/livecodes/languages/java-doppio/lang-java-doppio.ts similarity index 72% rename from src/livecodes/languages/java/lang-java.ts rename to src/livecodes/languages/java-doppio/lang-java-doppio.ts index 98bcb1f18f..e504d7a061 100644 --- a/src/livecodes/languages/java/lang-java.ts +++ b/src/livecodes/languages/java-doppio/lang-java-doppio.ts @@ -1,9 +1,10 @@ import type { LanguageSpecs } from '../../models'; import { codeMirrorBaseUrl, monacoLanguagesBaseUrl, wasmFmtClangBaseUrl } from '../../vendors'; -export const java: LanguageSpecs = { - name: 'java', - title: 'Java', +export const javaDoppio: LanguageSpecs = { + name: 'java-doppio', + title: 'Java (Doppio)', + longTitle: 'Java (DoppioJVM, JDK 8)', formatter: { factory: async () => { const formatter = await import(wasmFmtClangBaseUrl + 'clang-format-web.js'); @@ -15,19 +16,20 @@ export const java: LanguageSpecs = { }, compiler: { factory: () => async (code) => code, - scripts: ({ baseUrl }) => [baseUrl + '{{hash:lang-java-script.js}}'], + scripts: ({ baseUrl }) => [baseUrl + '{{hash:lang-java-doppio-script.js}}'], scriptType: 'text/java', compiledCodeLanguage: 'java', liveReload: true, }, - extensions: ['java'], + extensions: ['java-doppio', 'java8', 'doppio'], editor: 'script', editorSupport: { - monaco: { languageSupport: monacoLanguagesBaseUrl + 'java.js' }, + monaco: { languageSupport: monacoLanguagesBaseUrl + 'java.js', language: 'java' }, codemirror: { languageSupport: async () => (await import(codeMirrorBaseUrl + 'codemirror-lang-java.js')).java(), }, + codejar: { language: 'java' }, }, largeDownload: true, }; diff --git a/src/livecodes/languages/java-wasm/index.ts b/src/livecodes/languages/java-wasm/index.ts new file mode 100644 index 0000000000..8e43b00aeb --- /dev/null +++ b/src/livecodes/languages/java-wasm/index.ts @@ -0,0 +1 @@ +export * from './lang-java-wasm'; diff --git a/src/livecodes/languages/java-wasm/lang-java-wasm-script.ts b/src/livecodes/languages/java-wasm/lang-java-wasm-script.ts new file mode 100644 index 0000000000..2f174bb712 --- /dev/null +++ b/src/livecodes/languages/java-wasm/lang-java-wasm-script.ts @@ -0,0 +1,94 @@ +// @ts-nocheck +/* eslint-disable no-console */ + +import { javaWasmBaseUrl } from '../../vendors'; + +const javaWasmDistUrl = javaWasmBaseUrl + 'dist/'; + +livecodes.java = livecodes.java || {}; +livecodes.java.ready = false; + +let runtime; + +const getRuntime = async () => { + runtime ??= await window.JavaWasm.createRuntime({ + baseUrl: javaWasmDistUrl, + // each run starts with an empty file system + persistFiles: false, + }); + return runtime; +}; + +const getCode = () => { + let code = ''; + document + .querySelectorAll('script[type="text/java-wasm"]') + .forEach((script) => (code += script.innerHTML + '\n')); + return code; +}; + +const getMainClass = (code) => + code.match(/public\s+(?:final\s+|abstract\s+)?class\s+(\w+)/)?.[1] ?? 'Main'; + +const toStdin = (input) => { + const value = String(input ?? ''); + if (!value) return ''; + return value.endsWith('\n') ? value : value + '\n'; +}; + +livecodes.java.run = async (input = '') => { + const code = getCode(); + livecodes.java.input = input; + livecodes.java.output = null; + livecodes.java.ready = false; + + if (!code.trim()) { + livecodes.java.ready = true; + return { input, output: null, error: null, exitCode: 0 }; + } + + try { + const result = await ( + await getRuntime() + ).run(code, { input: toStdin(input), mainClass: getMainClass(code) }); + + const error = result.ok ? null : result.error; + // stdout and stderr are separate streams in Java; show both. + if (result.stdout) { + console.log(result.stdout); + } + const diagnostics = result.ok ? result.stderr : result.error || result.stderr; + if (diagnostics) { + console.error(diagnostics); + } + + livecodes.java.output = result.stdout; + livecodes.java.error = error; + livecodes.java.exitCode = result.exitCode; + return { input, output: result.stdout, error, exitCode: result.exitCode }; + } catch (err) { + const error = err?.message ?? err; + console.error(error); + livecodes.java.error = error; + livecodes.java.exitCode = 1; + return { input, output: null, error, exitCode: 1 }; + } finally { + livecodes.java.ready = true; + } +}; + +livecodes.java.loaded = new Promise((resolve) => { + const interval = setInterval(() => { + if (livecodes.java.ready) { + clearInterval(interval); + resolve(); + } + }, 50); +}); + +window.addEventListener('load', async () => { + livecodes.java.ready = false; + parent.postMessage({ type: 'loading', payload: true }, '*'); + await livecodes.java.run(livecodes.java.input); + parent.postMessage({ type: 'loading', payload: false }, '*'); +}); diff --git a/src/livecodes/languages/java-wasm/lang-java-wasm.ts b/src/livecodes/languages/java-wasm/lang-java-wasm.ts new file mode 100644 index 0000000000..392d495a8b --- /dev/null +++ b/src/livecodes/languages/java-wasm/lang-java-wasm.ts @@ -0,0 +1,45 @@ +import type { LanguageSpecs } from '../../models'; +import { + codeMirrorBaseUrl, + javaWasmBaseUrl, + monacoLanguagesBaseUrl, + wasmFmtClangBaseUrl, +} from '../../vendors'; + +export const javaWasm: LanguageSpecs = { + name: 'java-wasm', + title: 'Java (Wasm)', + longTitle: 'Java (WebAssembly)', + formatter: { + factory: async () => { + const formatter = await import(wasmFmtClangBaseUrl + 'clang-format-web.js'); + await formatter.default(); + return async (code) => ({ + formatted: await formatter.format(code, 'main.java', 'Google'), + }); + }, + }, + compiler: { + factory: () => async (code) => code, + scripts: ({ baseUrl }) => [ + javaWasmBaseUrl + 'dist/java-wasm.iife.js', + baseUrl + '{{hash:lang-java-wasm-script.js}}', + ], + scriptType: 'text/java-wasm', + compiledCodeLanguage: 'java-wasm', + liveReload: true, + }, + // `java` is the canonical name: it used to select DoppioJVM and now selects this engine. + extensions: ['java', 'java-wasm'], + editor: 'script', + editorLanguage: 'java', + editorSupport: { + monaco: { languageSupport: monacoLanguagesBaseUrl + 'java.js', language: 'java' }, + codemirror: { + languageSupport: async () => + (await import(codeMirrorBaseUrl + 'codemirror-lang-java.js')).java(), + }, + codejar: { language: 'java' }, + }, + largeDownload: true, +}; diff --git a/src/livecodes/languages/java/index.ts b/src/livecodes/languages/java/index.ts deleted file mode 100644 index e3803f5392..0000000000 --- a/src/livecodes/languages/java/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './lang-java'; diff --git a/src/livecodes/languages/languages.ts b/src/livecodes/languages/languages.ts index 3fdabafead..2819d6caf1 100644 --- a/src/livecodes/languages/languages.ts +++ b/src/livecodes/languages/languages.ts @@ -46,7 +46,8 @@ import { haskellWasm } from './haskell-wasm'; import { html } from './html'; import { imba } from './imba'; import { janetWasm } from './janet-wasm'; -import { java } from './java'; +import { javaDoppio } from './java-doppio'; +import { javaWasm } from './java-wasm'; import { javascript } from './javascript'; import { jinja } from './jinja'; import { jsx, tsx } from './jsx'; @@ -195,7 +196,8 @@ export const languages: LanguageSpecs[] = [ rustWasm, swiftWasm, zigWasm, - java, + javaWasm, + javaDoppio, csharpWasm, blazorWasm, vWasm, diff --git a/src/livecodes/models.ts b/src/livecodes/models.ts index 0eb72ed690..2d0c54f421 100644 --- a/src/livecodes/models.ts +++ b/src/livecodes/models.ts @@ -223,6 +223,7 @@ export type ScriptType = | 'text/odin-wasm' | 'text/zig-wasm' | 'text/java' + | 'text/java-wasm' | 'text/csharp-wasm' | 'text/razor' | 'text/fanak' diff --git a/src/livecodes/templates/starter/java-starter.ts b/src/livecodes/templates/starter/java-starter.ts index a2ef1974e5..4920ea8566 100644 --- a/src/livecodes/templates/starter/java-starter.ts +++ b/src/livecodes/templates/starter/java-starter.ts @@ -69,7 +69,7 @@ export const javaStarter: Template = { `.trimStart(), }, script: { - language: 'java', + language: 'java-wasm', content: ` import java.io.BufferedReader; import java.io.IOException; diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts index 3d91d88525..570aa16161 100644 --- a/src/livecodes/vendors.ts +++ b/src/livecodes/vendors.ts @@ -323,6 +323,8 @@ export const jsZipUrl = /* @__PURE__ */ getUrl('jszip@3.10.1/dist/jszip.js'); export const janetWasmBaseUrl = /* @__PURE__ */ getUrl('@live-codes/janet-wasm@0.1.0/'); +export const javaWasmBaseUrl = /* @__PURE__ */ getUrl('@live-codes/java-wasm@0.1.0/'); + export const juliaWasmBaseUrl = /* @__PURE__ */ getUrl('@chriskoch/julia-wasm@1.0.4'); export const keystoneJsUrl = /* @__PURE__ */ getUrl( diff --git a/src/sdk/models.ts b/src/sdk/models.ts index 6d56b17a02..1fc5caf2d3 100644 --- a/src/sdk/models.ts +++ b/src/sdk/models.ts @@ -227,6 +227,10 @@ export type Language = | 'clang-objcpp' | 'mm' | 'java' + | 'java-wasm' + | 'java-doppio' + | 'java8' + | 'doppio' | 'csharp' | 'csharp-wasm' | 'cs' diff --git a/vendor-licenses.md b/vendor-licenses.md index 856b4f70db..1d2751a6dd 100644 --- a/vendor-licenses.md +++ b/vendor-licenses.md @@ -326,6 +326,8 @@ Tau Prolog: [BSD 3-Clause License](https://github.com/tau-prolog/tau-prolog/blob Teal: [MIT License](https://github.com/teal-language/tl/blob/e907fbe56a70d44b65095e16ae2d1eae61c12066/LICENSE) +TeaVM (and the [teavm-javac](https://github.com/Vsprocessing/teavm-javac) fork used for Java): [Apache License 2.0](https://github.com/konsoletyper/teavm/blob/cfc0ce2a9874a4ce38b48adb90bc91ca0e755289/LICENSE). The bundled javac and class library from OpenJDK are [GPL-2.0 with the Classpath Exception](https://openjdk.org/legal/gplv2+ce.html). + ThemeMirror: [MIT License](https://github.com/vadimdemedes/thememirror/blob/94a6475a9113ec03d880fcb817aadcc5a16e82e4/package.json#L5) turbopascal: [BSD 2-Clause License](https://github.com/MikeRalphson/turbopascal/blob/cfcc5ee6d93f32664bb6127aa751c68841ca5c1d/LICENSE) From 72b1ddf2142af769f550b5fa6baca7338bcefc8c Mon Sep 17 00:00:00 2001 From: "pullfrog[bot]" <226033991+pullfrog[bot]@users.noreply.github.com> Date: Tue, 20 Oct 2026 20:17:14 +0000 Subject: [PATCH 2/5] fix(Compilers): bind Java (Doppio) tooltip to its own i18n keys and add language specs --- src/livecodes/html/language-info.html | 4 +- .../locales/en/language-info.lokalise.json | 26 +++++++--- .../i18n/locales/en/language-info.ts | 5 -- .../__tests__/lang-java-doppio.spec.ts | 42 +++++++++++++++++ .../__tests__/lang-java-wasm.spec.ts | 47 +++++++++++++++++++ 5 files changed, 110 insertions(+), 14 deletions(-) create mode 100644 src/livecodes/languages/java-doppio/__tests__/lang-java-doppio.spec.ts create mode 100644 src/livecodes/languages/java-wasm/__tests__/lang-java-wasm.spec.ts diff --git a/src/livecodes/html/language-info.html b/src/livecodes/html/language-info.html index ba0ca44e0b..9591972991 100644 --- a/src/livecodes/html/language-info.html +++ b/src/livecodes/html/language-info.html @@ -1294,10 +1294,10 @@

Java (Wasm)

Java (Doppio)

-
+
JVM running in the browser using DoppioJVM (JDK 8, interpreted in JavaScript).
-
-
-

Java (Doppio)

-
- JVM running in the browser using DoppioJVM (JDK 8, interpreted in JavaScript). +
+

Java 8

+
+ Java 8, compiled and run in the browser by a JVM interpreter written in JavaScript.
-