diff --git a/.nvmrc b/.nvmrc
index d78bf0a56c..564e92d084 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-v18.20.4
+v24.4.1
diff --git a/Dockerfile b/Dockerfile
index 65402a492c..65b79df75e 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM node:24.1.0-alpine3.21 AS builder
+FROM node:24.4.1-alpine3.22 AS builder
RUN apk update --no-cache && apk add --no-cache git
@@ -11,9 +11,9 @@ COPY server/package*.json server/
RUN npm ci
-COPY . .
-
ARG SELF_HOSTED
+ARG HOST_NAME
+ARG PORT
ARG SELF_HOSTED_SHARE
ARG SELF_HOSTED_BROADCAST
ARG BROADCAST_PORT
@@ -21,13 +21,25 @@ ARG SANDBOX_HOST_NAME
ARG SANDBOX_PORT
ARG FIREBASE_CONFIG
ARG DOCS_BASE_URL
+ARG LOCAL_MODULES
+ARG NODE_OPTIONS
+
+COPY scripts/download-modules.js scripts/
+COPY src/livecodes/vendors.ts src/livecodes/
+COPY src/sdk/package.sdk.json src/sdk/
+
+RUN if [ "$LOCAL_MODULES" == "true" ]; \
+ then npm run download-modules; \
+ fi
+
+COPY . .
RUN if [ "$DOCS_BASE_URL" == "null" ]; \
then npm run build:app; \
else npm run build; \
fi
-FROM node:24.1.0-alpine3.21 AS server
+FROM node:24.4.1-alpine3.22 AS server
RUN addgroup -S appgroup
RUN adduser -S appuser -G appgroup
diff --git a/README.md b/README.md
index 900089383e..7798ed9929 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ A [feature-rich](https://livecodes.io/docs/features/), open-source, **client-sid
[](https://www.npmjs.com/package/livecodes)
[](https://www.npmjs.com/package/livecodes)
[](https://www.jsdelivr.com/package/npm/livecodes)
-[](https://livecodes.io/docs/languages/)
+[](https://livecodes.io/docs/languages/)
[](https://livecodes.io/docs/)
[](https://livecodes.io/docs/llms.txt)
[](https://livecodes.io/docs/llms-full.txt)
diff --git a/docker-compose.yml b/docker-compose.yml
index e8bb4ca09c..dfcc8c54ed 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -5,6 +5,8 @@ services:
dockerfile: Dockerfile
args:
- SELF_HOSTED=true
+ - HOST_NAME=${HOST_NAME:-livecodes.localhost}
+ - PORT=${PORT:-443}
- SELF_HOSTED_SHARE=${SELF_HOSTED_SHARE:-true}
- SELF_HOSTED_BROADCAST=${SELF_HOSTED_BROADCAST:-true}
- BROADCAST_PORT=${BROADCAST_PORT:-3030}
@@ -12,6 +14,8 @@ services:
- SANDBOX_PORT=${SANDBOX_PORT:-8090}
- FIREBASE_CONFIG=${FIREBASE_CONFIG:-}
- DOCS_BASE_URL=${DOCS_BASE_URL:-null}
+ - LOCAL_MODULES=${LOCAL_MODULES:-false}
+ - NODE_OPTIONS=--max-old-space-size=4096
restart: unless-stopped
environment:
- SELF_HOSTED=true
@@ -26,6 +30,7 @@ services:
- LOG_URL=${LOG_URL:-null}
- VALKEY_HOST=valkey
- VALKEY_PORT=6379
+ - NODE_OPTIONS=--max-old-space-size=4096
volumes:
- ./assets:/srv/build/assets
depends_on:
diff --git a/docs/docs/advanced/docker.mdx b/docs/docs/advanced/docker.mdx
index 1e0188300a..e8a3a02a63 100644
--- a/docs/docs/advanced/docker.mdx
+++ b/docs/docs/advanced/docker.mdx
@@ -169,10 +169,56 @@ The hostname and many other options can be set using [environment variables](#en
Runs code in a separate origin [sandboxed iframe](https://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/) to prevent cross-site scripting.
+- Local modules
+
+ See [Local Modules](#local-modules) section for details.
+
- [404 page](https://livecodes.io/404)
Custom 404 page for resources that are not found.
+## Local Modules
+
+(EXPERIMENTAL)
+
+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.
+
+However, if you want to be able to run LiveCodes without an internet connection, you can download all these modules locally by setting the [environment variable](#environment-variables) `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.
+
+When working without internet connection, all resources have to be available locally. So, automatic [module resolution](../features/module-resolution.mdx) (e.g. of npm modules imported in user code) and loading type definitions for [intellisense](../features/intellisense.mdx) and auto-complete will not work out of the box.
+However, you can provide the list of modules to load using the [`imports`](../configuration/configuration-object.mdx#imports) property of the [config](../configuration/configuration-object.mdx) object (see [Custom Module Resolution](../features/module-resolution.mdx#custom-module-resolution)).
+Similarly, you can also provide the list of type definitions to load using the [`types`](../configuration/configuration-object.mdx#types) property (see [Custom Types](../features/intellisense.mdx#custom-types)).
+These modules and type definitions should be prepared in advance and made available to the running app (e.g. in the `/assets` directory - see [Volumes](#volumes)).
+
+Example:
+
+To run [React starter template](https://livecodes.io/?template=react) locally without internet connection, you need to:
+
+(assuming that the app is running on this URL: https://livecodes.localhost/)
+
+- Add [these files](https://github.com/hatemhosny/custom-modules-demo/tree/main/modules) to the [`/assets` directory](#volumes).
+- Open React starter template: https://livecodes.localhost/?template=react
+- Add this code to custom settings (Project menu → Custom Settings):
+
+```json
+{
+ "imports": {
+ "react": "https://livecodes.localhost/assets/react.js",
+ "react/compiler-runtime": "https://livecodes.localhost/assets/react-compiler-runtime.js",
+ "react/jsx-runtime": "https://livecodes.localhost/assets/react-jsx-runtime.js",
+ "react-dom": "https://livecodes.localhost/assets/react-dom.js",
+ "react-dom/client": "https://livecodes.localhost/assets/react-dom-client.js",
+ "scheduler": "https://livecodes.localhost/assets/scheduler.js"
+ },
+ "types": {
+ "react": "https://livecodes.localhost/assets/react.d.ts"
+ }
+}
+```
+
## Environment Variables
The app can be customized by setting different environment variables.
@@ -205,6 +251,7 @@ The following environment variables are supported:
| `FIREBASE_CONFIG` | [Firebase config object](https://firebase.google.com/docs/web/learn-more#config-object) (JSON), used for [authentication](../features/github-integration.mdx) | |
| `DOCS_BASE_URL` | [Base URL](../features/self-hosting.mdx#custom-build) of the documentation (e.g. `/docs/`) | `null` |
| `LOG_URL` | Full URL to send [server-side analytics](https://github.com/live-codes/livecodes/blob/develop/functions/index.ts) (e.g. `https://api.website.com/log`) | `null` |
+| `LOCAL_MODULES` | Download and use all modules locally (see [Local Modules](#local-modules)) | `false` |
:::info note
When running in a non-local environment (e.g. VPS),
diff --git a/docs/docs/languages/go-wasm.mdx b/docs/docs/languages/go-wasm.mdx
new file mode 100644
index 0000000000..1f8c108758
--- /dev/null
+++ b/docs/docs/languages/go-wasm.mdx
@@ -0,0 +1,93 @@
+# Go (Wasm)
+
+[Go](https://go.dev/) (Golang), is an open-source, statically typed, and compiled programming language developed by Google. It is designed for simplicity, efficiency, and strong support for concurrency, making it well-suited for building scalable and high-performance applications.
+
+LiveCodes uses [Yaegi](https://github.com/traefik/yaegi), the Go interpreter (running on WebAssembly), to run Go in the browser.
+
+:::info Note
+
+LiveCodes also supports running Go using [GopherJS](https://github.com/gopherjs/gopherjs) which is a Go to JavaScript compiler. Read documentation [here](./go.mdx).
+
+:::
+
+## Demo
+
+import LiveCodes from '../../src/components/LiveCodes.tsx';
+
+export const params = {
+ 'go-wasm': 'package main\n\nimport "fmt"\n\nfunc main() {\n\tfmt.Println("Hello, World!")\n}\n',
+ console: 'full',
+};
+
+
+
+## Usage
+
+LiveCodes runs Go in the browser, including the [standard library](https://pkg.go.dev/std).
+
+
+### Communication with JavaScript
+
+The Go 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.goWasm` object:
+
+- `livecodes.goWasm.input`: the initial standard input that is passed to the Go code.
+- `livecodes.goWasm.loaded`: A promise that resolves when the Go environment is loaded. Any other helpers should be used after this promise resolves.
+- `livecodes.goWasm.output`: the standard output.
+- `livecodes.goWasm.error`: the standard error.
+- `livecodes.goWasm.exitCode`: the exit code.
+- `livecodes.goWasm.run`: a function that runs the Go code with new input. This function takes a string as input and returns a promise that resolves when the Go code is done running. The promise resolves with an object containing the `input`, `output`, `error`, and `exitCode` properties.
+
+See the [example below](#example-usage) for more details.
+
+## Language Info
+
+### Name
+
+`go-wasm`
+
+### Extensions
+
+`wasm.go`, `go-wasm`, `gowasm`
+
+### Editor
+
+`script`
+
+## Compiler
+
+[Yaegi](https://github.com/traefik/yaegi), compiled to WebAssembly ([yaegi-wasm](https://github.com/Muhammad-Ayman/yaegi-wasm))
+
+### Version
+
+Yaegi v0.16.1, running go1.25.0
+
+## Code Formatting
+
+Using [GopherJS](https://github.com/gopherjs/gopherjs)
+
+## Example Usage
+
+This example demonstrates standard library usage and JavaScript interoperability (also check the code in the HTML editor):
+
+
+
+
+## Live Reload
+
+By default, new code changes are sent to the result page for re-evaluation without a full page reload, to avoid the need to reload the Go environment.
+
+This behavior can be disabled by adding the code comment `// __livecodes_reload__` to the code, which will force a full page reload.
+This comment can be added in the [`hiddenContent` property of the editor](../configuration/configuration-object.mdx#markup) for embedded playgrounds.
+
+## Starter Template
+
+https://livecodes.io/?template=go-wasm
+
+## Links
+
+- [Go](https://go.dev/)
+- [Go documentation](https://go.dev/doc/)
+- [Go standard library](https://pkg.go.dev/std)
+- [Yaegi](https://github.com/traefik/yaegi)
+- [Go using GopherJS](./go.mdx) in LiveCodes
diff --git a/docs/docs/languages/go.mdx b/docs/docs/languages/go.mdx
index 2e71b7f967..e3a584e872 100644
--- a/docs/docs/languages/go.mdx
+++ b/docs/docs/languages/go.mdx
@@ -1,3 +1,72 @@
# Go (Golang)
-TODO...
+[Go](https://go.dev/) (Golang), is an open-source, statically typed, and compiled programming language developed by Google. It is designed for simplicity, efficiency, and strong support for concurrency, making it well-suited for building scalable and high-performance applications.
+
+LiveCodes uses [GopherJS](https://github.com/gopherjs/gopherjs) which is a Go to JavaScript compiler, to run Go in the browser.
+
+:::info Note
+
+LiveCodes also supports running Go using [Yaegi](https://github.com/traefik/yaegi), the Go interpreter (running on WebAssembly). Read documentation [here](./go-wasm.mdx).
+
+:::
+
+## Demo
+
+import LiveCodes from '../../src/components/LiveCodes.tsx';
+
+export const params = {
+ 'go': 'package main\n\nimport "fmt"\n\nfunc main() {\n\tfmt.Println("Hello, World!")\n}\n',
+ console: 'full',
+};
+
+
+
+## Usage
+
+LiveCodes runs Go in the browser, including the [standard library](https://pkg.go.dev/std).
+
+JavaScript interoperability and DOM access is achieved using [package `js`](https://pkg.go.dev/syscall/js) (see the [example below](#example-usage)).
+
+## Language Info
+
+### Name
+
+`go`
+
+### Extensions
+
+`go`, `golang`
+
+### Editor
+
+`script`
+
+## Compiler
+
+[GopherJS](https://github.com/gopherjs/gopherjs), the Go to JavaScript compiler.
+
+### Version
+
+GopherJS v1.19.0 beta1, running Go 1.19.13
+
+## Code Formatting
+
+Using [GopherJS](https://github.com/gopherjs/gopherjs)
+
+## Example Usage
+
+This example demonstrates standard library usage, JavaScript interoperability and DOM access:
+
+
+
+## Starter Template
+
+https://livecodes.io/?template=go
+
+## Links
+
+- [Go](https://go.dev/)
+- [Go documentation](https://go.dev/doc/)
+- [Go standard library](https://pkg.go.dev/std)
+- [GopherJS](https://github.com/gopherjs/gopherjs)
+- [Go using Yaegi](./go-wasm.mdx) in LiveCodes
diff --git a/docs/docs/languages/markdown.mdx b/docs/docs/languages/markdown.mdx
index 4793abb742..1e01cc18d9 100644
--- a/docs/docs/languages/markdown.mdx
+++ b/docs/docs/languages/markdown.mdx
@@ -1,3 +1,160 @@
# Markdown
-TODO...
+[Markdown](https://daringfireball.net/projects/markdown/) is a text-to-HTML conversion tool for web writers.
+Markdown allows you to write using an easy-to-read, easy-to-write plain text format, then convert it to structurally valid HTML.
+
+Markdown is now one of the world's most popular markup languages.
+
+:::info Note
+
+Please note that MDX is also supported in LiveCodes and is [documented here](./mdx.mdx).
+
+:::
+
+## Demo
+
+import LiveCodes from '../../src/components/LiveCodes.tsx';
+
+export const markdownConfig = {
+ markup: {
+ language: 'markdown',
+ content: `## Markdown
+
+_Hello_ **World**
+
+Ordered List:
+
+1. item
+2. item
+3. item
+
+Unordered list:
+
+- item
+- item
+- item
+
+Link:
+
+[link](https://livecodes.io)
+
+Image:
+
+
+
+Table:
+
+| header 1 | header 2 |
+| -------- | -------- |
+| cell 1 | cell 2 |
+| cell 3 | cell 4 |
+
+Quote:
+
+> blockquote
+
+Code:
+
+\`\`\`python
+print("Hello, World!")
+\`\`\`
+`
+ },
+}
+
+
+
+## Styles
+
+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');
+```
+
+Example:
+
+export const styledMarkdownParams = {
+ template: 'markdown',
+ activeEditor: 'style',
+ css: `@import 'github-markdown-css';
+
+.markdown-body {
+ box-sizing: border-box;
+ min-width: 200px;
+ max-width: 980px;
+ margin: 0 auto;
+ padding: 45px;
+}
+
+@media (max-width: 767px) {
+ .markdown-body {
+ padding: 15px;
+ }
+}
+`,
+}
+
+
+
+## Language Info
+
+### Name
+
+`markdown`
+
+### Aliases
+
+`md`, `mdown`, `mkdn`
+
+### Extension
+
+`.md`
+
+### Editor
+
+`script`
+
+## Compiler
+
+[Marked](https://marked.js.org/)
+
+### Version
+
+`marked`: v13.0.2
+
+## Code Formatting
+
+Using [Prettier](https://prettier.io/).
+
+## Custom Settings
+
+[Custom settings](../advanced/custom-settings.mdx) added to the property `markdown` are passed as a JSON object to [`marked.parse`](https://marked.js.org/using_advanced). Please check the [documentation](https://marked.js.org/using_advanced#options) for full reference.
+
+Please note that custom settings should be valid JSON (i.e. functions are not allowed).
+
+**Example:**
+
+```json title="Custom Settings"
+{
+ "markdown": {
+ "gfm": true,
+ "breaks": true
+ }
+}
+```
+
+## Starter Template
+
+https://livecodes.io/?template=markdown
+
+## Links
+
+- [Markdown](https://daringfireball.net/projects/markdown/)
+- [Marked](https://marked.js.org/)
+- [The Markdown Guide](https://www.markdownguide.org/)
+- [MDX support in LiveCodes](./mdx.mdx)
+
diff --git a/docs/docs/languages/mdx.mdx b/docs/docs/languages/mdx.mdx
index 24ff946ef7..878089b313 100644
--- a/docs/docs/languages/mdx.mdx
+++ b/docs/docs/languages/mdx.mdx
@@ -1,3 +1,109 @@
# MDX
-TODO...
+[MDX](https://mdxjs.com/) allows using JSX in [Markdown](./markdown.mdx), creating dynamic and component-driven content for websites, documentation, and applications.
+
+:::info Note
+
+Please note that Markdown is also supported in LiveCodes and is [documented here](./markdown.mdx).
+
+:::
+
+## Demo
+
+import LiveCodes from '../../src/components/LiveCodes.tsx';
+
+export const mdxConfig = {
+ markup: {
+ language: 'mdx',
+ content: `import { Counter } from './script';
+
+# Counter
+
+
+`,},
+ style: {
+ language: 'css',
+ content: `body, body button {
+ text-align: center;
+ font: 1em sans-serif;
+}
+`,
+ },
+ script: {
+ language: 'jsx',
+ content: `import { useState } from "react";
+
+export function Counter() {
+ const [count, setCount] = useState(0);
+ return (
+
+
You clicked {count} times.
+
setCount(count + 1)}>
+ click me
+
+
+ );
+}
+`,
+ },
+}
+
+
+
+## Usage
+
+Components can be imported from the script editor that uses [JSX](./jsx.mdx) or [React](./react.mdx) by importing from `'./script'` (with no extension).
+
+Example:
+
+```js
+import { ComponentName } from './script';
+```
+
+## Language Info
+
+### Name
+
+`mdx`
+
+### Extension
+
+`.mdx`
+
+### Editor
+
+`script`
+
+## Compiler
+
+[MDX](https://mdxjs.com/)
+
+### Version
+
+`@mdx-js/mdx`: v3.1.0
+
+## Code Formatting
+
+Using [Prettier](https://prettier.io/).
+
+## Custom Settings
+
+[Custom settings](../advanced/custom-settings.mdx) added to the property `mdx` are passed as a JSON object to [`mdx.compile`](https://mdxjs.com/packages/mdx/#compilefile-options). Please check the [documentation](https://mdxjs.com/packages/mdx/#compileoptions) for full reference.
+
+Please note that custom settings should be valid JSON (i.e. functions are not allowed).
+
+
+## Starter Template
+
+https://livecodes.io/?template=mdx
+
+## Links
+
+- [MDX](https://mdxjs.com/)
+- [JSX](https://react.dev/learn/writing-markup-with-jsx)
+- [React](https://react.dev/)
+- [Markdown support in LiveCodes](./markdown.mdx)
+- [JSX support in LiveCodes](./jsx.mdx)
+- [React support in LiveCodes](./react.mdx)
+
+
diff --git a/docs/docs/languages/python-wasm.mdx b/docs/docs/languages/python-wasm.mdx
index a174a2b301..e98f819e3b 100644
--- a/docs/docs/languages/python-wasm.mdx
+++ b/docs/docs/languages/python-wasm.mdx
@@ -101,7 +101,7 @@ Check the [starter template](#starter-template) for an example.
### Version
-Pyodide v0.25.1, running Python v3.11.3
+Pyodide v0.28.0, running Python v3.13.2
## Code Formatting
diff --git a/docs/src/components/LanguageSliders.tsx b/docs/src/components/LanguageSliders.tsx
index e1daff5ac6..960c4933a6 100644
--- a/docs/src/components/LanguageSliders.tsx
+++ b/docs/src/components/LanguageSliders.tsx
@@ -83,6 +83,7 @@ export default function Sliders() {
{ name: 'ruby', title: 'Ruby' },
{ name: 'ruby-wasm', title: 'Ruby (Wasm)' },
{ name: 'go', title: 'Go' },
+ { name: 'go-wasm', title: 'Go (Wasm)' },
{ name: 'php', title: 'PHP' },
{ name: 'php-wasm', title: 'PHP (Wasm)' },
{ name: 'cpp', title: 'C++' },
diff --git a/docs/src/components/TemplateList.tsx b/docs/src/components/TemplateList.tsx
index 126f377f72..a246d4d47a 100644
--- a/docs/src/components/TemplateList.tsx
+++ b/docs/src/components/TemplateList.tsx
@@ -42,6 +42,7 @@ const templates = [
{ name: 'ruby', title: 'Ruby Starter', thumbnail: 'ruby.svg' },
{ name: 'ruby-wasm', title: 'Ruby (Wasm) Starter', thumbnail: 'ruby.svg' },
{ name: 'go', title: 'Go Starter', thumbnail: 'go.svg' },
+ { name: 'go-wasm', title: 'Go (Wasm) Starter', thumbnail: 'go.svg' },
{ name: 'php', title: 'PHP Starter', thumbnail: 'php.svg' },
{ name: 'php-wasm', title: 'PHP (Wasm) Starter', thumbnail: 'php.svg' },
{ name: 'cpp', title: 'C++ Starter', thumbnail: 'cpp.svg' },
diff --git a/e2e/specs/compilers.spec.ts b/e2e/specs/compilers.spec.ts
index bba6112526..d18dd75263 100644
--- a/e2e/specs/compilers.spec.ts
+++ b/e2e/specs/compilers.spec.ts
@@ -1,1783 +1,1783 @@
-import { expect } from '@playwright/test';
-import { getLoadedApp, waitForEditorFocus } from '../helpers';
-import { test } from '../test-fixtures';
-
-test.describe('Compiler Results', () => {
- test('HTML/CSS/JS', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.type('hello, ');
-
- await app.click(':nth-match([title="Change Language"], 2)');
- await app.click('text="CSS"');
- await waitForEditorFocus(app);
- await page.keyboard.type('body {color: blue;}');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text="JavaScript"');
- await waitForEditorFocus(app);
- await page.keyboard.type('document.body.innerHTML += "world!"');
-
- await waitForResultUpdate();
- const resultText = await getResult().innerText('body');
-
- expect(resultText).toContain('hello, world!');
- expect(await getResult().$eval('body', (e) => getComputedStyle(e).color)).toBe(
- 'rgb(0, 0, 255)',
- );
- });
-
- test('Markdown', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Markdown');
- await waitForEditorFocus(app);
- await app.page().keyboard.type('# Hi There');
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toBe('Hi There');
- });
-
- test('MDX', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=MDX');
- await waitForEditorFocus(app);
- await app.page().keyboard.type(`
-import {Hello} from './script';
-
-
-`);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JSX');
- await waitForEditorFocus(app);
- await app.page().keyboard.type(`
-import React from 'react';
-export const Hello = (props) => Hello, {props.title}! ;
-`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toBe('Hello, World!');
- });
-
- test('Astro', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Astro');
- await waitForEditorFocus(app);
- await app.page().keyboard.type(`---
-const title = "World";
----
-
-Hello, {title}! `);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toBe('Hello, World!');
- });
-
- test('Pug', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Pug');
- await waitForEditorFocus(app);
- await page.keyboard.type('h1 Hi There');
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toBe('Hi There');
- });
-
- test('Haml', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name": "Haml"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text="Haml"');
- await waitForEditorFocus(app);
- await page.keyboard.type('.content Hello, #{name}!');
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('.content');
-
- expect(resultText).toContain('Hello, Haml!');
- });
-
- test('AsciiDoc', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=AsciiDoc');
- await waitForEditorFocus(app);
- await page.keyboard.type('== Hello, World!');
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h2');
-
- expect(resultText).toContain('Hello, World!');
- });
-
- test('Mustache', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name": "Mustache"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Mustache');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{name}} `);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Mustache');
- });
-
- test('Mustache dynamic', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"prerender": false}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JavaScript');
- await waitForEditorFocus(app);
- await page.keyboard.type(`window.livecodes.templateData = { name: 'Mustache' };`);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Mustache');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{name}} `);
-
- await waitForResultUpdate();
- await app.waitForTimeout(3000);
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Mustache');
- });
-
- test('Handlebars', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name": "Handlebars"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Handlebars');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{name}} `);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Handlebars');
- });
-
- test('Handlebars dynamic', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"prerender": false}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JavaScript');
- await waitForEditorFocus(app);
- await page.keyboard.type(`window.livecodes.templateData = { name: 'Handlebars' };`);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Handlebars');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{name}} `);
-
- await waitForResultUpdate();
- await app.waitForTimeout(3000);
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Handlebars');
- });
-
- test('Nunjucks', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name": "Nunjucks"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Nunjucks');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{name}} `);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Nunjucks');
- });
-
- test('Nunjucks dynamic', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"prerender": false}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JavaScript');
- await waitForEditorFocus(app);
- await page.keyboard.type(`window.livecodes.templateData = { name: 'Nunjucks' };`);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Nunjucks');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{name}} `);
-
- await waitForResultUpdate();
- await app.waitForTimeout(3000);
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Nunjucks');
- });
-
- test('EJS', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name": "EJS"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=EJS');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to <%= name %> `);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to EJS');
- });
-
- test('EJS dynamic', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"prerender": false}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JavaScript');
- await waitForEditorFocus(app);
- await page.keyboard.type(`window.livecodes.templateData = { name: 'EJS' };`);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=EJS');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to <%= name %> `);
-
- await waitForResultUpdate();
- await app.waitForTimeout(3000);
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to EJS');
- });
-
- test('Eta', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name": "Eta"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text="Eta"');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to <%= it.name %> `);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Eta');
- });
-
- test('Eta dynamic', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"prerender": false}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JavaScript');
- await waitForEditorFocus(app);
- await page.keyboard.type(`window.livecodes.templateData = { name: 'Eta' };`);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text="Eta"');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to <%= it.name %> `);
-
- await waitForResultUpdate();
- await app.waitForTimeout(3000);
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Eta');
- });
-
- test('Liquid', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name":"liquid"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Liquid');
- await waitForEditorFocus(app);
- await page.keyboard.type(`{{ name | capitalize | prepend: "Welcome to "}}`);
-
- await waitForResultUpdate();
- const body = await getResult().$('body');
-
- expect(await body?.innerHTML()).toContain('Welcome to Liquid');
- });
-
- test('Liquid dynamic', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"prerender": false}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JavaScript');
- await waitForEditorFocus(app);
- await page.keyboard.type(`window.livecodes.templateData = { name: 'liquid' };`);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Liquid');
- await waitForEditorFocus(app);
- await page.keyboard.type(`{{ name | capitalize | prepend: "Welcome to "}}`);
-
- await waitForResultUpdate();
- await app.waitForTimeout(3000);
- const body = await getResult().$('body');
-
- expect(await body?.innerHTML()).toContain('Welcome to Liquid');
- });
-
- test('doT', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name":"doT"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=doT');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{=it.name}} `);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to doT');
- });
-
- test('doT dynamic', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"prerender": false}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JavaScript');
- await waitForEditorFocus(app);
- await page.keyboard.type(`window.livecodes.templateData = { name: 'doT' };`);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=doT');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{=it.name}} `);
-
- await waitForResultUpdate();
- await app.waitForTimeout(3000);
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to doT');
- });
-
- test('Twig', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name": "Twig"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Twig');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{ name }} `);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Twig');
- });
-
- test('Twig dynamic', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"prerender": false}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JavaScript');
- await waitForEditorFocus(app);
- await page.keyboard.type(`window.livecodes.templateData = { name: 'Twig' };`);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Twig');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{ name }} `);
-
- await waitForResultUpdate();
- await app.waitForTimeout(3000);
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Twig');
- });
-
- test('Vento', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name": "Vento"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Vento');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{ name }} `);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Vento');
- });
-
- test('Vento dynamic', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"prerender": false}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JavaScript');
- await waitForEditorFocus(app);
- await page.keyboard.type(`window.livecodes.templateData = { name: 'Vento' };`);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Vento');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{ name }} `);
-
- await waitForResultUpdate();
- await app.waitForTimeout(3000);
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Vento');
- });
-
- test('art-template', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name": "art-template"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=art-template');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{ name }} `);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to art-template');
- });
-
- test('art-template dynamic', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"prerender": false}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JavaScript');
- await waitForEditorFocus(app);
- await page.keyboard.type(`window.livecodes.templateData = { name: 'art-template' };`);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=art-template');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{ name }} `);
-
- await waitForResultUpdate();
- await app.waitForTimeout(3000);
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to art-template');
- });
-
- test('jinja', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name": "jinja"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text="Jinja"');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{ name }} `);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to jinja');
- });
-
- test('jinja dynamic', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"prerender": false}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JavaScript');
- await waitForEditorFocus(app);
- await page.keyboard.type(`window.livecodes.templateData = { name: 'jinja' };`);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text="Jinja"');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{ name }} `);
-
- await waitForResultUpdate();
- await app.waitForTimeout(3000);
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to jinja');
- });
-
- test('BBCode', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=BBCode');
- await waitForEditorFocus(app);
- await app.page().keyboard.type('[quote]quoted text[/quote]');
-
- await waitForResultUpdate();
- const resultText = await getResult().innerText('blockquote');
-
- expect(resultText).toBe('quoted text');
- });
-
- test('MJML', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=MJML');
- await waitForEditorFocus(app);
- await page.keyboard.type(`
-
-
-
-
-
- Hello MJML!
-
-
-
-
-
-`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('table');
-
- expect(resultText).toContain('Hello MJML!');
- });
-
- test('SCSS', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 2)');
- await app.click('text=SCSS');
- await waitForEditorFocus(app);
- await page.keyboard.type(
- `$font-stack: Helvetica, sans-serif; body { font: 100% $font-stack; }`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('style');
-
- expect(resultText).toContain('font: 100% Helvetica, sans-serif;');
- });
-
- test('Sass', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 2)');
- await app.click('text=Sass');
- await waitForEditorFocus(app);
- await page.keyboard.type(`$font-stack: Helvetica, sans-serif\nbody\n font: 100% $font-stack`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('style');
-
- expect(resultText).toContain('font: 100% Helvetica, sans-serif;');
- });
-
- test('Less', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 2)');
- await app.click('text=Less');
- await waitForEditorFocus(app);
- await page.keyboard.type(`@width: 10px; #header { width: @width; }`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('style');
-
- expect(resultText).toContain('width: 10px;');
- });
-
- test('Stylus', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 2)');
- await app.click('text=Stylus');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`font-size = 14px\nbody\n font font-size Arial, sans-serif`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('style');
-
- expect(resultText).toContain('font: 14px Arial, sans-serif;');
- });
-
- test('Stylis', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 2)');
- await app.click('text=Stylis');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- '[namespace] {\n div {\n display: flex;\n\n @media screen {\n color: blue;\n }\n }\n\n div {\n transform: translateZ(0);\n\n h1, h2 {\n color: red;\n }\n }\n}',
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('style');
-
- expect(resultText).toContain(
- '[namespace] div{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}@media screen{[namespace] div{color:blue;}}[namespace] div{-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);}[namespace] div h1,[namespace] div h2{color:red;}',
- );
- });
-
- test('PostCSS/postcssImportUrl', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 2)');
- await app.click('text=Import Url');
- await app.click('text=CSS');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`@import "github-markdown-css";`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('style');
-
- expect(resultText).toContain('.markdown-body');
- });
-
- test('PostCSS/Autoprefixer', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 2)');
- await app.click('text=Autoprefixer');
- await app.click('text=CSS');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`.example { user-select: none; }`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('style');
-
- expect(resultText).toContain('-webkit-user-select: none;');
- });
-
- test('PostCSS/Preset Env', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 2)');
- await app.click('text=Preset Env');
- await app.click('text=CSS');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `:root { --mainColor: #12345678; --secondaryColor: lab(32.5 38.5 -47.6 / 90%); }`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('style');
-
- expect(resultText).toContain('--mainColor: rgba(18,52,86,0.47059);');
- });
-
- test('Babel', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Babel');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`[1, 2, 3].map(n => n + 1);`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('body > script');
-
- expect(resultText).toContain(
- `[1, 2, 3].map(function (n) {
- return n + 1;
-});`,
- );
- });
-
- test('Sucrase', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Sucrase');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`const Greet = (name: string) => <>Hello {name}!>;`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('body > script');
-
- expect(resultText).toContain(
- `const Greet = (name) => React.createElement(React.Fragment, null, "Hello " , name, "!");`,
- );
- });
-
- test('TypeScript', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=TypeScript');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `type Fish = { swim: () => void };
-type Bird = { fly: () => void };
-declare function getSmallPet(): Fish | Bird;
-// ---cut---
-function isFish(pet: Fish | Bird): pet is Fish {
- return (pet as Fish).swim !== undefined;
-}`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('body > script');
-
- expect(resultText).toContain(
- `// ---cut---
-function isFish(pet) {
- return pet.swim !== undefined;
-}`,
- );
- });
-
- test('Flow', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Flow');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- 'function foo(x: ?number): string {if (x) { return x; } return "default string"; }',
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('body > script');
-
- expect(resultText).toContain(
- 'function foo(x ) {if (x) { return x; } return "default string"; }',
- );
- });
-
- test('JSX', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`Loading...
`);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text="JSX"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `
-const Hello = (props) => Hello, {props.name}
-export default () => ;
-`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain(`Hello, React`);
- });
-
- test('TSX', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text="TSX"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `
-interface Props { name: string }
-const Hello = (props: Props) => Hello, {props.name}
-export default () => ;
-`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain(`Hello, React`);
- });
-
- test('React', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`Loading...
`);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text="React"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `
-const Hello = (props) => Hello, {props.name}
-export default () => ;
-`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain(`Hello, React`);
- });
-
- test('React (TSX)', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text="React (TSX)"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `
-interface Props { name: string }
-const Hello = (props: Props) => Hello, {props.name}
-export default () => ;
-`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain(`Hello, React`);
- });
-
- test('Vue', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await (await app.$('[data-lang="vue"]'))?.click();
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `
-Hello, {{ title }}
-
-
-`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain(`Hello, Vue`);
- expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(0, 0, 255)');
- });
-
- test('Vue JSX', async ({ page, getTestUrl }) => {
- const sfc = `
-
-
-`;
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
- await app.click(':nth-match([title="Change Language"], 3)');
- await (await app.$('[data-lang="vue"]'))?.click();
- await waitForEditorFocus(app);
- await page.keyboard.insertText(sfc);
-
- await waitForResultUpdate();
-
- await getResult().click('text=Click me');
- await getResult().click('text=Click me');
- await getResult().click('text=Click me');
-
- const titleText = await getResult().innerText('h1');
- expect(titleText).toBe('Hello, Vue!');
-
- const counterText = await getResult().innerText('text=You clicked');
- expect(counterText).toBe('You clicked 3 times.');
- });
-
- test('Vue import', async ({ page, getTestUrl }) => {
- const sfc = `
-
-
-
-
-`;
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await (await app.$('[data-lang="vue"]'))?.click();
- await waitForEditorFocus(app);
- await page.keyboard.insertText(sfc);
-
- await waitForResultUpdate();
-
- // css import
- const headHTML = await getResult().innerHTML('head');
- expect(headHTML).toContain(
- ' ',
- );
-
- // bare module import
- const uuidText = await getResult().innerText('#uuid');
- expect(uuidText.length).toBeGreaterThan(10);
-
- // import vue component
- await getResult().click(':nth-match(button, 1)');
- await getResult().click(':nth-match(button, 1)');
- await getResult().click(':nth-match(button, 1)');
-
- // import vue component that has relative imports and fetches absolute url
- const buttonText = await getResult().innerText(':nth-match(button, 1)');
- expect(buttonText).toBe('Count is: 3, double is: 6');
- });
-
- test('Vue langs', async ({ page, getTestUrl }) => {
- const sfc = `
- # Hello, {{ name }}!
- some text
-
-
-
-
-
-`;
-
- await page.goto(
- getTestUrl({
- x: 'code/N4IgLglmA2CmIC4QFUB2kawCYAIAKATgPYBWsAxmCADQhawDO5BEADpEaoiDeAIYBzBogDaAXVp9KEAG6wAolihEC3Ji3a8AtnwIBrAK6tEoaH1QCDg+EgAWYLdF7lOYWOm4gAvrQZgAnnAmIGYWVgI2IOQMwrQu6O5USN6+zGxJpuaW1twyBvBxroncADxuWqxmbjihAgC8ADogWlhNAHwNBA2oODgAxDgAErDQ0ETUOMDAOKh8WrA4Xl4AhJ3dvSWsOAjkZjGNIAAkfoGwAHRuAB5g7QxE8zhXYCUA9KwdXaiv5ZV8bh-dNZfdTpGpZA5gBhNHAMWBgIwAno4eJ+GZzWAIGFgFgWHB1HAAcgAavkcABmAkAbiBrxB7ERNJOcDBFgOTBi0K0RCwBjgiN6hwAZq4ALR+KR6THDaBySDkPgTBjmBhi2AsQXUz4C1gsHQEfwilxjAiYvoAVgtmvWOGOFE4WF0BqNKkxAgIsHcVtQQN6tgAjJMfb0cML0JiAEwABkjAFIbaGwGKwBKvcHkURjZjDjqIHqnRmVKnFkCgxdYNdA1rgwnMX7o3GhaLxeQ9EXes6TTbYfEHfrDQWCEWvDSXkzYG0UiAxwxbB7IaIJFO0uxhAhxHEYoRGHDPLQdURyIw7gRV+uogY-PcAMpwyAWVfAHwgXOsFTzhCP2gBViMExPtx+A+IRZOEkTfowy5UIUCQeMkT5yCeECcNwAAs3hAA',
- }),
- );
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await (await app.$('[data-lang="vue"]'))?.click();
- await waitForEditorFocus(app);
- // await page.keyboard.insertText(sfc);
-
- await waitForResultUpdate();
-
- const headerText = await getResult().innerText('h1');
-
- // markdown, scss, typescript
- expect(headerText).toContain(`Hello, Vue 3!`);
- expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(85, 85, 85)');
-
- // css modules
- expect(await getResult().$eval('p', (e) => getComputedStyle(e).color)).toBe('rgb(0, 128, 0)');
- });
-
- test('Vue + Tailwind CSS', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await (await app.$('[data-lang="vue"]'))?.click();
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `
-
-
Tailwind in Vue SFC
-
-
-`,
- );
-
- await app.click(':nth-match([title="Change Language"], 2)');
- await app.click('text=Tailwind CSS');
- await app.click('text=CSS');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `@tailwind base;
-@tailwind components;
-@tailwind utilities;
-`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain(`Tailwind in Vue SFC`);
- expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe(
- 'rgb(220, 38, 38)',
- );
- });
-
- test('Vue 2', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Vue 2');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `
-Hello, {{ title }}
-
-
-`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain(`Hello, Vue 2`);
- expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(0, 0, 255)');
- });
-
- test('Svelte', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await (await app.$('[data-lang="svelte"]'))?.click();
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `
-
-
-
Hello, {title}
-
-`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain(`Hello, Svelte`);
- expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(0, 0, 255)');
- });
-
- test('Malina.js', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Malina.js');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `
-
-
-
Hello, {title}
-
-`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain(`Hello, Malina.js`);
- expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(0, 0, 255)');
- });
-
- test('Stencil', async ({ page, getTestUrl, editor }) => {
- test.skip(editor === 'codejar', 'please fix');
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(' ');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Stencil');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `import { Component, Prop, h } from "@stencil/core";
-@Component({
- tag: "my-app",
- styles: "h1 { color: blue; }",
-})
-export class App {
- @Prop() title: string;
- render() {
- return (
- Hello, {this.title}
- );
- }
-}`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain(`Hello, Stencil`);
- expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(0, 0, 255)');
- });
-
- test('CoffeeScript', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=CoffeeScript');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`square = (x) -> x * x`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('body > script');
-
- expect(resultText).toContain(`var square;`);
- expect(resultText).toContain(`square = function(x) {
- return x * x;
-};`);
- });
-
- test('LiveScript', async ({ page, getTestUrl, editor }) => {
- test.skip(editor === 'codejar', 'please fix');
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText('Hello, World ');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=LiveScript');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`{ capitalize, join, map, words } = require 'prelude-ls'
-title = 'live script'
-|> words
-|> map capitalize
-|> join ''
-(document.getElementById \\title).textContent = title`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerText('h1');
-
- expect(resultText).toContain(`Hello, LiveScript`);
- });
-
- test('Riot.js', async ({ page, getTestUrl, editor }) => {
- test.skip(editor === 'codejar', 'please fix');
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(' ');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Riot.js');
- await waitForEditorFocus(app);
- await page.keyboard.insertText('Hello, {props.title} ');
-
- await waitForResultUpdate();
- const resultText = await getResult().innerText('h1');
-
- expect(resultText).toContain(`Hello, Riot.js`);
- });
-
- test('AssemblyScript', async ({ page, getTestUrl }) => {
- test.fixme();
-
- await page.goto(getTestUrl());
-
- const { app, getResult } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `Hello, World
- `,
- );
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=AssemblyScript');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`export function getTitle(): string {return "AssemblyScript";`);
- // workaround for monaco auto-complete
- await page.keyboard.press('Delete');
- await page.keyboard.insertText(`}`);
-
- await app.waitForTimeout(15000);
- const resultText = await getResult().innerText('text=Hello, AssemblyScript');
-
- expect(resultText).toContain(`Hello, AssemblyScript`);
- });
-
- test('Python', async ({ page, getTestUrl, editor }) => {
- test.skip(editor === 'codejar', 'please fix');
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText('');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Python');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`from browser import document
-title = 'Python'
-document['header'].html = f"Hello, {title}"`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerText('h1');
-
- expect(resultText).toContain(`Hello, Python`);
- });
-
- test('Pyodide', async ({ page, getTestUrl }) => {
- test.skip();
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText('');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Pyodide');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`from js import document
-title = 'Python'
-document.getElementById('header').innerHTML = f"Hello, {title}"`);
-
- await waitForResultUpdate();
- await getResult().waitForSelector('text=Hello, Python');
- const resultText = await getResult().innerText('h1');
-
- expect(resultText).toContain(`Hello, Python`);
- });
-
- test('Ruby', async ({ page, getTestUrl, editor }) => {
- test.skip(editor === 'codejar', 'please fix');
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText('Hello, world ');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Ruby');
- await waitForEditorFocus(app);
-
- await page.keyboard.insertText(`require "native"
-title = 'Ruby'
-$$.document.querySelector('#title').innerHTML = title`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerText('text=Hello, Ruby');
-
- expect(resultText).toContain(`Hello, Ruby`);
- });
-
- test('Go', async ({ page, getTestUrl, editor }) => {
- test.slow();
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText('Hello, world ');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Go');
- await waitForEditorFocus(app);
-
- await page.keyboard.insertText(`package main
-import "syscall/js"
-func main() {
- js.Global().Get("document").Call("querySelector", "#title").Set("innerHTML", "Golang")
-}`);
-
- await waitForResultUpdate({ delay: 4000, timeout: 60_000 });
- const resultText = await getResult().innerText('h1');
-
- expect(resultText).toContain(`Hello, Golang`);
- });
-
- test('PHP', async ({ page, getTestUrl, editor }) => {
- test.skip(editor === 'codejar', 'please fix');
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText('Hello, world ');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=PHP');
- await waitForEditorFocus(app);
-
- // go below pre-inserted 'getElementById('title')->textContent = $title;`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerText('h1');
-
- expect(resultText).toContain(`Hello, PHP`);
- });
-
- test('Perl', async ({ page, getTestUrl, editor }) => {
- test.skip(editor === 'codejar', 'please fix');
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText('Hello, world ');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Perl');
- await waitForEditorFocus(app);
-
- await page.keyboard.insertText(`use strict;
-my $title = 'Perl';
-JS::inline('document.getElementById("title").innerHTML') = $title;`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerText('h1');
-
- expect(resultText).toContain(`Hello, Perl`);
- });
-
- test('Lua', async ({ page, getTestUrl, editor }) => {
- test.skip(editor === 'codejar', 'please fix');
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText('Hello, world ');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Lua');
- await waitForEditorFocus(app);
-
- await page.keyboard.insertText(`js = require "js"
-window = js.global
-document = window.document
-document:getElementById("title").innerHTML = "Lua"`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerText('h1');
-
- expect(resultText).toContain(`Hello, Lua`);
- });
-
- test('Scheme', async ({ page, getTestUrl, editor }) => {
- test.skip(editor === 'codejar', 'please fix');
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText('Hello, world ');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Scheme');
- await waitForEditorFocus(app);
-
- await page.keyboard.insertText(`(let ((title "Scheme"))
- (set-content! "#title" title))`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerText('h1');
-
- expect(resultText).toContain(`Hello, Scheme`);
- });
-});
+import { expect } from '@playwright/test';
+import { getLoadedApp, waitForEditorFocus } from '../helpers';
+import { test } from '../test-fixtures';
+
+test.describe('Compiler Results', () => {
+ test('HTML/CSS/JS', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.type('hello, ');
+
+ await app.click(':nth-match([title="Change Language"], 2)');
+ await app.click('text="CSS"');
+ await waitForEditorFocus(app);
+ await page.keyboard.type('body {color: blue;}');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text="JavaScript"');
+ await waitForEditorFocus(app);
+ await page.keyboard.type('document.body.innerHTML += "world!"');
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerText('body');
+
+ expect(resultText).toContain('hello, world!');
+ expect(await getResult().$eval('body', (e) => getComputedStyle(e).color)).toBe(
+ 'rgb(0, 0, 255)',
+ );
+ });
+
+ test('Markdown', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Markdown');
+ await waitForEditorFocus(app);
+ await app.page().keyboard.type('# Hi There');
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toBe('Hi There');
+ });
+
+ test('MDX', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=MDX');
+ await waitForEditorFocus(app);
+ await app.page().keyboard.type(`
+import {Hello} from './script';
+
+
+`);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JSX');
+ await waitForEditorFocus(app);
+ await app.page().keyboard.type(`
+import React from 'react';
+export const Hello = (props) => Hello, {props.title}! ;
+`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toBe('Hello, World!');
+ });
+
+ test('Astro', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Astro');
+ await waitForEditorFocus(app);
+ await app.page().keyboard.type(`---
+const title = "World";
+---
+
+Hello, {title}! `);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toBe('Hello, World!');
+ });
+
+ test('Pug', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Pug');
+ await waitForEditorFocus(app);
+ await page.keyboard.type('h1 Hi There');
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toBe('Hi There');
+ });
+
+ test('Haml', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name": "Haml"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text="Haml"');
+ await waitForEditorFocus(app);
+ await page.keyboard.type('.content Hello, #{name}!');
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('.content');
+
+ expect(resultText).toContain('Hello, Haml!');
+ });
+
+ test('AsciiDoc', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=AsciiDoc');
+ await waitForEditorFocus(app);
+ await page.keyboard.type('== Hello, World!');
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h2');
+
+ expect(resultText).toContain('Hello, World!');
+ });
+
+ test('Mustache', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name": "Mustache"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Mustache');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{name}} `);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Mustache');
+ });
+
+ test('Mustache dynamic', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"prerender": false}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JavaScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`window.livecodes.templateData = { name: 'Mustache' };`);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Mustache');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{name}} `);
+
+ await waitForResultUpdate();
+ await app.waitForTimeout(3000);
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Mustache');
+ });
+
+ test('Handlebars', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name": "Handlebars"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Handlebars');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{name}} `);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Handlebars');
+ });
+
+ test('Handlebars dynamic', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"prerender": false}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JavaScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`window.livecodes.templateData = { name: 'Handlebars' };`);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Handlebars');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{name}} `);
+
+ await waitForResultUpdate();
+ await app.waitForTimeout(3000);
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Handlebars');
+ });
+
+ test('Nunjucks', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name": "Nunjucks"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Nunjucks');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{name}} `);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Nunjucks');
+ });
+
+ test('Nunjucks dynamic', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"prerender": false}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JavaScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`window.livecodes.templateData = { name: 'Nunjucks' };`);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Nunjucks');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{name}} `);
+
+ await waitForResultUpdate();
+ await app.waitForTimeout(3000);
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Nunjucks');
+ });
+
+ test('EJS', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name": "EJS"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=EJS');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to <%= name %> `);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to EJS');
+ });
+
+ test('EJS dynamic', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"prerender": false}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JavaScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`window.livecodes.templateData = { name: 'EJS' };`);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=EJS');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to <%= name %> `);
+
+ await waitForResultUpdate();
+ await app.waitForTimeout(3000);
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to EJS');
+ });
+
+ test('Eta', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name": "Eta"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text="Eta"');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to <%= it.name %> `);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Eta');
+ });
+
+ test('Eta dynamic', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"prerender": false}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JavaScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`window.livecodes.templateData = { name: 'Eta' };`);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text="Eta"');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to <%= it.name %> `);
+
+ await waitForResultUpdate();
+ await app.waitForTimeout(3000);
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Eta');
+ });
+
+ test('Liquid', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name":"liquid"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Liquid');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`{{ name | capitalize | prepend: "Welcome to "}}`);
+
+ await waitForResultUpdate();
+ const body = await getResult().$('body');
+
+ expect(await body?.innerHTML()).toContain('Welcome to Liquid');
+ });
+
+ test('Liquid dynamic', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"prerender": false}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JavaScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`window.livecodes.templateData = { name: 'liquid' };`);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Liquid');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`{{ name | capitalize | prepend: "Welcome to "}}`);
+
+ await waitForResultUpdate();
+ await app.waitForTimeout(3000);
+ const body = await getResult().$('body');
+
+ expect(await body?.innerHTML()).toContain('Welcome to Liquid');
+ });
+
+ test('doT', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name":"doT"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=doT');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{=it.name}} `);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to doT');
+ });
+
+ test('doT dynamic', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"prerender": false}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JavaScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`window.livecodes.templateData = { name: 'doT' };`);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=doT');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{=it.name}} `);
+
+ await waitForResultUpdate();
+ await app.waitForTimeout(3000);
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to doT');
+ });
+
+ test('Twig', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name": "Twig"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Twig');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{ name }} `);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Twig');
+ });
+
+ test('Twig dynamic', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"prerender": false}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JavaScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`window.livecodes.templateData = { name: 'Twig' };`);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Twig');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{ name }} `);
+
+ await waitForResultUpdate();
+ await app.waitForTimeout(3000);
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Twig');
+ });
+
+ test('Vento', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name": "Vento"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Vento');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{ name }} `);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Vento');
+ });
+
+ test('Vento dynamic', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"prerender": false}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JavaScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`window.livecodes.templateData = { name: 'Vento' };`);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Vento');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{ name }} `);
+
+ await waitForResultUpdate();
+ await app.waitForTimeout(3000);
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Vento');
+ });
+
+ test('art-template', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name": "art-template"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=art-template');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{ name }} `);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to art-template');
+ });
+
+ test('art-template dynamic', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"prerender": false}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JavaScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`window.livecodes.templateData = { name: 'art-template' };`);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=art-template');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{ name }} `);
+
+ await waitForResultUpdate();
+ await app.waitForTimeout(3000);
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to art-template');
+ });
+
+ test('jinja', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name": "jinja"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text="Jinja"');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{ name }} `);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to jinja');
+ });
+
+ test('jinja dynamic', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"prerender": false}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JavaScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`window.livecodes.templateData = { name: 'jinja' };`);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text="Jinja"');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{ name }} `);
+
+ await waitForResultUpdate();
+ await app.waitForTimeout(3000);
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to jinja');
+ });
+
+ test('BBCode', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=BBCode');
+ await waitForEditorFocus(app);
+ await app.page().keyboard.type('[quote]quoted text[/quote]');
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerText('blockquote');
+
+ expect(resultText).toBe('quoted text');
+ });
+
+ test('MJML', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=MJML');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`
+
+
+
+
+
+ Hello MJML!
+
+
+
+
+
+`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('table');
+
+ expect(resultText).toContain('Hello MJML!');
+ });
+
+ test('SCSS', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 2)');
+ await app.click('text=SCSS');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(
+ `$font-stack: Helvetica, sans-serif; body { font: 100% $font-stack; }`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('style');
+
+ expect(resultText).toContain('font: 100% Helvetica, sans-serif;');
+ });
+
+ test('Sass', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 2)');
+ await app.click('text=Sass');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`$font-stack: Helvetica, sans-serif\nbody\n font: 100% $font-stack`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('style');
+
+ expect(resultText).toContain('font: 100% Helvetica, sans-serif;');
+ });
+
+ test('Less', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 2)');
+ await app.click('text=Less');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`@width: 10px; #header { width: @width; }`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('style');
+
+ expect(resultText).toContain('width: 10px;');
+ });
+
+ test('Stylus', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 2)');
+ await app.click('text=Stylus');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`font-size = 14px\nbody\n font font-size Arial, sans-serif`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('style');
+
+ expect(resultText).toContain('font: 14px Arial, sans-serif;');
+ });
+
+ test('Stylis', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 2)');
+ await app.click('text=Stylis');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ '[namespace] {\n div {\n display: flex;\n\n @media screen {\n color: blue;\n }\n }\n\n div {\n transform: translateZ(0);\n\n h1, h2 {\n color: red;\n }\n }\n}',
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('style');
+
+ expect(resultText).toContain(
+ '[namespace] div{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}@media screen{[namespace] div{color:blue;}}[namespace] div{-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);}[namespace] div h1,[namespace] div h2{color:red;}',
+ );
+ });
+
+ test('PostCSS/postcssImportUrl', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 2)');
+ await app.click('text=Import Url');
+ await app.click('text=CSS');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`@import "github-markdown-css";`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('style');
+
+ expect(resultText).toContain('.markdown-body');
+ });
+
+ test('PostCSS/Autoprefixer', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 2)');
+ await app.click('text=Autoprefixer');
+ await app.click('text=CSS');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`.example { user-select: none; }`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('style');
+
+ expect(resultText).toContain('-webkit-user-select: none;');
+ });
+
+ test('PostCSS/Preset Env', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 2)');
+ await app.click('text=Preset Env');
+ await app.click('text=CSS');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `:root { --mainColor: #12345678; --secondaryColor: lab(32.5 38.5 -47.6 / 90%); }`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('style');
+
+ expect(resultText).toContain('--mainColor: rgba(18,52,86,0.47059);');
+ });
+
+ test('Babel', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Babel');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`[1, 2, 3].map(n => n + 1);`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('body > script');
+
+ expect(resultText).toContain(
+ `[1, 2, 3].map(function (n) {
+ return n + 1;
+});`,
+ );
+ });
+
+ test('Sucrase', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Sucrase');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`const Greet = (name: string) => <>Hello {name}!>;`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('body > script');
+
+ expect(resultText).toContain(
+ `const Greet = (name) => React.createElement(React.Fragment, null, "Hello " , name, "!");`,
+ );
+ });
+
+ test('TypeScript', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=TypeScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `type Fish = { swim: () => void };
+type Bird = { fly: () => void };
+declare function getSmallPet(): Fish | Bird;
+// ---cut---
+function isFish(pet: Fish | Bird): pet is Fish {
+ return (pet as Fish).swim !== undefined;
+}`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('body > script');
+
+ expect(resultText).toContain(
+ `// ---cut---
+function isFish(pet) {
+ return pet.swim !== undefined;
+}`,
+ );
+ });
+
+ test('Flow', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Flow');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ 'function foo(x: ?number): string {if (x) { return x; } return "default string"; }',
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('body > script');
+
+ expect(resultText).toContain(
+ 'function foo(x ) {if (x) { return x; } return "default string"; }',
+ );
+ });
+
+ test('JSX', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`Loading...
`);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text="JSX"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `
+const Hello = (props) => Hello, {props.name}
+export default () => ;
+`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain(`Hello, React`);
+ });
+
+ test('TSX', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text="TSX"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `
+interface Props { name: string }
+const Hello = (props: Props) => Hello, {props.name}
+export default () => ;
+`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain(`Hello, React`);
+ });
+
+ test('React', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`Loading...
`);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text="React"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `
+const Hello = (props) => Hello, {props.name}
+export default () => ;
+`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain(`Hello, React`);
+ });
+
+ test('React (TSX)', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text="React (TSX)"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `
+interface Props { name: string }
+const Hello = (props: Props) => Hello, {props.name}
+export default () => ;
+`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain(`Hello, React`);
+ });
+
+ test('Vue', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await (await app.$('[data-lang="vue"]'))?.click();
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `
+Hello, {{ title }}
+
+
+`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain(`Hello, Vue`);
+ expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(0, 0, 255)');
+ });
+
+ test('Vue JSX', async ({ page, getTestUrl }) => {
+ const sfc = `
+
+
+`;
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await (await app.$('[data-lang="vue"]'))?.click();
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(sfc);
+
+ await waitForResultUpdate();
+
+ await getResult().click('text=Click me');
+ await getResult().click('text=Click me');
+ await getResult().click('text=Click me');
+
+ const titleText = await getResult().innerText('h1');
+ expect(titleText).toBe('Hello, Vue!');
+
+ const counterText = await getResult().innerText('text=You clicked');
+ expect(counterText).toBe('You clicked 3 times.');
+ });
+
+ test('Vue import', async ({ page, getTestUrl }) => {
+ const sfc = `
+
+
+
+
+`;
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await (await app.$('[data-lang="vue"]'))?.click();
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(sfc);
+
+ await waitForResultUpdate();
+
+ // css import
+ const headHTML = await getResult().innerHTML('head');
+ expect(headHTML).toContain(
+ ' ',
+ );
+
+ // bare module import
+ const uuidText = await getResult().innerText('#uuid');
+ expect(uuidText.length).toBeGreaterThan(10);
+
+ // import vue component
+ await getResult().click(':nth-match(button, 1)');
+ await getResult().click(':nth-match(button, 1)');
+ await getResult().click(':nth-match(button, 1)');
+
+ // import vue component that has relative imports and fetches absolute url
+ const buttonText = await getResult().innerText(':nth-match(button, 1)');
+ expect(buttonText).toBe('Count is: 3, double is: 6');
+ });
+
+ test('Vue langs', async ({ page, getTestUrl }) => {
+ const sfc = `
+ # Hello, {{ name }}!
+ some text
+
+
+
+
+
+`;
+
+ await page.goto(
+ getTestUrl({
+ x: 'code/N4IgLglmA2CmIC4QFUB2kawCYAIAKATgPYBWsAxmCADQhawDO5BEADpEaoiDeAIYBzBogDaAXVp9KEAG6wAolihEC3Ji3a8AtnwIBrAK6tEoaH1QCDg+EgAWYLdF7lOYWOm4gAvrQZgAnnAmIGYWVgI2IOQMwrQu6O5USN6+zGxJpuaW1twyBvBxroncADxuWqxmbjihAgC8ADogWlhNAHwNBA2oODgAxDgAErDQ0ETUOMDAOKh8WrA4Xl4AhJ3dvSWsOAjkZjGNIAAkfoGwAHRuAB5g7QxE8zhXYCUA9KwdXaiv5ZV8bh-dNZfdTpGpZA5gBhNHAMWBgIwAno4eJ+GZzWAIGFgFgWHB1HAAcgAavkcABmAkAbiBrxB7ERNJOcDBFgOTBi0K0RCwBjgiN6hwAZq4ALR+KR6THDaBySDkPgTBjmBhi2AsQXUz4C1gsHQEfwilxjAiYvoAVgtmvWOGOFE4WF0BqNKkxAgIsHcVtQQN6tgAjJMfb0cML0JiAEwABkjAFIbaGwGKwBKvcHkURjZjDjqIHqnRmVKnFkCgxdYNdA1rgwnMX7o3GhaLxeQ9EXes6TTbYfEHfrDQWCEWvDSXkzYG0UiAxwxbB7IaIJFO0uxhAhxHEYoRGHDPLQdURyIw7gRV+uogY-PcAMpwyAWVfAHwgXOsFTzhCP2gBViMExPtx+A+IRZOEkTfowy5UIUCQeMkT5yCeECcNwAAs3hAA',
+ }),
+ );
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await (await app.$('[data-lang="vue"]'))?.click();
+ await waitForEditorFocus(app);
+ // await page.keyboard.insertText(sfc);
+
+ await waitForResultUpdate();
+
+ const headerText = await getResult().innerText('h1');
+
+ // markdown, scss, typescript
+ expect(headerText).toContain(`Hello, Vue 3!`);
+ expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(85, 85, 85)');
+
+ // css modules
+ expect(await getResult().$eval('p', (e) => getComputedStyle(e).color)).toBe('rgb(0, 128, 0)');
+ });
+
+ test('Vue + Tailwind CSS', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await (await app.$('[data-lang="vue"]'))?.click();
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `
+
+
Tailwind in Vue SFC
+
+
+`,
+ );
+
+ await app.click(':nth-match([title="Change Language"], 2)');
+ await app.click('text=Tailwind CSS');
+ await app.click('text=CSS');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `@tailwind base;
+@tailwind components;
+@tailwind utilities;
+`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain(`Tailwind in Vue SFC`);
+ expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe(
+ 'rgb(220, 38, 38)',
+ );
+ });
+
+ test('Vue 2', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Vue 2');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `
+Hello, {{ title }}
+
+
+`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain(`Hello, Vue 2`);
+ expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(0, 0, 255)');
+ });
+
+ test('Svelte', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await (await app.$('[data-lang="svelte"]'))?.click();
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `
+
+
+
Hello, {title}
+
+`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain(`Hello, Svelte`);
+ expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(0, 0, 255)');
+ });
+
+ test('Malina.js', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Malina.js');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `
+
+
+
Hello, {title}
+
+`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain(`Hello, Malina.js`);
+ expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(0, 0, 255)');
+ });
+
+ test('Stencil', async ({ page, getTestUrl, editor }) => {
+ test.skip(editor === 'codejar', 'please fix');
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(' ');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Stencil');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `import { Component, Prop, h } from "@stencil/core";
+@Component({
+ tag: "my-app",
+ styles: "h1 { color: blue; }",
+})
+export class App {
+ @Prop() title: string;
+ render() {
+ return (
+ Hello, {this.title}
+ );
+ }
+}`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain(`Hello, Stencil`);
+ expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(0, 0, 255)');
+ });
+
+ test('CoffeeScript', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=CoffeeScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`square = (x) -> x * x`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('body > script');
+
+ expect(resultText).toContain(`var square;`);
+ expect(resultText).toContain(`square = function(x) {
+ return x * x;
+};`);
+ });
+
+ test('LiveScript', async ({ page, getTestUrl, editor }) => {
+ test.skip(editor === 'codejar', 'please fix');
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText('Hello, World ');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=LiveScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`{ capitalize, join, map, words } = require 'prelude-ls'
+title = 'live script'
+|> words
+|> map capitalize
+|> join ''
+(document.getElementById \\title).textContent = title`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerText('h1');
+
+ expect(resultText).toContain(`Hello, LiveScript`);
+ });
+
+ test('Riot.js', async ({ page, getTestUrl, editor }) => {
+ test.skip(editor === 'codejar', 'please fix');
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(' ');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Riot.js');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText('Hello, {props.title} ');
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerText('h1');
+
+ expect(resultText).toContain(`Hello, Riot.js`);
+ });
+
+ test('AssemblyScript', async ({ page, getTestUrl }) => {
+ test.fixme();
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `Hello, World
+ `,
+ );
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=AssemblyScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`export function getTitle(): string {return "AssemblyScript";`);
+ // workaround for monaco auto-complete
+ await page.keyboard.press('Delete');
+ await page.keyboard.insertText(`}`);
+
+ await app.waitForTimeout(15000);
+ const resultText = await getResult().innerText('text=Hello, AssemblyScript');
+
+ expect(resultText).toContain(`Hello, AssemblyScript`);
+ });
+
+ test('Python', async ({ page, getTestUrl, editor }) => {
+ test.skip(editor === 'codejar', 'please fix');
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText('');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Python');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`from browser import document
+title = 'Python'
+document['header'].html = f"Hello, {title}"`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerText('h1');
+
+ expect(resultText).toContain(`Hello, Python`);
+ });
+
+ test('Pyodide', async ({ page, getTestUrl }) => {
+ test.skip();
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText('');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Pyodide');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`from js import document
+title = 'Python'
+document.getElementById('header').innerHTML = f"Hello, {title}"`);
+
+ await waitForResultUpdate();
+ await getResult().waitForSelector('text=Hello, Python');
+ const resultText = await getResult().innerText('h1');
+
+ expect(resultText).toContain(`Hello, Python`);
+ });
+
+ test('Ruby', async ({ page, getTestUrl, editor }) => {
+ test.skip(editor === 'codejar', 'please fix');
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText('Hello, world ');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Ruby');
+ await waitForEditorFocus(app);
+
+ await page.keyboard.insertText(`require "native"
+title = 'Ruby'
+$$.document.querySelector('#title').innerHTML = title`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerText('text=Hello, Ruby');
+
+ expect(resultText).toContain(`Hello, Ruby`);
+ });
+
+ test('Go', async ({ page, getTestUrl, editor }) => {
+ test.slow();
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText('Hello, world ');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Go');
+ await waitForEditorFocus(app);
+
+ await page.keyboard.insertText(`package main
+import "syscall/js"
+func main() {
+ js.Global().Get("document").Call("querySelector", "#title").Set("innerHTML", "Golang")
+}`);
+
+ await waitForResultUpdate({ delay: 4000, timeout: 60_000 });
+ const resultText = await getResult().innerText('h1');
+
+ expect(resultText).toContain(`Hello, Golang`);
+ });
+
+ test('PHP', async ({ page, getTestUrl, editor }) => {
+ test.skip(editor === 'codejar', 'please fix');
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText('Hello, world ');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=PHP');
+ await waitForEditorFocus(app);
+
+ // go below pre-inserted 'getElementById('title')->textContent = $title;`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerText('h1');
+
+ expect(resultText).toContain(`Hello, PHP`);
+ });
+
+ test('Perl', async ({ page, getTestUrl, editor }) => {
+ test.skip(editor === 'codejar', 'please fix');
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText('Hello, world ');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Perl');
+ await waitForEditorFocus(app);
+
+ await page.keyboard.insertText(`use strict;
+my $title = 'Perl';
+JS::inline('document.getElementById("title").innerHTML') = $title;`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerText('h1');
+
+ expect(resultText).toContain(`Hello, Perl`);
+ });
+
+ test('Lua', async ({ page, getTestUrl, editor }) => {
+ test.skip(editor === 'codejar', 'please fix');
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText('Hello, world ');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Lua');
+ await waitForEditorFocus(app);
+
+ await page.keyboard.insertText(`js = require "js"
+window = js.global
+document = window.document
+document:getElementById("title").innerHTML = "Lua"`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerText('h1');
+
+ expect(resultText).toContain(`Hello, Lua`);
+ });
+
+ test('Scheme', async ({ page, getTestUrl, editor }) => {
+ test.skip(editor === 'codejar', 'please fix');
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText('Hello, world ');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Scheme');
+ await waitForEditorFocus(app);
+
+ await page.keyboard.insertText(`(let ((title "Scheme"))
+ (set-content! "#title" title))`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerText('h1');
+
+ expect(resultText).toContain(`Hello, Scheme`);
+ });
+});
diff --git a/eslint.config.mjs b/eslint.config.mjs
index aab8c872fb..1b84e6be5e 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -31,6 +31,7 @@ export default [
'**/.docusaurus',
'**/.jest',
'**/.storybook',
+ '**/.cache',
'functions/vendors',
],
},
diff --git a/functions/vendors/templates.js b/functions/vendors/templates.js
index 10dbce55f7..2bbc7ed68f 100644
--- a/functions/vendors/templates.js
+++ b/functions/vendors/templates.js
@@ -447,10 +447,10 @@ body {
font-size: 3.5rem;
}
}
-`.trimStart()},script:{language:"javascript",content:""},stylesheets:["{{ __CDN_URL__ }}bootstrap@5.3.0/dist/css/bootstrap.min.css"],scripts:["{{ __CDN_URL__ }}bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"],cssPreset:"",imports:{},types:{}};var y={name:"coffeescript",title:getTemplateName("templates.starter.coffeescript","CoffeeScript Starter"),thumbnail:"assets/templates/coffeescript.svg",activeEditor:"script",markup:{language:"html",content:`
+`.trimStart()},script:{language:"javascript",content:""},stylesheets:["{{ __CDN_URL__ }}bootstrap@5.3.0/dist/css/bootstrap.min.css"],scripts:["{{ __CDN_URL__ }}bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"],cssPreset:"",imports:{},types:{}};var y={name:"civet",title:getTemplateName("templates.starter.civet","Civet Starter"),thumbnail:"assets/templates/civet.png",activeEditor:"script",markup:{language:"html",content:`
Hello, World !
-
+
You clicked 0 times.
Click me
@@ -463,25 +463,25 @@ body {
.logo {
width: 150px;
}
-`.trimStart()},script:{language:"coffeescript",content:`
-titleElement = document.getElementById 'title'
-counterElement = document.getElementById 'counter'
-button = document.getElementById 'counter-button'
+`.trimStart()},script:{language:"civet",content:`
+titleElement := document.getElementById 'title'
+counterElement := document.getElementById 'counter'
+button := document.getElementById 'counter-button'
-title = 'CoffeeScript'
+title := 'Civet'
titleElement.innerText = title
-counter = (count) -> -> count += 1
-increment = counter 0
+counter := (count: number) => => count += 1
+increment := counter 0
+function handleClick: void counterElement.innerText = increment()
-button.addEventListener('click',
- -> counterElement.innerText = increment())
-`.trimStart()},stylesheets:[],scripts:[],cssPreset:"",imports:{},types:{}};var x={name:"go",title:getTemplateName("templates.starter.go","Go Starter"),thumbnail:"assets/templates/go.svg",activeEditor:"script",markup:{language:"html",content:`
+button.addEventListener 'click', handleClick
+`.trimStart()},stylesheets:[],scripts:[],cssPreset:"",imports:{},types:{}};var x={name:"clio",title:getTemplateName("templates.starter.clio","Clio Starter"),thumbnail:"assets/templates/clio.png",activeEditor:"script",markup:{language:"html",content:`
-
Hello, World !
-
+
Hello, World!
+
You clicked 0 times.
-
Click me
+
Loading...
`.trimStart()},style:{language:"css",content:`
.container,
@@ -490,62 +490,38 @@ button.addEventListener('click',
font: 1em sans-serif;
}
.logo {
- width: 250px;
+ width: 150px;
}
-`.trimStart()},script:{language:"go",content:`
-package main
-
-import (
- "fmt"
- "syscall/js"
- "time"
-)
-
-func main() {
- title := querySelector("#title")
- title.Set("innerHTML", "Golang")
+`.trimStart()},script:{language:"clio",content:`
+fn capitalize str:
+ (str.charAt 0 -> .toUpperCase) + (str.slice 1 -> .toLowerCase)
- registerCounter()
+fn greet name:
+ f"Hello, {name}!"
- // yes, you can use goroutines (check the console)
- go greet()
- fmt.Println("Hello!")
-}
+fn setTitle name:
+ title = document.querySelector "#title"
+ title.innerText = name -> capitalize -> greet
-func querySelector(id string) js.Value {
- return js.Global().Get("document").Call("querySelector", id)
-}
+fn increment value:
+ (Number value) + 1
-func registerCounter() {
- btn := querySelector("#counter-button")
- counter := querySelector("#counter")
- count := 0
+fn activateBtn btn:
+ btn.disabled = false
+ btn.innerText = "Click me"
+ btn
- var cb js.Func
- cb = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
- count += 1
- counter.Set("innerHTML", count)
- return nil
- })
- btn.Call("addEventListener", "click", cb)
-}
+fn onBtnClick:
+ counter = document.querySelector "#counter"
+ counter.innerText = increment counter.innerText
-func greet() {
- if hours, _, _ := time.Now().Clock(); hours < 12 {
- fmt.Println("Good morning")
- } else if hours < 18 {
- fmt.Println("Good afternoon")
- } else {
- fmt.Println("Good evening")
- }
-}
-`.trimStart()},stylesheets:[],scripts:[],cssPreset:"",imports:{},types:{}};var w={name:"jquery",title:getTemplateName("templates.starter.jquery","jQuery Starter"),thumbnail:"assets/templates/jquery.svg",activeEditor:"script",markup:{language:"html",content:`
-
-
Hello, World !
-
-
You clicked 0 times.
-
Click me
-
+export fn main argv:
+ setTitle "clio"
+ document.querySelector "#counter-button"
+ -> activateBtn
+ -> .addEventListener "click" onBtnClick
+`.trimStart()},stylesheets:[],scripts:[],cssPreset:"",imports:{},types:{}};var w={name:"clojurescript",title:getTemplateName("templates.starter.clojurescript","ClojureScript Starter"),thumbnail:"assets/templates/cljs.svg",activeEditor:"script",markup:{language:"html",content:`
+Loading...
`.trimStart()},style:{language:"css",content:`
.container,
.container button {
@@ -553,24 +529,43 @@ func greet() {
font: 1em sans-serif;
}
.logo {
- width: 300px;
+ width: 150px;
}
-`.trimStart()},script:{language:"javascript",content:`
-import $ from "jquery";
+`.trimStart()},script:{language:"clojurescript",content:`
+(ns react.component
+ (:require
+ ;; you may use npm packages
+ ["canvas-confetti$default" :as confetti]
+ ["react$default" :as React]
+ ["react" :refer [useState]]
+ ["react-dom/client" :refer [createRoot]]))
-$("#title").text('jQuery');
+(defn Counter [^:js {:keys [name]}]
+ (let [[counter setCount] (useState 0)]
+ #jsx [:div
+ {:className "container"}
+ [:h1 (str "Hello, " name "!")]
+ [:img
+ {:className "logo"
+ :alt "logo"
+ :src "{{ __livecodes_baseUrl__ }}assets/templates/cljs.svg"}]
+ [:p "You clicked " counter " times."]
+ [:button
+ {:onClick (fn []
+ (if (= (mod counter 3) 0) (confetti))
+ (setCount (inc counter)))}
+ "Click me"]]))
-let count = 0;
-$("#counter-button").click(() => {
- count += 1;
- $("#counter").text(count);
-});
-`.trimStart()},stylesheets:[],scripts:[],cssPreset:"",imports:{},types:{}};var S={name:"knockout",title:getTemplateName("templates.starter.knockout","Knockout Starter"),thumbnail:"assets/templates/knockout.svg",activeEditor:"script",markup:{language:"html",content:`
+(def title "ClojureScript")
+(print (str "Hello, " title "!"))
+(defonce root (createRoot (js/document.querySelector "#app")))
+(.render root #jsx [Counter #js {:name title}])
+`.trimStart()}};var S={name:"coffeescript",title:getTemplateName("templates.starter.coffeescript","CoffeeScript Starter"),thumbnail:"assets/templates/coffeescript.svg",activeEditor:"script",markup:{language:"html",content:`
-
Hello, World !
-
-
You clicked 0 times.
-
Click me
+
Hello, World !
+
+
You clicked 0 times.
+
Click me
`.trimStart()},style:{language:"css",content:`
.container,
@@ -579,27 +574,25 @@ $("#counter-button").click(() => {
font: 1em sans-serif;
}
.logo {
- width: 250px;
+ width: 150px;
}
-`.trimStart()},script:{language:"javascript",content:`
-import ko from "knockout";
+`.trimStart()},script:{language:"coffeescript",content:`
+titleElement = document.getElementById 'title'
+counterElement = document.getElementById 'counter'
+button = document.getElementById 'counter-button'
-class ClickCounterViewModel {
- constructor() {
- this.title = 'Knockout';
- this.numberOfClicks = ko.observable(0);
+title = 'CoffeeScript'
+titleElement.innerText = title
- this.registerClick = function () {
- this.numberOfClicks(this.numberOfClicks() + 1);
- };
- }
-}
+counter = (count) -> -> count += 1
+increment = counter 0
-ko.applyBindings(new ClickCounterViewModel());
-`.trimStart()},stylesheets:[],scripts:[],cssPreset:"",imports:{},types:{}};var k={name:"livescript",title:getTemplateName("templates.starter.livescript","LiveScript Starter"),thumbnail:"assets/templates/livescript.svg",activeEditor:"script",markup:{language:"html",content:`
+button.addEventListener('click',
+ -> counterElement.innerText = increment())
+`.trimStart()},stylesheets:[],scripts:[],cssPreset:"",imports:{},types:{}};var k={name:"commonlisp",title:getTemplateName("templates.starter.commonlisp","Common Lisp Starter"),thumbnail:"assets/templates/commonlisp.svg",activeEditor:"script",markup:{language:"html",content:`
-
Hello, World !
-
+
Hello, World!
+
You clicked 0 times.
Click me
@@ -612,31 +605,70 @@ ko.applyBindings(new ClickCounterViewModel());
.logo {
width: 150px;
}
-`.trimStart()},script:{language:"livescript",content:`
-{ capitalize, join, map, words } = require 'prelude-ls'
-
-title = 'live script'
-|> words
-|> map capitalize
-|> join ''
-
-(document.getElementById \\title).innerText = title
+`.trimStart()},script:{language:"commonlisp",content:`
+(defun set-attribute (&key selector attribute value)
+ (let ((node
+ (#j:document:querySelector selector)))
+ (setf (jscl::oget node attribute) value)
+ node))
-increment = (count) -> -> count += 1
-counter = increment 0
+(let ((title "Common Lisp"))
+ (set-attribute :selector "#title" :attribute "innerHTML"
+ :value (format nil "Hello, ~A!" title)))
-counter-element = document.getElementById \\counter
-button = document.getElementById \\counter-button
+(let ((counter 0))
+ (set-attribute :selector "#counter-button" :attribute "onclick"
+ :value #'(lambda (ev)
+ (setf counter (+ counter 1))
+ (set-attribute :selector "#counter" :attribute "innerHTML"
+ :value counter))))
-button.addEventListener \\click,
- -> counter-element.innerText = counter!
-`.trimStart()},stylesheets:[],scripts:[],cssPreset:"",imports:{},types:{}};var _={name:"lua",title:getTemplateName("templates.starter.lua","Lua Starter"),thumbnail:"assets/templates/lua.svg",activeEditor:"script",markup:{language:"html",content:`
+(#j:console:clear)
+(write "Hello, Common Lisp!")
+`.trimStart()},stylesheets:[],scripts:[],cssPreset:"",imports:{},types:{}};var _={name:"cpp",title:getTemplateName("templates.starter.cpp","C++ Starter"),thumbnail:"assets/templates/cpp.svg",activeEditor:"script",markup:{language:"html",content:`
-
Hello, World !
-
-
You clicked 0 times.
+
Hello, World !
+
+
You clicked 0 times.
Click me
+
+
+ {{polyfillScript}}
diff --git a/src/livecodes/html/language-info.html b/src/livecodes/html/language-info.html
index 940044e9ac..c990bac90d 100644
--- a/src/livecodes/html/language-info.html
+++ b/src/livecodes/html/language-info.html
@@ -534,6 +534,11 @@ Go
>Learn X in Y minutes, where X=Go
+
+ LiveCodes Documentations
+
Load starter template Go
+
+ Go (Wasm)
+
+ Go interpreter running on WebAssembly, using Yaegi
+
+
+
Haml
diff --git a/src/livecodes/i18n/locales/ar/language-info.lokalise.json b/src/livecodes/i18n/locales/ar/language-info.lokalise.json
index 4b572acc34..7b5634a8e7 100644
--- a/src/livecodes/i18n/locales/ar/language-info.lokalise.json
+++ b/src/livecodes/i18n/locales/ar/language-info.lokalise.json
@@ -222,6 +222,15 @@
"go.name": {
"translation": "Go"
},
+ "goWasm.desc": {
+ "translation": "مترجم Go يعمل على WebAssembly، باستخدام Yaegi"
+ },
+ "goWasm.link": {
+ "translation": "
اذهب إلى الموقع الرسمي يايجي تعلم X في دقائق Y، حيث X = اذهب وثائق LiveCodes تحميل قالب البداية تحميل قالب البداية "
+ },
+ "goWasm.name": {
+ "translation": "Go (Wasm)"
+ },
"haml.desc": {
"translation": "مترجم Haml لقوالب العرض في جافا سكريبت على جانب العميل باستخدام clientside-haml-js."
},
diff --git a/src/livecodes/i18n/locales/ar/language-info.ts b/src/livecodes/i18n/locales/ar/language-info.ts
index 706f696c6c..2326716de7 100644
--- a/src/livecodes/i18n/locales/ar/language-info.ts
+++ b/src/livecodes/i18n/locales/ar/language-info.ts
@@ -125,6 +125,11 @@ const languageInfo: I18nLangInfoTranslation = {
link: '<1><2>موقع جو2>1> <3><4>وثائق جو4>3> <5> <6>مستودع GopherJS6> 5> <7> <8>تعلم X في Y دقيقة، حيث X=Go8> 7> <9><10>تحميل قالب البداية10>9>',
name: 'Go',
},
+ goWasm: {
+ desc: 'مترجم Go يعمل على WebAssembly، باستخدام Yaegi',
+ link: '<1><2>اذهب إلى الموقع الرسمي2>1> <3><4>يايجي4>3> <5> <6>تعلم X في دقائق Y، حيث X = اذهب6> 5> <7> <8>وثائق LiveCodes8> 7> <9> <10>تحميل قالب البداية تحميل قالب البداية10> 9>',
+ name: 'Go (Wasm)',
+ },
haml: {
desc: 'مترجم Haml لقوالب العرض في جافا سكريبت على جانب العميل باستخدام clientside-haml-js.',
link: '<1><2>الموقع الرسمي لـ Haml2>1> <3> <4>وثائق Haml4> 3> <5> <6>مستودع GitHub لـ clientside-haml-js6> 5> <7> <8>تعلم X في Y دقيقة، حيث X=haml8> 7> <9> <10>وثائق LiveCodes10> 9>',
diff --git a/src/livecodes/i18n/locales/ar/translation.lokalise.json b/src/livecodes/i18n/locales/ar/translation.lokalise.json
index 0145456d6a..b2887000d5 100644
--- a/src/livecodes/i18n/locales/ar/translation.lokalise.json
+++ b/src/livecodes/i18n/locales/ar/translation.lokalise.json
@@ -1950,6 +1950,9 @@
"templates.starter.cpp": {
"translation": "قالب C++"
},
+ "templates.starter.cpp-wasm": {
+ "translation": "قالب C++ (Wasm)"
+ },
"templates.starter.daisyui": {
"translation": "قالب daisyUI"
},
@@ -1965,6 +1968,9 @@
"templates.starter.go": {
"translation": "قالب Go"
},
+ "templates.starter.go-wasm": {
+ "translation": "قالب Go (Wasm)"
+ },
"templates.starter.heading": {
"translation": "قوالب البداية"
},
diff --git a/src/livecodes/i18n/locales/ar/translation.ts b/src/livecodes/i18n/locales/ar/translation.ts
index 4d6465c08b..fc62be86ff 100644
--- a/src/livecodes/i18n/locales/ar/translation.ts
+++ b/src/livecodes/i18n/locales/ar/translation.ts
@@ -989,11 +989,13 @@ const translation: I18nTranslation = {
coffeescript: 'قالب CoffeeScript',
commonlisp: 'قالب Common Lisp',
cpp: 'قالب C++',
+ 'cpp-wasm': 'قالب C++ (Wasm)',
daisyui: 'قالب daisyUI',
diagrams: 'قالب الرسوم البيانية',
fennel: 'قالب Fennel',
gleam: 'قالب Gleam',
go: 'قالب Go',
+ 'go-wasm': 'قالب Go (Wasm)',
heading: 'قوالب البداية',
imba: 'قالب Imba',
java: 'قالب Java',
diff --git a/src/livecodes/i18n/locales/de/language-info.lokalise.json b/src/livecodes/i18n/locales/de/language-info.lokalise.json
index 955b04645a..b9160550d2 100644
--- a/src/livecodes/i18n/locales/de/language-info.lokalise.json
+++ b/src/livecodes/i18n/locales/de/language-info.lokalise.json
@@ -222,6 +222,15 @@
"go.name": {
"translation": "Go"
},
+ "goWasm.desc": {
+ "translation": "Go-Interpreter, der auf WebAssembly läuft, unter Verwendung von Yaegi"
+ },
+ "goWasm.link": {
+ "translation": "
Go offizielle Website Yaegi Lerne X in Y Minuten, wobei X=Go LiveCodes Dokumentationen Lade Startvorlage "
+ },
+ "goWasm.name": {
+ "translation": "Go (Wasm)"
+ },
"haml.desc": {
"translation": "Haml-Compiler für clientseitige JavaScript-View-Templates unter Verwendung von clientside-haml-js."
},
diff --git a/src/livecodes/i18n/locales/de/language-info.ts b/src/livecodes/i18n/locales/de/language-info.ts
index 65309a94da..6e1402c08a 100644
--- a/src/livecodes/i18n/locales/de/language-info.ts
+++ b/src/livecodes/i18n/locales/de/language-info.ts
@@ -128,6 +128,11 @@ const languageInfo: I18nLangInfoTranslation = {
link: '<1><2>Go Website2>1> <3><4>Go Dokumentation4>3> <5> <6>GopherJS Repository6> 5> <7> <8>Lerne X in Y Minuten, wobei X=Go8> 7> <9><10>Starter-Vorlage laden10>9>',
name: 'Go',
},
+ goWasm: {
+ desc: 'Go-Interpreter, der auf WebAssembly läuft, unter Verwendung von Yaegi',
+ link: '<1><2>Go offizielle Website2>1> <3><4>Yaegi4>3> <5> <6>Lerne X in Y Minuten, wobei X=Go6> 5> <7> <8>LiveCodes Dokumentationen8> 7> <9> <10>Lade Startvorlage10> 9>',
+ name: 'Go (Wasm)',
+ },
haml: {
desc: 'Haml-Compiler für clientseitige JavaScript-View-Templates unter Verwendung von clientside-haml-js.',
link: '<1><2>Haml offizielle Website2>1> <3> <4>Haml Dokumentation4> 3> <5> <6>clientside-haml-js GitHub Repository6> 5> <7> <8>Lerne X in Y Minuten, wobei X=haml8> 7> <9> <10>LiveCodes Dokumentation10> 9>',
diff --git a/src/livecodes/i18n/locales/de/translation.lokalise.json b/src/livecodes/i18n/locales/de/translation.lokalise.json
index 2832c23d75..1d05f2540e 100644
--- a/src/livecodes/i18n/locales/de/translation.lokalise.json
+++ b/src/livecodes/i18n/locales/de/translation.lokalise.json
@@ -1950,6 +1950,9 @@
"templates.starter.cpp": {
"translation": "C++-Starter"
},
+ "templates.starter.cpp-wasm": {
+ "translation": "C++ (Wasm)-Starter"
+ },
"templates.starter.daisyui": {
"translation": "daisyUI-Starter"
},
@@ -1965,6 +1968,9 @@
"templates.starter.go": {
"translation": "Go-Starter"
},
+ "templates.starter.go-wasm": {
+ "translation": "Go (Wasm)-Starter"
+ },
"templates.starter.heading": {
"translation": "Starter-Vorlagen"
},
diff --git a/src/livecodes/i18n/locales/de/translation.ts b/src/livecodes/i18n/locales/de/translation.ts
index c12c3da4be..c8e50df7d8 100644
--- a/src/livecodes/i18n/locales/de/translation.ts
+++ b/src/livecodes/i18n/locales/de/translation.ts
@@ -991,11 +991,13 @@ const translation: I18nTranslation = {
coffeescript: 'CoffeeScript-Starter',
commonlisp: 'Common Lisp-Starter',
cpp: 'C++-Starter',
+ 'cpp-wasm': 'C++ (Wasm)-Starter',
daisyui: 'daisyUI-Starter',
diagrams: 'Diagramm-Starter',
fennel: 'Fennel-Starter',
gleam: 'Gleam-Starter',
go: 'Go-Starter',
+ 'go-wasm': 'Go (Wasm)-Starter',
heading: 'Starter-Vorlagen',
imba: 'Imba-Starter',
java: 'Java-Starter',
diff --git a/src/livecodes/i18n/locales/en/language-info.lokalise.json b/src/livecodes/i18n/locales/en/language-info.lokalise.json
index bf064d71d7..d73b7f3b13 100644
--- a/src/livecodes/i18n/locales/en/language-info.lokalise.json
+++ b/src/livecodes/i18n/locales/en/language-info.lokalise.json
@@ -289,13 +289,25 @@
"translation": "Here, it is compiled to JavaScript using GopherJS."
},
"go.link": {
- "notes": "###
###\n \n\n### ###\n \n\n### ###\n \n\n### ###\n \n\n### ###\n \n\n### ###\n \n\n### ###\n \n\n### ###\n \n\n### ###\n \n\n### ###\n \n\n",
- "translation": "Go website Go documentation GopherJS repo Learn X in Y minutes, where X=Go Load starter template "
+ "notes": "### ###\n \n\n### ###\n \n\n### ###\n \n\n### ###\n \n\n### ###\n \n\n### ###\n \n\n### ###\n \n\n### ###\n \n\n### ###\n \n\n### ###\n \n\n### ###\n \n\n### ###\n \n\n",
+ "translation": "Go website Go documentation GopherJS repo Learn X in Y minutes, where X=Go LiveCodes Documentations Load starter template "
},
"go.name": {
"notes": "",
"translation": "Go"
},
+ "goWasm.desc": {
+ "notes": "",
+ "translation": "Go interpreter running on WebAssembly, using Yaegi"
+ },
+ "goWasm.link": {
+ "notes": "### ###\n \n\n### ###\n \n\n### ###\n \n\n### ###\n \n\n### ###\n \n\n### ###\n \n\n### ###\n \n\n### ###\n \n\n### ###\n \n\n### ###\n \n\n",
+ "translation": "Go official website Yaegi Learn X in Y minutes, where X=Go LiveCodes Documentations Load starter template "
+ },
+ "goWasm.name": {
+ "notes": "",
+ "translation": "Go (Wasm)"
+ },
"haml.desc": {
"notes": "",
"translation": "Haml compiler for client side javascript view templates using clientside-haml-js."
diff --git a/src/livecodes/i18n/locales/en/language-info.ts b/src/livecodes/i18n/locales/en/language-info.ts
index 820583ea22..849bf97bb1 100644
--- a/src/livecodes/i18n/locales/en/language-info.ts
+++ b/src/livecodes/i18n/locales/en/language-info.ts
@@ -131,9 +131,14 @@ const languageInfo = {
desc1:
'Go (Golang) is an open source programming language that makes it easy to build simple, reliable, and efficient software.',
desc2: 'Here, it is compiled to JavaScript using GopherJS.',
- link: '<1><2>Go website2>1> <3><4>Go documentation4>3> <5> <6>GopherJS repo6> 5> <7> <8>Learn X in Y minutes, where X=Go8> 7> <9> <10>Load starter template10> 9>',
+ link: '<1><2>Go website2>1> <3><4>Go documentation4>3> <5> <6>GopherJS repo6> 5> <7> <8>Learn X in Y minutes, where X=Go8> 7> <9> <10>LiveCodes Documentations10> 9> <11> <12>Load starter template12> 11>',
name: 'Go',
},
+ goWasm: {
+ desc: 'Go interpreter running on WebAssembly, using Yaegi',
+ link: '<1><2>Go official website2>1> <3><4>Yaegi4>3> <5> <6>Learn X in Y minutes, where X=Go6> 5> <7> <8>LiveCodes Documentations8> 7> <9> <10>Load starter template10> 9>',
+ name: 'Go (Wasm)',
+ },
haml: {
desc: 'Haml compiler for client side javascript view templates using clientside-haml-js.',
link: '<1><2>Haml official website2>1> <3> <4>Haml documentation4> 3> <5> <6>clientside-haml-js GitHub repo6> 5> <7> <8>Learn X in Y minutes, where X=haml8> 7> <9> <10>LiveCodes Documentations10> 9>',
diff --git a/src/livecodes/i18n/locales/en/translation.lokalise.json b/src/livecodes/i18n/locales/en/translation.lokalise.json
index d6d83d19e2..83f8a79203 100644
--- a/src/livecodes/i18n/locales/en/translation.lokalise.json
+++ b/src/livecodes/i18n/locales/en/translation.lokalise.json
@@ -2600,6 +2600,10 @@
"notes": "",
"translation": "C++ Starter"
},
+ "templates.starter.cpp-wasm": {
+ "notes": "",
+ "translation": "C++ (Wasm) Starter"
+ },
"templates.starter.daisyui": {
"notes": "",
"translation": "daisyUI Starter"
@@ -2620,6 +2624,10 @@
"notes": "",
"translation": "Go Starter"
},
+ "templates.starter.go-wasm": {
+ "notes": "",
+ "translation": "Go (Wasm) Starter"
+ },
"templates.starter.heading": {
"notes": "",
"translation": "Starter Templates"
diff --git a/src/livecodes/i18n/locales/en/translation.ts b/src/livecodes/i18n/locales/en/translation.ts
index 7346431e9b..9e7810b549 100644
--- a/src/livecodes/i18n/locales/en/translation.ts
+++ b/src/livecodes/i18n/locales/en/translation.ts
@@ -996,11 +996,13 @@ const translation = {
coffeescript: 'CoffeeScript Starter',
commonlisp: 'Common Lisp Starter',
cpp: 'C++ Starter',
+ 'cpp-wasm': 'C++ (Wasm) Starter',
daisyui: 'daisyUI Starter',
diagrams: 'Diagrams Starter',
fennel: 'Fennel Starter',
gleam: 'Gleam Starter',
go: 'Go Starter',
+ 'go-wasm': 'Go (Wasm) Starter',
heading: 'Starter Templates',
imba: 'Imba Starter',
java: 'Java Starter',
diff --git a/src/livecodes/i18n/locales/es/language-info.lokalise.json b/src/livecodes/i18n/locales/es/language-info.lokalise.json
index fdd413f099..53dec063ad 100644
--- a/src/livecodes/i18n/locales/es/language-info.lokalise.json
+++ b/src/livecodes/i18n/locales/es/language-info.lokalise.json
@@ -222,6 +222,15 @@
"go.name": {
"translation": "Go"
},
+ "goWasm.desc": {
+ "translation": "Intérprete Go ejecutándose en WebAssembly, usando Yaegi"
+ },
+ "goWasm.link": {
+ "translation": "Go sitio web oficial Yaegi Aprenda X en Y minutos, donde X=Go LiveCodes Documentations Cargar plantilla de inicio "
+ },
+ "goWasm.name": {
+ "translation": "Go (Wasm)"
+ },
"haml.desc": {
"translation": "Compilador Haml para plantillas de vista JavaScript del lado del cliente usando clientside-haml-js."
},
diff --git a/src/livecodes/i18n/locales/es/language-info.ts b/src/livecodes/i18n/locales/es/language-info.ts
index 1914077a67..79238313ca 100644
--- a/src/livecodes/i18n/locales/es/language-info.ts
+++ b/src/livecodes/i18n/locales/es/language-info.ts
@@ -128,6 +128,11 @@ const languageInfo: I18nLangInfoTranslation = {
link: '<1><2>Sitio web de Go2>1> <3><4>Documentación de Go4>3> <5> <6>Repositorio de GopherJS6> 5> <7> <8>Aprende X en Y minutos, donde X=Go8> 7> <9><10>Cargar plantilla inicial10>9>',
name: 'Go',
},
+ goWasm: {
+ desc: 'Intérprete Go ejecutándose en WebAssembly, usando Yaegi',
+ link: '<1><2>Go sitio web oficial2>1> <3><4>Yaegi4>3> <5> <6>Aprenda X en Y minutos, donde X=Go6> 5> <7> <8>LiveCodes Documentations8> 7> <9> <10>Cargar plantilla de inicio10> 9>',
+ name: 'Go (Wasm)',
+ },
haml: {
desc: 'Compilador Haml para plantillas de vista JavaScript del lado del cliente usando clientside-haml-js.',
link: '<1><2>Sitio web oficial de Haml2>1> <3> <4>Documentación de Haml4> 3> <5> <6>Repositorio GitHub de clientside-haml-js6> 5> <7> <8>Aprende X en Y minutos, donde X=haml8> 7> <9> <10>Documentación de LiveCodes10> 9>',
diff --git a/src/livecodes/i18n/locales/es/translation.lokalise.json b/src/livecodes/i18n/locales/es/translation.lokalise.json
index 8ad355d08a..fcff96d645 100644
--- a/src/livecodes/i18n/locales/es/translation.lokalise.json
+++ b/src/livecodes/i18n/locales/es/translation.lokalise.json
@@ -1950,6 +1950,9 @@
"templates.starter.cpp": {
"translation": "Inicio C++"
},
+ "templates.starter.cpp-wasm": {
+ "translation": "Inicio C++ (Wasm)"
+ },
"templates.starter.daisyui": {
"translation": "Inicio daisyUI"
},
@@ -1965,6 +1968,9 @@
"templates.starter.go": {
"translation": "Inicio Go"
},
+ "templates.starter.go-wasm": {
+ "translation": "Inicio Go (Wasm)"
+ },
"templates.starter.heading": {
"translation": "Plantillas de Inicio"
},
diff --git a/src/livecodes/i18n/locales/es/translation.ts b/src/livecodes/i18n/locales/es/translation.ts
index ec6f69b986..4530743f01 100644
--- a/src/livecodes/i18n/locales/es/translation.ts
+++ b/src/livecodes/i18n/locales/es/translation.ts
@@ -989,11 +989,13 @@ const translation: I18nTranslation = {
coffeescript: 'Inicio CoffeeScript',
commonlisp: 'Inicio Common Lisp',
cpp: 'Inicio C++',
+ 'cpp-wasm': 'Inicio C++ (Wasm)',
daisyui: 'Inicio daisyUI',
diagrams: 'Inicio Diagramas',
fennel: 'Inicio Fennel',
gleam: 'Inicio Gleam',
go: 'Inicio Go',
+ 'go-wasm': 'Inicio Go (Wasm)',
heading: 'Plantillas de Inicio',
imba: 'Inicio Imba',
java: 'Inicio Java',
diff --git a/src/livecodes/i18n/locales/fa/language-info.lokalise.json b/src/livecodes/i18n/locales/fa/language-info.lokalise.json
index 565b396ff4..6adf3cc2f7 100644
--- a/src/livecodes/i18n/locales/fa/language-info.lokalise.json
+++ b/src/livecodes/i18n/locales/fa/language-info.lokalise.json
@@ -222,6 +222,15 @@
"go.name": {
"translation": "Go"
},
+ "goWasm.desc": {
+ "translation": "Go interpreter در حال اجرا در WebAssembly، با استفاده از Yaegi"
+ },
+ "goWasm.link": {
+ "translation": "برو وب سایت رسمی یاگی X را در دقیقه Y یاد بگیرید، جایی که X=Go مستندات LiveCodes قالب استارت را بارگذاری کنید "
+ },
+ "goWasm.name": {
+ "translation": "Go (Wasm)"
+ },
"haml.desc": {
"translation": "کامپایلر Haml برای قالبهای نما جاوااسکریپت سمت کلاینت با استفاده از clientside-haml-js."
},
diff --git a/src/livecodes/i18n/locales/fa/language-info.ts b/src/livecodes/i18n/locales/fa/language-info.ts
index 7aecddd0d2..a298caa32f 100644
--- a/src/livecodes/i18n/locales/fa/language-info.ts
+++ b/src/livecodes/i18n/locales/fa/language-info.ts
@@ -127,6 +127,11 @@ const languageInfo: I18nLangInfoTranslation = {
link: '<1><2>وبسایت Go2>1> <3><4>مستندات Go4>3> <5> <6>مخزن GopherJS6> 5> <7> <8>یادگیری X در Y دقیقه، جایی که X=Go8> 7> <9> <10>بارگذاری قالب شروع کننده10> 9>',
name: 'Go',
},
+ goWasm: {
+ desc: 'Go interpreter در حال اجرا در WebAssembly، با استفاده از Yaegi',
+ link: '<1><2>برو وب سایت رسمی2>1> <3><4>یاگی4>3> <5> <6>X را در دقیقه Y یاد بگیرید، جایی که X=Go6> 5> <7> <8>مستندات LiveCodes8> 7> <9> <10>قالب استارت را بارگذاری کنید10> 9>',
+ name: 'Go (Wasm)',
+ },
haml: {
desc: 'کامپایلر Haml برای قالبهای نما جاوااسکریپت سمت کلاینت با استفاده از clientside-haml-js.',
link: '<1><2>وبسایت رسمی Haml2>1> <3> <4>مستندات Haml4> 3> <5> <6>مخزن GitHub clientside-haml-js6> 5> <7> <8>یادگیری X در Y دقیقه، جایی که X=haml8> 7> <9> <10>مستندات LiveCodes10> 9>',
diff --git a/src/livecodes/i18n/locales/fa/translation.lokalise.json b/src/livecodes/i18n/locales/fa/translation.lokalise.json
index 6914086373..d869534f47 100644
--- a/src/livecodes/i18n/locales/fa/translation.lokalise.json
+++ b/src/livecodes/i18n/locales/fa/translation.lokalise.json
@@ -1950,6 +1950,9 @@
"templates.starter.cpp": {
"translation": "شروع کننده C++"
},
+ "templates.starter.cpp-wasm": {
+ "translation": "شروع کننده Go (Wasm)"
+ },
"templates.starter.daisyui": {
"translation": "شروع کننده daisyUI"
},
@@ -1965,6 +1968,9 @@
"templates.starter.go": {
"translation": "شروع کننده Go"
},
+ "templates.starter.go-wasm": {
+ "translation": "شروع کننده Go (Wasm)"
+ },
"templates.starter.heading": {
"translation": "قالبهای شروع کننده"
},
diff --git a/src/livecodes/i18n/locales/fa/translation.ts b/src/livecodes/i18n/locales/fa/translation.ts
index f8bba0f514..a5d0c93cc8 100644
--- a/src/livecodes/i18n/locales/fa/translation.ts
+++ b/src/livecodes/i18n/locales/fa/translation.ts
@@ -990,11 +990,13 @@ const translation: I18nTranslation = {
coffeescript: 'شروع کننده CoffeeScript',
commonlisp: 'شروع کننده Common Lisp',
cpp: 'شروع کننده C++',
+ 'cpp-wasm': 'شروع کننده Go (Wasm)',
daisyui: 'شروع کننده daisyUI',
diagrams: 'شروع کننده نمودارها',
fennel: 'شروع کننده Fennel',
gleam: 'شروع کننده Gleam',
go: 'شروع کننده Go',
+ 'go-wasm': 'شروع کننده Go (Wasm)',
heading: 'قالبهای شروع کننده',
imba: 'شروع کننده Imba',
java: 'شروع کننده جاوا',
diff --git a/src/livecodes/i18n/locales/fr/language-info.lokalise.json b/src/livecodes/i18n/locales/fr/language-info.lokalise.json
index 8784f5634b..487be6ec2d 100644
--- a/src/livecodes/i18n/locales/fr/language-info.lokalise.json
+++ b/src/livecodes/i18n/locales/fr/language-info.lokalise.json
@@ -222,6 +222,15 @@
"go.name": {
"translation": "Go"
},
+ "goWasm.desc": {
+ "translation": "Interpréteur Go fonctionnant sur WebAssembly, utilisant Yaegi"
+ },
+ "goWasm.link": {
+ "translation": "Site officiel de Go Yaegi Apprendre X en Y minutes, où X=Go LiveCodes Documentations Charger un modèle de démarrage "
+ },
+ "goWasm.name": {
+ "translation": "Go (Wasm)"
+ },
"haml.desc": {
"translation": "Compilateur Haml pour les modèles de vue JavaScript côté client utilisant clientside-haml-js."
},
diff --git a/src/livecodes/i18n/locales/fr/language-info.ts b/src/livecodes/i18n/locales/fr/language-info.ts
index 64c5cf3187..85f55ccc73 100644
--- a/src/livecodes/i18n/locales/fr/language-info.ts
+++ b/src/livecodes/i18n/locales/fr/language-info.ts
@@ -128,6 +128,11 @@ const languageInfo: I18nLangInfoTranslation = {
link: '<1><2>Site web de Go2>1> <3><4>Documentation de Go4>3> <5> <6>Dépôt GopherJS6> 5> <7> <8>Apprenez X en Y minutes, où X=Go8> 7> <9><10>Charger le modèle de démarrage10>9>',
name: 'Go',
},
+ goWasm: {
+ desc: 'Interpréteur Go fonctionnant sur WebAssembly, utilisant Yaegi',
+ link: '<1><2>Site officiel de Go2>1> <3><4>Yaegi4>3> <5> <6>Apprendre X en Y minutes, où X=Go6> 5> <7> <8>LiveCodes Documentations8> 7> <9> <10>Charger un modèle de démarrage10> 9>',
+ name: 'Go (Wasm)',
+ },
haml: {
desc: 'Compilateur Haml pour les modèles de vue JavaScript côté client utilisant clientside-haml-js.',
link: '<1><2>Site officiel de Haml2>1> <3> <4>Documentation de Haml4> 3> <5> <6>Dépôt GitHub de clientside-haml-js6> 5> <7> <8>Apprenez X en Y minutes, où X=haml8> 7> <9> <10>Documentation LiveCodes10> 9>',
diff --git a/src/livecodes/i18n/locales/fr/translation.lokalise.json b/src/livecodes/i18n/locales/fr/translation.lokalise.json
index c9930fcf5f..448c55ba22 100644
--- a/src/livecodes/i18n/locales/fr/translation.lokalise.json
+++ b/src/livecodes/i18n/locales/fr/translation.lokalise.json
@@ -1950,6 +1950,9 @@
"templates.starter.cpp": {
"translation": "Démarrage C++"
},
+ "templates.starter.cpp-wasm": {
+ "translation": "Démarrage C++ (Wasm)"
+ },
"templates.starter.daisyui": {
"translation": "Démarrage daisyUI"
},
@@ -1965,6 +1968,9 @@
"templates.starter.go": {
"translation": "Démarrage Go"
},
+ "templates.starter.go-wasm": {
+ "translation": "Démarrage Go (Wasm)"
+ },
"templates.starter.heading": {
"translation": "Modèles de Démarrage"
},
diff --git a/src/livecodes/i18n/locales/fr/translation.ts b/src/livecodes/i18n/locales/fr/translation.ts
index bf8b5614fb..4b02dcc1aa 100644
--- a/src/livecodes/i18n/locales/fr/translation.ts
+++ b/src/livecodes/i18n/locales/fr/translation.ts
@@ -991,11 +991,13 @@ const translation: I18nTranslation = {
coffeescript: 'Démarrage CoffeeScript',
commonlisp: 'Démarrage Common Lisp',
cpp: 'Démarrage C++',
+ 'cpp-wasm': 'Démarrage C++ (Wasm)',
daisyui: 'Démarrage daisyUI',
diagrams: 'Démarrage Diagrammes',
fennel: 'Démarrage Fennel',
gleam: 'Démarrage Gleam',
go: 'Démarrage Go',
+ 'go-wasm': 'Démarrage Go (Wasm)',
heading: 'Modèles de Démarrage',
imba: 'Démarrage Imba',
java: 'Démarrage Java',
diff --git a/src/livecodes/i18n/locales/hi/language-info.lokalise.json b/src/livecodes/i18n/locales/hi/language-info.lokalise.json
index 06b89ff54e..5c4b26c454 100644
--- a/src/livecodes/i18n/locales/hi/language-info.lokalise.json
+++ b/src/livecodes/i18n/locales/hi/language-info.lokalise.json
@@ -222,6 +222,15 @@
"go.name": {
"translation": "Go"
},
+ "goWasm.desc": {
+ "translation": "Yaegi का उपयोग करके WebAssembly पर चलने वाले दुभाषिया पर जाएं"
+ },
+ "goWasm.link": {
+ "translation": "आधिकारिक वेबसाइट पर जाएं यागी Y मिनट में X जानें, जहां X=Go लाइवकोड्स दस्तावेज़ीकरण स्टार्टर टेम्पलेट लोड करें "
+ },
+ "goWasm.name": {
+ "translation": "Go (Wasm)"
+ },
"haml.desc": {
"translation": "क्लाइंटसाइड-haml-js का उपयोग करके क्लाइंट साइड जावास्क्रिप्ट व्यू टेम्प्लेट्स के लिए Haml कंपाइलर।"
},
diff --git a/src/livecodes/i18n/locales/hi/language-info.ts b/src/livecodes/i18n/locales/hi/language-info.ts
index 457d5f91e1..f829ebf33b 100644
--- a/src/livecodes/i18n/locales/hi/language-info.ts
+++ b/src/livecodes/i18n/locales/hi/language-info.ts
@@ -127,6 +127,11 @@ const languageInfo: I18nLangInfoTranslation = {
link: '<1><2>Go वेबसाइट2>1> <3><4>Go दस्तावेज़ीकरण4>3> <5> <6>GopherJS रेपो6> 5> <7> <8>X को Y मिनटों में सीखें, जहां X=Go8> 7> <9><10>स्टार्टर टेम्पलेट लोड करें10>9>',
name: 'Go',
},
+ goWasm: {
+ desc: 'Yaegi का उपयोग करके WebAssembly पर चलने वाले दुभाषिया पर जाएं',
+ link: '<1><2>आधिकारिक वेबसाइट पर जाएं2>1> <3><4>यागी4>3> <5> <6>Y मिनट में X जानें, जहां X=Go6> 5> <7> <8>लाइवकोड्स दस्तावेज़ीकरण8> 7> <9> <10>स्टार्टर टेम्पलेट लोड करें10> 9>',
+ name: 'Go (Wasm)',
+ },
haml: {
desc: 'क्लाइंटसाइड-haml-js का उपयोग करके क्लाइंट साइड जावास्क्रिप्ट व्यू टेम्प्लेट्स के लिए Haml कंपाइलर।',
link: '<1><2>Haml आधिकारिक वेबसाइट2>1> <3> <4>Haml दस्तावेज़ीकरण4> 3> <5> <6>clientside-haml-js GitHub रेपो6> 5> <7> <8>X को Y मिनटों में सीखें, जहां X=haml8> 7> <9> <10>LiveCodes दस्तावेज़ीकरण10> 9>',
diff --git a/src/livecodes/i18n/locales/hi/translation.lokalise.json b/src/livecodes/i18n/locales/hi/translation.lokalise.json
index 721c9a91ca..5903fb36b4 100644
--- a/src/livecodes/i18n/locales/hi/translation.lokalise.json
+++ b/src/livecodes/i18n/locales/hi/translation.lokalise.json
@@ -1950,6 +1950,9 @@
"templates.starter.cpp": {
"translation": "C++ स्टार्टर"
},
+ "templates.starter.cpp-wasm": {
+ "translation": "C++ (Wasm) स्टार्टर"
+ },
"templates.starter.daisyui": {
"translation": "daisyUI स्टार्टर"
},
@@ -1965,6 +1968,9 @@
"templates.starter.go": {
"translation": "Go स्टार्टर"
},
+ "templates.starter.go-wasm": {
+ "translation": "Go (Wasm) स्टार्टर"
+ },
"templates.starter.heading": {
"translation": "स्टार्टर टेम्पलेट्स"
},
diff --git a/src/livecodes/i18n/locales/hi/translation.ts b/src/livecodes/i18n/locales/hi/translation.ts
index 9411c5ed16..9da6a3082f 100644
--- a/src/livecodes/i18n/locales/hi/translation.ts
+++ b/src/livecodes/i18n/locales/hi/translation.ts
@@ -989,11 +989,13 @@ const translation: I18nTranslation = {
coffeescript: 'CoffeeScript स्टार्टर',
commonlisp: 'Common Lisp स्टार्टर',
cpp: 'C++ स्टार्टर',
+ 'cpp-wasm': 'C++ (Wasm) स्टार्टर',
daisyui: 'daisyUI स्टार्टर',
diagrams: 'आरेख स्टार्टर',
fennel: 'Fennel स्टार्टर',
gleam: 'Gleam स्टार्टर',
go: 'Go स्टार्टर',
+ 'go-wasm': 'Go (Wasm) स्टार्टर',
heading: 'स्टार्टर टेम्पलेट्स',
imba: 'Imba स्टार्टर',
java: 'Java स्टार्टर',
diff --git a/src/livecodes/i18n/locales/it/language-info.lokalise.json b/src/livecodes/i18n/locales/it/language-info.lokalise.json
index 940742e123..3dbf79b54c 100644
--- a/src/livecodes/i18n/locales/it/language-info.lokalise.json
+++ b/src/livecodes/i18n/locales/it/language-info.lokalise.json
@@ -222,6 +222,15 @@
"go.name": {
"translation": "Go"
},
+ "goWasm.desc": {
+ "translation": "Interprete Go in esecuzione su WebAssembly, utilizzando Yaegi"
+ },
+ "goWasm.link": {
+ "translation": "Sito ufficiale di Go Yaegi Imparare X in Y minuti, dove X=Go LiveCodes Documentations Caricare il modello di partenza "
+ },
+ "goWasm.name": {
+ "translation": "Go (Wasm)"
+ },
"haml.desc": {
"translation": "Compilatore Haml per template di vista JavaScript lato client utilizzando clientside-haml-js."
},
diff --git a/src/livecodes/i18n/locales/it/language-info.ts b/src/livecodes/i18n/locales/it/language-info.ts
index cd6bb68c34..a174242cdb 100644
--- a/src/livecodes/i18n/locales/it/language-info.ts
+++ b/src/livecodes/i18n/locales/it/language-info.ts
@@ -127,6 +127,11 @@ const languageInfo: I18nLangInfoTranslation = {
link: '<1><2>Sito web di Go2>1> <3><4>Documentazione di Go4>3> <5> <6>Repo di GopherJS6> 5> <7> <8>Impara X in Y minuti, dove X=Go8> 7> <9><10>Carica modello di partenza10>9>',
name: 'Go',
},
+ goWasm: {
+ desc: 'Interprete Go in esecuzione su WebAssembly, utilizzando Yaegi',
+ link: '<1><2>Sito ufficiale di Go2>1> <3><4>Yaegi4>3> <5> <6>Imparare X in Y minuti, dove X=Go6> 5> <7> <8>LiveCodes Documentations8> 7> <9> <10>Caricare il modello di partenza10> 9>',
+ name: 'Go (Wasm)',
+ },
haml: {
desc: 'Compilatore Haml per template di vista JavaScript lato client utilizzando clientside-haml-js.',
link: '<1><2>Sito ufficiale di Haml2>1> <3> <4>Documentazione di Haml4> 3> <5> <6>Repository GitHub di clientside-haml-js6> 5> <7> <8>Impara X in Y minuti, dove X=haml8> 7> <9> <10>Documentazione LiveCodes10> 9>',
diff --git a/src/livecodes/i18n/locales/it/translation.lokalise.json b/src/livecodes/i18n/locales/it/translation.lokalise.json
index 657f112407..aa2447dab8 100644
--- a/src/livecodes/i18n/locales/it/translation.lokalise.json
+++ b/src/livecodes/i18n/locales/it/translation.lokalise.json
@@ -1950,6 +1950,9 @@
"templates.starter.cpp": {
"translation": "Starter C++"
},
+ "templates.starter.cpp-wasm": {
+ "translation": "Starter C++ (Wasm)"
+ },
"templates.starter.daisyui": {
"translation": "Starter daisyUI"
},
@@ -1965,6 +1968,9 @@
"templates.starter.go": {
"translation": "Starter Go"
},
+ "templates.starter.go-wasm": {
+ "translation": "Starter Go (Wasm)"
+ },
"templates.starter.heading": {
"translation": "Modelli di Partenza"
},
diff --git a/src/livecodes/i18n/locales/it/translation.ts b/src/livecodes/i18n/locales/it/translation.ts
index e6af58b806..e114e0149f 100644
--- a/src/livecodes/i18n/locales/it/translation.ts
+++ b/src/livecodes/i18n/locales/it/translation.ts
@@ -990,11 +990,13 @@ const translation: I18nTranslation = {
coffeescript: 'Starter CoffeeScript',
commonlisp: 'Starter Common Lisp',
cpp: 'Starter C++',
+ 'cpp-wasm': 'Starter C++ (Wasm)',
daisyui: 'Starter daisyUI',
diagrams: 'Starter Diagrammi',
fennel: 'Starter Fennel',
gleam: 'Starter Gleam',
go: 'Starter Go',
+ 'go-wasm': 'Starter Go (Wasm)',
heading: 'Modelli di Partenza',
imba: 'Starter Imba',
java: 'Starter Java',
diff --git a/src/livecodes/i18n/locales/ja/language-info.lokalise.json b/src/livecodes/i18n/locales/ja/language-info.lokalise.json
index 66b7e00bd9..ecc5203a35 100644
--- a/src/livecodes/i18n/locales/ja/language-info.lokalise.json
+++ b/src/livecodes/i18n/locales/ja/language-info.lokalise.json
@@ -222,6 +222,15 @@
"go.name": {
"translation": "Go"
},
+ "goWasm.desc": {
+ "translation": "WebAssembly上で動作するGoインタプリタ、Yaegiを使用"
+ },
+ "goWasm.link": {
+ "translation": "囲碁公式サイト 八重垣 XをY分で学ぶ、X=囲碁 LiveCodesドキュメンテーション スターターテンプレートの読み込み "
+ },
+ "goWasm.name": {
+ "translation": "Go (Wasm)"
+ },
"haml.desc": {
"translation": "clientside-haml-js を使用したクライアントサイド JavaScript ビューテンプレート用の Haml コンパイラ。"
},
diff --git a/src/livecodes/i18n/locales/ja/language-info.ts b/src/livecodes/i18n/locales/ja/language-info.ts
index d593748fc6..a2c7af56b1 100644
--- a/src/livecodes/i18n/locales/ja/language-info.ts
+++ b/src/livecodes/i18n/locales/ja/language-info.ts
@@ -127,6 +127,11 @@ const languageInfo: I18nLangInfoTranslation = {
link: '<1><2>Go ウェブサイト2>1> <3><4>Go ドキュメント4>3> <5> <6>GopherJS リポジトリ6> 5> <7> <8>X分でYを学ぶ、X=Go8> 7> <9><10>スターターテンプレートを読み込む10>9>',
name: 'Go',
},
+ goWasm: {
+ desc: 'WebAssembly上で動作するGoインタプリタ、Yaegiを使用',
+ link: '<1><2>囲碁公式サイト2>1> <3><4>八重垣4>3> <5> <6>XをY分で学ぶ、X=囲碁6> 5> <7> <8>LiveCodesドキュメンテーション8> 7> <9> <10>スターターテンプレートの読み込み10> 9>',
+ name: 'Go (Wasm)',
+ },
haml: {
desc: 'clientside-haml-js を使用したクライアントサイド JavaScript ビューテンプレート用の Haml コンパイラ。',
link: '<1><2>Haml 公式ウェブサイト2>1> <3> <4>Haml ドキュメント4> 3> <5> <6>clientside-haml-js GitHub リポジトリ6> 5> <7> <8>X分でYを学ぶ、X=haml8> 7> <9> <10>LiveCodes ドキュメント10> 9>',
diff --git a/src/livecodes/i18n/locales/ja/translation.lokalise.json b/src/livecodes/i18n/locales/ja/translation.lokalise.json
index e6b88f2abf..af16dd574e 100644
--- a/src/livecodes/i18n/locales/ja/translation.lokalise.json
+++ b/src/livecodes/i18n/locales/ja/translation.lokalise.json
@@ -1950,6 +1950,9 @@
"templates.starter.cpp": {
"translation": "C++スターター"
},
+ "templates.starter.cpp-wasm": {
+ "translation": "C++(Wasm)スターター"
+ },
"templates.starter.daisyui": {
"translation": "daisyUIスターター"
},
@@ -1965,6 +1968,9 @@
"templates.starter.go": {
"translation": "Goスターター"
},
+ "templates.starter.go-wasm": {
+ "translation": "Go(Wasm)スターター"
+ },
"templates.starter.heading": {
"translation": "スターターテンプレート"
},
diff --git a/src/livecodes/i18n/locales/ja/translation.ts b/src/livecodes/i18n/locales/ja/translation.ts
index 2ad602c9ab..2b90d5ba45 100644
--- a/src/livecodes/i18n/locales/ja/translation.ts
+++ b/src/livecodes/i18n/locales/ja/translation.ts
@@ -989,11 +989,13 @@ const translation: I18nTranslation = {
coffeescript: 'CoffeeScriptスターター',
commonlisp: 'Common Lispスターター',
cpp: 'C++スターター',
+ 'cpp-wasm': 'C++(Wasm)スターター',
daisyui: 'daisyUIスターター',
diagrams: 'ダイアグラムスターター',
fennel: 'Fennelスターター',
gleam: 'Gleamスターター',
go: 'Goスターター',
+ 'go-wasm': 'Go(Wasm)スターター',
heading: 'スターターテンプレート',
imba: 'Imbaスターター',
java: 'Javaスターター',
diff --git a/src/livecodes/i18n/locales/pt/language-info.lokalise.json b/src/livecodes/i18n/locales/pt/language-info.lokalise.json
index 41d7a05153..1d9ef54339 100644
--- a/src/livecodes/i18n/locales/pt/language-info.lokalise.json
+++ b/src/livecodes/i18n/locales/pt/language-info.lokalise.json
@@ -222,6 +222,15 @@
"go.name": {
"translation": "Go"
},
+ "goWasm.desc": {
+ "translation": "Intérprete Go em execução no WebAssembly, usando Yaegi"
+ },
+ "goWasm.link": {
+ "translation": "Sítio Web oficial do Go Yaegi Aprender X em Y minutos, em que X=Go Documentações LiveCodes Carregar modelo inicial "
+ },
+ "goWasm.name": {
+ "translation": "Go (Wasm)"
+ },
"haml.desc": {
"translation": "Compilador Haml para modelos de visualização JavaScript do lado do cliente usando clientside-haml-js."
},
diff --git a/src/livecodes/i18n/locales/pt/language-info.ts b/src/livecodes/i18n/locales/pt/language-info.ts
index 1170313707..465969e0f3 100644
--- a/src/livecodes/i18n/locales/pt/language-info.ts
+++ b/src/livecodes/i18n/locales/pt/language-info.ts
@@ -127,6 +127,11 @@ const languageInfo: I18nLangInfoTranslation = {
link: '<1><2>Site do Go2>1> <3><4>Documentação do Go4>3> <5> <6>Repositório do GopherJS6> 5> <7> <8>Aprenda X em Y minutos, onde X=Go8> 7> <9><10>Carregar modelo inicial10>9>',
name: 'Go',
},
+ goWasm: {
+ desc: 'Intérprete Go em execução no WebAssembly, usando Yaegi',
+ link: '<1><2>Sítio Web oficial do Go2>1> <3><4>Yaegi4>3> <5> <6>Aprender X em Y minutos, em que X=Go6> 5> <7> <8>Documentações LiveCodes8> 7> <9> <10>Carregar modelo inicial10> 9>',
+ name: 'Go (Wasm)',
+ },
haml: {
desc: 'Compilador Haml para modelos de visualização JavaScript do lado do cliente usando clientside-haml-js.',
link: '<1><2>Site oficial do Haml2>1> <3> <4>Documentação do Haml4> 3> <5> <6>Repositório GitHub do clientside-haml-js6> 5> <7> <8>Aprenda X em Y minutos, onde X=haml8> 7> <9> <10>Documentação do LiveCodes10> 9>',
diff --git a/src/livecodes/i18n/locales/pt/translation.lokalise.json b/src/livecodes/i18n/locales/pt/translation.lokalise.json
index 1be85db133..851a549b21 100644
--- a/src/livecodes/i18n/locales/pt/translation.lokalise.json
+++ b/src/livecodes/i18n/locales/pt/translation.lokalise.json
@@ -1950,6 +1950,9 @@
"templates.starter.cpp": {
"translation": "Iniciante C++"
},
+ "templates.starter.cpp-wasm": {
+ "translation": "Iniciante C++ (Wasm)"
+ },
"templates.starter.daisyui": {
"translation": "Iniciante daisyUI"
},
@@ -1965,6 +1968,9 @@
"templates.starter.go": {
"translation": "Iniciante Go"
},
+ "templates.starter.go-wasm": {
+ "translation": "Iniciante Go (Wasm)"
+ },
"templates.starter.heading": {
"translation": "Modelos Iniciantes"
},
diff --git a/src/livecodes/i18n/locales/pt/translation.ts b/src/livecodes/i18n/locales/pt/translation.ts
index 7260f4e3c3..ded4a0be2f 100644
--- a/src/livecodes/i18n/locales/pt/translation.ts
+++ b/src/livecodes/i18n/locales/pt/translation.ts
@@ -990,11 +990,13 @@ const translation: I18nTranslation = {
coffeescript: 'Iniciante CoffeeScript',
commonlisp: 'Iniciante Common Lisp',
cpp: 'Iniciante C++',
+ 'cpp-wasm': 'Iniciante C++ (Wasm)',
daisyui: 'Iniciante daisyUI',
diagrams: 'Iniciante Diagrams',
fennel: 'Iniciante Fennel',
gleam: 'Iniciante Gleam',
go: 'Iniciante Go',
+ 'go-wasm': 'Iniciante Go (Wasm)',
heading: 'Modelos Iniciantes',
imba: 'Iniciante Imba',
java: 'Iniciante Java',
diff --git a/src/livecodes/i18n/locales/ru/language-info.lokalise.json b/src/livecodes/i18n/locales/ru/language-info.lokalise.json
index a3852feaa0..c4786bc7d4 100644
--- a/src/livecodes/i18n/locales/ru/language-info.lokalise.json
+++ b/src/livecodes/i18n/locales/ru/language-info.lokalise.json
@@ -222,6 +222,15 @@
"go.name": {
"translation": "Go"
},
+ "goWasm.desc": {
+ "translation": "Интерпретатор Go, работающий на WebAssembly, с использованием Yaegi"
+ },
+ "goWasm.link": {
+ "translation": "Официальный сайт Go Yaegi Узнайте X за Y минут, где X=Go Документация LiveCodes Загрузите стартовый шаблон "
+ },
+ "goWasm.name": {
+ "translation": "Go (Wasm)"
+ },
"haml.desc": {
"translation": "Компилятор Haml для клиентских шаблонов JavaScript с использованием clientside-haml-js."
},
diff --git a/src/livecodes/i18n/locales/ru/language-info.ts b/src/livecodes/i18n/locales/ru/language-info.ts
index 3554d0a592..c25e54afcb 100644
--- a/src/livecodes/i18n/locales/ru/language-info.ts
+++ b/src/livecodes/i18n/locales/ru/language-info.ts
@@ -129,6 +129,11 @@ const languageInfo: I18nLangInfoTranslation = {
link: '<1><2>Сайт Go2>1> <3><4>Документация Go4>3> <5> <6>Репозиторий GopherJS6> 5> <7> <8>Изучите X за Y минут, где X=Go8> 7> <9><10>Загрузить стартовый шаблон10>9>',
name: 'Go',
},
+ goWasm: {
+ desc: 'Интерпретатор Go, работающий на WebAssembly, с использованием Yaegi',
+ link: '<1><2>Официальный сайт Go2>1> <3><4>Yaegi4>3> <5> <6>Узнайте X за Y минут, где X=Go6> 5> <7> <8>Документация LiveCodes8> 7> <9> <10>Загрузите стартовый шаблон10> 9>',
+ name: 'Go (Wasm)',
+ },
haml: {
desc: 'Компилятор Haml для клиентских шаблонов JavaScript с использованием clientside-haml-js.',
link: '<1><2>Официальный сайт Haml2>1> <3> <4>Документация Haml4> 3> <5> <6>GitHub-репозиторий clientside-haml-js6> 5> <7> <8>Изучите X за Y минут, где X=haml8> 7> <9> <10>Документация LiveCodes10> 9>',
diff --git a/src/livecodes/i18n/locales/ru/translation.lokalise.json b/src/livecodes/i18n/locales/ru/translation.lokalise.json
index dece03eb6f..97c0d3a820 100644
--- a/src/livecodes/i18n/locales/ru/translation.lokalise.json
+++ b/src/livecodes/i18n/locales/ru/translation.lokalise.json
@@ -1950,6 +1950,9 @@
"templates.starter.cpp": {
"translation": "Стартер C++"
},
+ "templates.starter.cpp-wasm": {
+ "translation": "Стартер C++ (Wasm)"
+ },
"templates.starter.daisyui": {
"translation": "Стартер daisyUI"
},
@@ -1965,6 +1968,9 @@
"templates.starter.go": {
"translation": "Стартер Go"
},
+ "templates.starter.go-wasm": {
+ "translation": "Стартер Go (Wasm)"
+ },
"templates.starter.heading": {
"translation": "Стартовые шаблоны"
},
diff --git a/src/livecodes/i18n/locales/ru/translation.ts b/src/livecodes/i18n/locales/ru/translation.ts
index b631cf88f0..ee01115053 100644
--- a/src/livecodes/i18n/locales/ru/translation.ts
+++ b/src/livecodes/i18n/locales/ru/translation.ts
@@ -989,11 +989,13 @@ const translation: I18nTranslation = {
coffeescript: 'Стартер CoffeeScript',
commonlisp: 'Стартер Common Lisp',
cpp: 'Стартер C++',
+ 'cpp-wasm': 'Стартер C++ (Wasm)',
daisyui: 'Стартер daisyUI',
diagrams: 'Стартер диаграмм',
fennel: 'Стартер Fennel',
gleam: 'Стартер Gleam',
go: 'Стартер Go',
+ 'go-wasm': 'Стартер Go (Wasm)',
heading: 'Стартовые шаблоны',
imba: 'Стартер Imba',
java: 'Стартер Java',
diff --git a/src/livecodes/i18n/locales/ur/language-info.lokalise.json b/src/livecodes/i18n/locales/ur/language-info.lokalise.json
index 3126f5aa1b..08222d5590 100644
--- a/src/livecodes/i18n/locales/ur/language-info.lokalise.json
+++ b/src/livecodes/i18n/locales/ur/language-info.lokalise.json
@@ -222,6 +222,15 @@
"go.name": {
"translation": "گو"
},
+ "goWasm.desc": {
+ "translation": "Yaegi کا استعمال کرتے ہوئے WebAssembly پر چلنے والے مترجم پر جائیں۔"
+ },
+ "goWasm.link": {
+ "translation": "سرکاری ویب سائٹ پر جائیں یگی Y منٹ میں X سیکھیں ، جہاں X = Go لائیو کوڈز دستاویزات لوڈ اسٹارٹر سانچہ "
+ },
+ "goWasm.name": {
+ "translation": "Go (Wasm)"
+ },
"haml.desc": {
"translation": "کلائنٹ سائیڈ جاوا اسکرپٹ ویو ٹیمپلیٹس کے لیے کلائنٹ سائیڈ-ہیمل-جے ایس کا استعمال کرتے ہوئے ہیمل کمپائلر۔"
},
diff --git a/src/livecodes/i18n/locales/ur/language-info.ts b/src/livecodes/i18n/locales/ur/language-info.ts
index 9dc26e5bb9..d8d9f66514 100644
--- a/src/livecodes/i18n/locales/ur/language-info.ts
+++ b/src/livecodes/i18n/locales/ur/language-info.ts
@@ -128,6 +128,11 @@ const languageInfo: I18nLangInfoTranslation = {
link: '<1><2>گو ویب سائٹ2>1> <3><4>گو دستاویزات4>3> <5> <6>گوفر جے ایس ریپو6> 5> <7> <8>X کو Y منٹ میں سیکھیں، جہاں X=گو8> 7> <9><10>ابتدائی سانچہ لوڈ کریں10>9>',
name: 'گو',
},
+ goWasm: {
+ desc: 'Yaegi کا استعمال کرتے ہوئے WebAssembly پر چلنے والے مترجم پر جائیں۔',
+ link: '<1><2>سرکاری ویب سائٹ پر جائیں2>1> <3><4>یگی4>3> <5> <6>Y منٹ میں X سیکھیں ، جہاں X = Go6> 5> <7> <8>لائیو کوڈز دستاویزات8> 7> <9> <10>لوڈ اسٹارٹر سانچہ10> 9>',
+ name: 'Go (Wasm)',
+ },
haml: {
desc: 'کلائنٹ سائیڈ جاوا اسکرپٹ ویو ٹیمپلیٹس کے لیے کلائنٹ سائیڈ-ہیمل-جے ایس کا استعمال کرتے ہوئے ہیمل کمپائلر۔',
link: '<1><2>ہیمل کی سرکاری ویب سائٹ2>1> <3> <4>ہیمل دستاویزات4> 3> <5> <6>کلائنٹ سائیڈ-ہیمل-جے ایس گٹ ہب ریپو6> 5> <7> <8>X کو Y منٹ میں سیکھیں، جہاں X=ہیمل8> 7> <9> <10>لائیو کوڈز دستاویزات10> 9>',
diff --git a/src/livecodes/i18n/locales/ur/translation.lokalise.json b/src/livecodes/i18n/locales/ur/translation.lokalise.json
index f72e40283a..c3c5d43461 100644
--- a/src/livecodes/i18n/locales/ur/translation.lokalise.json
+++ b/src/livecodes/i18n/locales/ur/translation.lokalise.json
@@ -1950,6 +1950,9 @@
"templates.starter.cpp": {
"translation": "سی++ شروعاتی"
},
+ "templates.starter.cpp-wasm": {
+ "translation": "سی++ (واسم) شروعاتی"
+ },
"templates.starter.daisyui": {
"translation": "daisyUI شروعاتی"
},
@@ -1965,6 +1968,9 @@
"templates.starter.go": {
"translation": "گو شروعاتی"
},
+ "templates.starter.go-wasm": {
+ "translation": "گو (واسم) شروعاتی"
+ },
"templates.starter.heading": {
"translation": "شروعاتی سانچے"
},
diff --git a/src/livecodes/i18n/locales/ur/translation.ts b/src/livecodes/i18n/locales/ur/translation.ts
index 27a451cd4f..24aa686bdd 100644
--- a/src/livecodes/i18n/locales/ur/translation.ts
+++ b/src/livecodes/i18n/locales/ur/translation.ts
@@ -989,11 +989,13 @@ const translation: I18nTranslation = {
coffeescript: 'کافی اسکرپٹ شروعاتی',
commonlisp: 'کامن لسپ شروعاتی',
cpp: 'سی++ شروعاتی',
+ 'cpp-wasm': 'سی++ (واسم) شروعاتی',
daisyui: 'daisyUI شروعاتی',
diagrams: 'ڈایاگرامز شروعاتی',
fennel: 'فینل شروعاتی',
gleam: 'گلیم شروعاتی',
go: 'گو شروعاتی',
+ 'go-wasm': 'گو (واسم) شروعاتی',
heading: 'شروعاتی سانچے',
imba: 'امبا شروعاتی',
java: 'جاوا شروعاتی',
diff --git a/src/livecodes/i18n/locales/zh-CN/language-info.lokalise.json b/src/livecodes/i18n/locales/zh-CN/language-info.lokalise.json
index e53ce3c702..3f1399c9d7 100644
--- a/src/livecodes/i18n/locales/zh-CN/language-info.lokalise.json
+++ b/src/livecodes/i18n/locales/zh-CN/language-info.lokalise.json
@@ -222,6 +222,15 @@
"go.name": {
"translation": "Go"
},
+ "goWasm.desc": {
+ "translation": "使用 Yaegi 在 WebAssembly 上运行 Go 解释器"
+ },
+ "goWasm.link": {
+ "translation": "围棋官方网站 Yaegi 在 Y 分钟内学会 X,其中 X=Go LiveCodes 文档 加载启动模板 "
+ },
+ "goWasm.name": {
+ "translation": "Go (Wasm)"
+ },
"haml.desc": {
"translation": "使用 clientside-haml-js 的 Haml 编译器,用于编写客户端侧 JavaScript 视图模板。"
},
diff --git a/src/livecodes/i18n/locales/zh-CN/language-info.ts b/src/livecodes/i18n/locales/zh-CN/language-info.ts
index c06b638aa9..a01bb4731e 100644
--- a/src/livecodes/i18n/locales/zh-CN/language-info.ts
+++ b/src/livecodes/i18n/locales/zh-CN/language-info.ts
@@ -124,6 +124,11 @@ const languageInfo: I18nLangInfoTranslation = {
link: '<1><2>Go 官方网站2>1> <3><4>Go 文档4>3> <5> <6>GopherJS 仓库6> 5> <7> <8>在 Y 分钟内学习 X,其中 X=Go8> 7> <9><10>加载启动模板10>9>',
name: 'Go',
},
+ goWasm: {
+ desc: '使用 Yaegi 在 WebAssembly 上运行 Go 解释器',
+ link: '<1><2>围棋官方网站2>1> <3><4>Yaegi4>3> <5> <6>在 Y 分钟内学会 X,其中 X=Go6> 5> <7> <8>LiveCodes 文档8> 7> <9> <10>加载启动模板10> 9>',
+ name: 'Go (Wasm)',
+ },
haml: {
desc: '使用 clientside-haml-js 的 Haml 编译器,用于编写客户端侧 JavaScript 视图模板。',
link: '<1><2>Haml 官网2>1> <3> <4>Haml 文档4> 3> <5> <6>clientside-haml-js GitHub 仓库6> 5> <7> <8>在 Y 分钟内学习 X,其中 X=haml8> 7> <9> <10>LiveCodes 文档10> 9>',
diff --git a/src/livecodes/i18n/locales/zh-CN/translation.lokalise.json b/src/livecodes/i18n/locales/zh-CN/translation.lokalise.json
index 34d128b18c..b2e410b40f 100644
--- a/src/livecodes/i18n/locales/zh-CN/translation.lokalise.json
+++ b/src/livecodes/i18n/locales/zh-CN/translation.lokalise.json
@@ -1950,6 +1950,9 @@
"templates.starter.cpp": {
"translation": "C++ 启动模板"
},
+ "templates.starter.cpp-wasm": {
+ "translation": "C++(WASM)启动模板"
+ },
"templates.starter.daisyui": {
"translation": "daisyUI 启动模板"
},
@@ -1965,6 +1968,9 @@
"templates.starter.go": {
"translation": "Go 启动模板"
},
+ "templates.starter.go-wasm": {
+ "translation": "Go(WASM)启动模板"
+ },
"templates.starter.heading": {
"translation": "启动模板"
},
diff --git a/src/livecodes/i18n/locales/zh-CN/translation.ts b/src/livecodes/i18n/locales/zh-CN/translation.ts
index e5b541584e..1185d6da5d 100644
--- a/src/livecodes/i18n/locales/zh-CN/translation.ts
+++ b/src/livecodes/i18n/locales/zh-CN/translation.ts
@@ -987,11 +987,13 @@ const translation: I18nTranslation = {
coffeescript: 'CoffeeScript 启动模板',
commonlisp: 'Common Lisp 启动模板',
cpp: 'C++ 启动模板',
+ 'cpp-wasm': 'C++(WASM)启动模板',
daisyui: 'daisyUI 启动模板',
diagrams: '图表启动模板',
fennel: 'Fennel 启动模板',
gleam: 'Gleam 启动模板',
go: 'Go 启动模板',
+ 'go-wasm': 'Go(WASM)启动模板',
heading: '启动模板',
imba: 'Imba 启动模板',
java: 'Java 启动模板',
diff --git a/src/livecodes/languages/clojurescript/lang-clojurescript.ts b/src/livecodes/languages/clojurescript/lang-clojurescript.ts
index 60199edeee..6b438e8c5e 100644
--- a/src/livecodes/languages/clojurescript/lang-clojurescript.ts
+++ b/src/livecodes/languages/clojurescript/lang-clojurescript.ts
@@ -23,9 +23,9 @@ export const clojurescript: LanguageSpecs = {
imports: {
'cherry-cljs': cherryCljsBaseUrl + 'index.js',
'cherry-cljs/cljs.core.js': cherryCljsBaseUrl + 'cljs.core.js',
- 'cherry-cljs/lib/clojure.string.js': 'lib/clojure.string.js',
- 'cherry-cljs/lib/clojure.set.js': 'lib/clojure.set.js',
- 'cherry-cljs/lib/clojure.walk.js': 'lib/clojure.walk.js',
+ 'cherry-cljs/lib/clojure.string.js': cherryCljsBaseUrl + 'lib/clojure.string.js',
+ 'cherry-cljs/lib/clojure.set.js': cherryCljsBaseUrl + 'lib/clojure.set.js',
+ 'cherry-cljs/lib/clojure.walk.js': cherryCljsBaseUrl + 'lib/clojure.walk.js',
'squint-cljs': squintCljsBaseUrl + 'index.js',
'squint-cljs/core.js': squintCljsBaseUrl + 'core.js',
'squint-cljs/string.js': squintCljsBaseUrl + 'string.js',
diff --git a/src/livecodes/languages/diagrams/lang-diagrams-compiler-esm.ts b/src/livecodes/languages/diagrams/lang-diagrams-compiler-esm.ts
index ff45f7120b..d27d3da78d 100644
--- a/src/livecodes/languages/diagrams/lang-diagrams-compiler-esm.ts
+++ b/src/livecodes/languages/diagrams/lang-diagrams-compiler-esm.ts
@@ -16,7 +16,7 @@ import {
cytoscapeUrl,
elkjsBaseUrl,
graphreCdnUrl,
- hpccJsCdnUrl,
+ hpccJsCdnBaseUrl,
mermaidCdnUrl,
nomnomlCdnUrl,
pintoraUrl,
@@ -180,7 +180,7 @@ const compileGnuplot = async (code: string) => {
const compileMermaid = async (code: string) => {
let mermaid: any;
const load = async () => {
- mermaid = (await import(mermaidCdnUrl)).default;
+ mermaid = await loadScript(mermaidCdnUrl, 'mermaid');
mermaid.initialize({
startOnLoad: false,
});
@@ -201,7 +201,7 @@ const compileMermaid = async (code: string) => {
const compileGraphviz = async (code: string) => {
let graphviz: any;
const load = async () => {
- const hpccWasm = await import(hpccJsCdnUrl);
+ const hpccWasm = await import(hpccJsCdnBaseUrl + 'index.js');
graphviz = await hpccWasm.Graphviz.load();
};
const render = (src: string, script: HTMLScriptElement) => {
diff --git a/src/livecodes/languages/go-wasm/index.ts b/src/livecodes/languages/go-wasm/index.ts
new file mode 100644
index 0000000000..ef6da91230
--- /dev/null
+++ b/src/livecodes/languages/go-wasm/index.ts
@@ -0,0 +1 @@
+export * from './lang-go-wasm';
diff --git a/src/livecodes/languages/go-wasm/lang-go-wasm-script.ts b/src/livecodes/languages/go-wasm/lang-go-wasm-script.ts
new file mode 100644
index 0000000000..42641e491f
--- /dev/null
+++ b/src/livecodes/languages/go-wasm/lang-go-wasm-script.ts
@@ -0,0 +1,174 @@
+/* eslint-disable no-console */
+import { createWorkerFromContent } from '../../utils/utils';
+import { yaegiWasmBaseUrl } from '../../vendors';
+
+const workerSrc = `
+(async () => {
+ importScripts('${yaegiWasmBaseUrl}wasm_exec.js');
+
+ const wasmUrl = '${yaegiWasmBaseUrl}yaegi-browser.wasm';
+ const wasmResponse = await fetch(wasmUrl);
+
+ const initYaegi = async () => {
+ try {
+ let instance;
+ const go = new Go();
+ try {
+ const streaming = await WebAssembly.instantiateStreaming(wasmResponse.clone(), go.importObject);
+ instance = streaming.instance;
+ } catch {
+ const resp = await wasmResponse.clone();
+ if (!resp.ok)
+ throw new Error('Failed to fetch yaegi-browser.wasm: ' + resp.status);
+ const bytes = await resp.arrayBuffer();
+ const res = await WebAssembly.instantiate(bytes, go.importObject);
+ instance = res.instance;
+ }
+ go.run(instance);
+ } catch (err) {
+ console.error('Failed to load Yaegi:', err);
+ throw err;
+ }
+ };
+
+ addEventListener('message', async (e) => {
+ const runCode = async (code, input) => {
+ let output = null;
+ let error = null;
+ let exitCode = 0;
+
+ const originalConsoleLog = console.log;
+ const originalConsoleError = console.error;
+ let capturedOutput = '';
+ let capturedError = '';
+
+ try {
+ await initYaegi();
+
+ console.log = (...args) => {
+ capturedOutput += args.join(' ') + '\\n';
+ };
+
+ console.error = (...args) => {
+ capturedError += args.join(' ') + '\\n';
+ };
+
+ // Set up stdin if input is provided
+ if (input && globalThis.setStdin) {
+ globalThis.setStdin(input);
+ }
+
+ if (self.yaegi) {
+ try {
+ const result = await self.yaegi.eval(code);
+ } catch (err) {
+ console.error('Yaegi execution error:', err);
+ throw err;
+ }
+ } else {
+ throw new Error(
+ 'Yaegi not found on window. Make sure yaegi-browser.wasm is loaded correctly.',
+ );
+ }
+
+ output = capturedOutput.trim();
+ if (capturedError) {
+ error = capturedError.trim();
+ exitCode = 1;
+ }
+ } catch (err) {
+ error = err.message || err.toString();
+ exitCode = 1;
+ } finally {
+ // Restore console functions
+ console.log = originalConsoleLog;
+ console.error = originalConsoleError;
+ }
+
+ return { input, output, error, exitCode };
+ };
+
+ const code = e.data.code;
+ const input = e.data.input;
+ const result = code.trim() ? await runCode(code, input) : {};
+ postMessage(result);
+ });
+
+ // Initialize Yaegi when worker starts
+ initYaegi()
+ .then(() => {
+ postMessage({ loaded: true });
+ })
+ .catch((err) => {
+ console.error('Failed to initialize Yaegi:', err);
+ postMessage({ error: err.message });
+ });
+})();
+`;
+
+livecodes.goWasm = livecodes.goWasm || {};
+
+livecodes.goWasm.worker = livecodes.goWasm.worker || createWorkerFromContent(workerSrc);
+const worker: Worker = livecodes.goWasm.worker;
+
+const initialized = new Promise((resolve) => {
+ const onload = (e: MessageEvent) => {
+ console.log('Loading Yaegi WebAssembly...');
+ if (e.data.loaded) {
+ worker.removeEventListener('message', onload);
+ console.log('Yaegi WebAssembly loaded successfully.');
+ livecodes.goWasm.worker.loaded = true;
+ resolve();
+ }
+ };
+ if (!livecodes.goWasm.worker.loaded) {
+ worker.addEventListener('message', onload);
+ } else {
+ resolve();
+ }
+});
+
+livecodes.goWasm.run =
+ livecodes.goWasm.run ||
+ ((input: string) =>
+ new Promise((resolve) => {
+ let code = '';
+ livecodes.goWasm.input = input;
+ livecodes.goWasm.output = null;
+ const scripts = document.querySelectorAll('script[type="text/go-wasm"]');
+ scripts.forEach((script) => (code += (script.textContent ?? '') + '\n'));
+ worker.onmessage = function (e: MessageEvent) {
+ if (e.data.loaded) return;
+ const result = e.data;
+ if (result.error != null) {
+ console.error(result.error);
+ } else if (result.output != null) {
+ console.log(result.output);
+ }
+ livecodes.goWasm.input = result.input;
+ livecodes.goWasm.output = result.output;
+ livecodes.goWasm.error = result.error;
+ livecodes.goWasm.exitCode = result.exitCode;
+ livecodes.goWasm.ready = true;
+ resolve(result);
+ };
+
+ worker.postMessage({ code, input: `${String(input ?? '')}` });
+ }));
+
+livecodes.goWasm.loaded = new Promise((resolve) => {
+ const i = setInterval(() => {
+ if (livecodes.goWasm.ready) {
+ clearInterval(i);
+ return resolve();
+ }
+ }, 50);
+});
+
+window.addEventListener('load', async () => {
+ livecodes.goWasm.ready = false;
+ parent.postMessage({ type: 'loading', payload: true }, '*');
+ await initialized;
+ await livecodes.goWasm.run(livecodes.goWasm.input);
+ parent.postMessage({ type: 'loading', payload: false }, '*');
+});
diff --git a/src/livecodes/languages/go-wasm/lang-go-wasm.ts b/src/livecodes/languages/go-wasm/lang-go-wasm.ts
new file mode 100644
index 0000000000..8f8fcb0291
--- /dev/null
+++ b/src/livecodes/languages/go-wasm/lang-go-wasm.ts
@@ -0,0 +1,19 @@
+import type { LanguageSpecs } from '../../models';
+import { go } from '../go/lang-go';
+
+export const goWasm: LanguageSpecs = {
+ name: 'go-wasm',
+ title: 'Go (Wasm)',
+ formatter: go.formatter,
+ compiler: {
+ factory: () => async (code) => code,
+ scripts: ({ baseUrl }) => [baseUrl + '{{hash:lang-go-wasm-script.js}}'],
+ liveReload: true,
+ scriptType: 'text/go-wasm',
+ compiledCodeLanguage: 'go',
+ },
+ extensions: ['wasm.go', 'go-wasm', 'gowasm'],
+ editor: 'script',
+ editorLanguage: 'go',
+ largeDownload: true,
+};
diff --git a/src/livecodes/languages/languages.ts b/src/livecodes/languages/languages.ts
index 9f318652af..54e3479030 100644
--- a/src/livecodes/languages/languages.ts
+++ b/src/livecodes/languages/languages.ts
@@ -23,6 +23,7 @@ import { fennel } from './fennel';
import { flow } from './flow';
import { gleam } from './gleam';
import { go } from './go';
+import { goWasm } from './go-wasm';
import { haml } from './haml';
import { handlebars } from './handlebars';
import { html } from './html';
@@ -142,6 +143,7 @@ export const languages: LanguageSpecs[] = [
ruby,
rubyWasm,
go,
+ goWasm,
php,
phpWasm,
cpp,
diff --git a/src/livecodes/languages/postgresql/lang-postgresql-compiler-esm.ts b/src/livecodes/languages/postgresql/lang-postgresql-compiler-esm.ts
index aacc74f089..baa85b387b 100644
--- a/src/livecodes/languages/postgresql/lang-postgresql-compiler-esm.ts
+++ b/src/livecodes/languages/postgresql/lang-postgresql-compiler-esm.ts
@@ -1,6 +1,6 @@
import type { CompilerFunction } from '../../models';
import { getLanguageCustomSettings, safeName } from '../../utils/utils';
-import { pgliteUrl } from '../../vendors';
+import { pgliteBaseUrl } from '../../vendors';
declare global {
interface Window {
@@ -11,7 +11,7 @@ declare global {
export const pgSqlCompiler: CompilerFunction = async (code, { config }) => {
if (!code.trim()) return '{ data: [] }';
- window.PGlite = window.PGlite || (await import(pgliteUrl)).PGlite;
+ window.PGlite = window.PGlite || (await import(pgliteBaseUrl + 'index.js')).PGlite;
const options = getLanguageCustomSettings('pgsql', config);
const { dbName, scriptURLs, ...pgliteOptions } = options;
diff --git a/src/livecodes/languages/python-wasm/lang-python-wasm-script.ts b/src/livecodes/languages/python-wasm/lang-python-wasm-script.ts
index e0ec66b066..b4a378516b 100644
--- a/src/livecodes/languages/python-wasm/lang-python-wasm-script.ts
+++ b/src/livecodes/languages/python-wasm/lang-python-wasm-script.ts
@@ -1,5 +1,5 @@
/* eslint-disable no-underscore-dangle */
-import { fontAwesomeUrl, pyodideBaseUrl } from '../../vendors';
+import { pyodideBaseUrl } from '../../vendors';
declare const loadPyodide: any;
@@ -50,12 +50,6 @@ window.addEventListener('load', async () => {
}
async function prepareEnv() {
- // needed for matplotlib icons
- const stylesheet = document.createElement('link');
- stylesheet.rel = 'stylesheet';
- stylesheet.href = fontAwesomeUrl;
- document.head.append(stylesheet);
-
await pyodideReady;
const patchInput = `
from js import prompt
diff --git a/src/livecodes/languages/rescript/lang-rescript-compiler-esm.ts b/src/livecodes/languages/rescript/lang-rescript-compiler-esm.ts
index c12bf5243d..53170e41de 100644
--- a/src/livecodes/languages/rescript/lang-rescript-compiler-esm.ts
+++ b/src/livecodes/languages/rescript/lang-rescript-compiler-esm.ts
@@ -6,7 +6,10 @@ import {
reasonReactUrl,
reasonStdLibBaseUrl,
requireUrl,
- rescriptCdnBaseUrl,
+ rescriptCdnUrl1,
+ rescriptCdnUrl2,
+ rescriptCdnUrl3,
+ rescriptCdnUrl4,
rescriptStdLibBaseUrl,
} from '../../vendors';
@@ -57,12 +60,7 @@ const loadCompiler = async (language: Language) => {
);
} else {
window.require(
- [
- rescriptCdnBaseUrl + 'compiler.js',
- rescriptCdnBaseUrl + 'compiler-builtins/cmij.js',
- rescriptCdnBaseUrl + '%40rescript/react/cmij.js',
- rescriptCdnBaseUrl + '%40rescript/core/cmij.js',
- ],
+ [rescriptCdnUrl1, rescriptCdnUrl2, rescriptCdnUrl3, rescriptCdnUrl4],
() => {
window.rescript_ocaml_compiler = window.rescript_compiler;
window.rescript_compiler = undefined;
diff --git a/src/livecodes/languages/rescript/lang-rescript-formatter.ts b/src/livecodes/languages/rescript/lang-rescript-formatter.ts
index 6851d6cb7d..4036a7d642 100644
--- a/src/livecodes/languages/rescript/lang-rescript-formatter.ts
+++ b/src/livecodes/languages/rescript/lang-rescript-formatter.ts
@@ -1,12 +1,12 @@
import type { LanguageFormatter } from '../../models';
import { getAbsoluteUrl } from '../../utils';
-import { rescriptCdnBaseUrl } from '../../vendors';
+import { rescriptCdnUrl1 } from '../../vendors';
declare const importScripts: any;
const createRescriptFormatter: LanguageFormatter['factory'] = (baseUrl, language) => {
if (!(self as any).rescript_compiler) {
- importScripts(getAbsoluteUrl(rescriptCdnBaseUrl + 'compiler.js', baseUrl));
+ importScripts(getAbsoluteUrl(rescriptCdnUrl1, baseUrl));
}
const compiler = (self as any).rescript_compiler.make();
compiler.setModuleSystem('es6');
diff --git a/src/livecodes/languages/tailwindcss/processor-tailwindcss-compiler.ts b/src/livecodes/languages/tailwindcss/processor-tailwindcss-compiler.ts
index 5c3a3b4575..d9bf67bf17 100644
--- a/src/livecodes/languages/tailwindcss/processor-tailwindcss-compiler.ts
+++ b/src/livecodes/languages/tailwindcss/processor-tailwindcss-compiler.ts
@@ -6,6 +6,7 @@ import { modulesService } from '../../services';
import { getLanguageCustomSettings } from '../../utils/utils';
import { tailwindcss3Url, tailwindcssBaseUrl, vendorsBaseUrl } from '../../vendors';
import { lightningcssFeatures } from '../lightningcss/processor-lightningcss-compiler';
+import { addCodeInStyleBlocks } from './utils';
declare const self: any;
@@ -186,21 +187,21 @@ self.createTailwindcssCompiler = (): CompilerFunction => {
},
});
- return tailwind.generateStylesFromContent(code, [
- `${options.html}\n `,
- ]);
+ const html = `${options.html}\n `;
+ return tailwind.generateStylesFromContent(addCodeInStyleBlocks(code, html), [html]);
};
const tailwind4: CompilerFunction = async (code, { config, options }) => {
- const prepareCode = (css: string) => {
+ const prepareCode = (css: string, html: string) => {
let result = replaceStyleImports(css, [/tailwindcss/g]);
if (!result.includes('@import')) {
result = `@import "tailwindcss";${result}`;
}
- return result;
+ return addCodeInStyleBlocks(result, html);
};
+
const html = `${options.html}\n `;
- const css = prepareCode(code);
+ const css = prepareCode(code, html);
try {
const compiler = await self.tailwindcss.compile(css, {
base: '/',
diff --git a/src/livecodes/languages/tailwindcss/utils.ts b/src/livecodes/languages/tailwindcss/utils.ts
new file mode 100644
index 0000000000..ec39c53713
--- /dev/null
+++ b/src/livecodes/languages/tailwindcss/utils.ts
@@ -0,0 +1,13 @@
+export const addCodeInStyleBlocks = (css: string, html: string) => {
+ // from compiler/compile-blocks.ts#compileBlocks
+ const getBlockPattern = (el: 'style', langAttr = 'lang') =>
+ `(<${el}\\s*)(?:([\\s\\S]*?)${langAttr}\\s*=\\s*["']([A-Za-z0-9 _]*)["'])?((?:[^>]*)>)([\\s\\S]*?)(<\\/${el}>)`;
+ const pattern = getBlockPattern('style');
+ for (const arr of [...html.matchAll(new RegExp(pattern, 'g'))]) {
+ const content = arr[5];
+ if (content?.trim()) {
+ css += `\n${content}`;
+ }
+ }
+ return css;
+};
diff --git a/src/livecodes/languages/utils.ts b/src/livecodes/languages/utils.ts
index 903ca3aa17..beafe93f45 100644
--- a/src/livecodes/languages/utils.ts
+++ b/src/livecodes/languages/utils.ts
@@ -1,6 +1,6 @@
import type { Compiler, Config, CustomSettings, Language, Processor } from '../models';
import { getLanguageCustomSettings } from '../utils/utils';
-import { highlightjsUrl } from '../vendors';
+import { vendorsBaseUrl } from '../vendors';
export const getLanguageByAlias = (alias: string = ''): Language | undefined => {
if (!alias) return;
@@ -97,7 +97,8 @@ export const getCustomSettings = (
export const detectLanguage = async (code: string, languages: Language[]) => {
(window as any).HighlightJS =
- (window as any).HighlightJS || (await import(highlightjsUrl)).default;
+ (window as any).HighlightJS ||
+ (await import(vendorsBaseUrl + 'highlight.js/highlight.js')).default;
const result = (window as any).HighlightJS.highlightAuto(code, languages);
return {
language: result.language as Language,
diff --git a/src/livecodes/main.ts b/src/livecodes/main.ts
index b65d9c8f4a..d99136b19a 100644
--- a/src/livecodes/main.ts
+++ b/src/livecodes/main.ts
@@ -5,7 +5,7 @@ import appHTML from './html/app.html?raw';
import type { API, CDN, Config, CustomEvents, EmbedOptions } from './models';
import { modulesService } from './services/modules';
import { isInIframe } from './utils/utils';
-import { codeMirrorBaseUrl, esModuleShimsPath } from './vendors';
+import { codeMirrorBasePath, esModuleShimsPath } from './vendors';
export type { API, Config };
@@ -77,7 +77,7 @@ export const livecodes = (container: string, config: Partial = {}): Prom
const loadApp = async () => {
const appCDN = await modulesService.checkCDNs(esModuleShimsPath, params.get('appCDN') as CDN);
-
+ const codeMirrorBaseUrl = modulesService.getUrl(codeMirrorBasePath, appCDN as CDN);
const supportsImportMaps = HTMLScriptElement.supports
? HTMLScriptElement.supports('importmap')
: false;
@@ -104,6 +104,17 @@ export const livecodes = (container: string, config: Partial = {}): Prom
import * as mod from '${baseUrl}{{hash:codemirror.js}}';
window['${baseUrl}{{hash:codemirror.js}}'] = mod;
+ `,
+ )
+ .replace(
+ /{{polyfillScript}}/g,
+ process.env.LOCAL_MODULES === 'true'
+ ? ''
+ : `
+
`,
)
.replace(/{{codemirrorCoreUrl}}/g, `${codeMirrorBaseUrl}codemirror-core.js`)
diff --git a/src/livecodes/services/modules.ts b/src/livecodes/services/modules.ts
index 5ec3f1d25a..54f5e57a74 100644
--- a/src/livecodes/services/modules.ts
+++ b/src/livecodes/services/modules.ts
@@ -1,6 +1,7 @@
import type { CDN } from '../models';
declare const globalThis: { appCDN: CDN };
+const localModules = process.env.LOCAL_MODULES === 'true';
const moduleCDNs: CDN[] = [
'esm.sh',
@@ -60,14 +61,16 @@ export const modulesService = {
},
getUrl: (path: string, cdn?: CDN) =>
- path.startsWith('http') || path.startsWith('data:')
- ? path
- : getCdnUrl(path, false, cdn || getAppCDN()) || path,
+ path.startsWith('data:') ? path : getCdnUrl(path, false, cdn || getAppCDN()) || path,
cdnLists: { npm: npmCDNs, module: moduleCDNs, gh: ghCDNs },
checkCDNs: async (testModule: string, preferredCDN?: CDN) => {
- const cdns: CDN[] = [preferredCDN, ...modulesService.cdnLists.npm].filter(Boolean) as CDN[];
+ const modulesBaseUrl = new URL('./modules/', location.href).href as CDN;
+ const localCDN = localModules ? modulesBaseUrl : undefined;
+ const cdns = [preferredCDN, localCDN, ...modulesService.cdnLists.npm].filter(
+ (x) => x != null,
+ ) as CDN[];
for (const cdn of cdns) {
try {
const res = await fetch(modulesService.getUrl(testModule, cdn), {
@@ -94,6 +97,10 @@ export const getAppCDN = (): CDN => {
};
const getCdnUrl = (modName: string, isModule: boolean, defaultCDN?: CDN) => {
+ if (localModules && !isModule) {
+ return getLocalUrl(modName, defaultCDN);
+ }
+ if (modName.startsWith('data:')) return modName;
const post = isModule && modName.startsWith('unpkg:') ? '?module' : '';
if (modName.startsWith('gh:')) {
modName = modName.replace('gh', ghCDNs[0]);
@@ -107,9 +114,23 @@ const getCdnUrl = (modName: string, isModule: boolean, defaultCDN?: CDN) => {
return modName.replace(pattern, template) + post;
}
}
+ if (modName.startsWith('http')) return modName;
return null;
};
+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}`;
+};
+
// based on https://github.com/neoascetic/rawgithack/blob/master/web/rawgithack.js
const TEMPLATES: Array<[RegExp, string]> = [
[/^(esm\.sh:)(.+)/i, 'https://esm.sh/$2'],
diff --git a/src/livecodes/styles/inc-menu.scss b/src/livecodes/styles/inc-menu.scss
index 98ecebe646..4b92adf7c2 100644
--- a/src/livecodes/styles/inc-menu.scss
+++ b/src/livecodes/styles/inc-menu.scss
@@ -570,7 +570,7 @@ i.arrow {
width: var(--s16);
&[for='theme-color-custom'] {
- background: conic-gradient(in hsl longer hue, red 0 0);
+ background: conic-gradient(in hsl longer hue, red 0 100%);
filter: contrast(0.5);
}
diff --git a/src/livecodes/templates/starter/cpp-wasm-starter.ts b/src/livecodes/templates/starter/cpp-wasm-starter.ts
index 776e0e1cf8..8e54515005 100644
--- a/src/livecodes/templates/starter/cpp-wasm-starter.ts
+++ b/src/livecodes/templates/starter/cpp-wasm-starter.ts
@@ -3,7 +3,7 @@ import type { Template } from '../../models';
export const cppWasmStarter: Template = {
name: 'cpp-wasm',
aliases: ['clang'],
- title: 'C++ (Wasm) Starter',
+ title: window.deps.translateString('templates.starter.cpp-wasm', 'C++ (Wasm) Starter'),
thumbnail: 'assets/templates/cpp.svg',
activeEditor: 'script',
markup: {
diff --git a/src/livecodes/templates/starter/go-wasm-starter.ts b/src/livecodes/templates/starter/go-wasm-starter.ts
new file mode 100644
index 0000000000..1952a33370
--- /dev/null
+++ b/src/livecodes/templates/starter/go-wasm-starter.ts
@@ -0,0 +1,177 @@
+import type { Template } from '../../models';
+
+export const goWasmStarter: Template = {
+ name: 'go-wasm',
+ title: window.deps.translateString('templates.starter.go-wasm', 'Go (Wasm) Starter'),
+ thumbnail: 'assets/templates/go.svg',
+ activeEditor: 'script',
+ markup: {
+ language: 'html',
+ content: `
+
+
Go (Wasm)
+
+
+
+
Interactive Counter
+
Current count: 0
+
Loading...
+
+
+
+
Stdin Input Demo
+
Enter your name:
+
+
Loading...
+
+
+
+
+
+
+
+`.trimStart(),
+ },
+ style: {
+ language: 'css',
+ content: `
+.container {
+ max-width: 800px;
+ margin: 0 auto;
+ padding: 20px;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+}
+
+.logo {
+ width: 150px;
+ display: block;
+ margin: 20px auto;
+}
+
+.demo-section {
+ background: #f5f5f5;
+ padding: 20px;
+ margin: 20px 0;
+ border-radius: 8px;
+ border-left: 4px solid #00add8;
+}
+
+.demo-section h2 {
+ margin-top: 0;
+ color: #333;
+}
+
+button {
+ background: #00add8;
+ color: white;
+ border: none;
+ padding: 10px 20px;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 16px;
+ margin: 10px 5px;
+}
+
+button:hover:not(:disabled) {
+ background: #0099c7;
+}
+
+button:disabled {
+ background: #ccc;
+ cursor: not-allowed;
+}
+
+input[type="text"], input[type="number"] {
+ padding: 8px 12px;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ font-size: 16px;
+ margin: 5px;
+ width: 200px;
+}
+
+#counter {
+ font-weight: bold;
+ color: #00add8;
+ font-size: 24px;
+}
+
+#greeting, #result {
+ font-weight: bold;
+ color: #333;
+ margin-top: 10px;
+}
+`.trimStart(),
+ },
+ script: {
+ language: 'go-wasm',
+ content: `
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+)
+
+func main() {
+ // Read input from stdin
+ scanner := bufio.NewScanner(os.Stdin)
+
+ if scanner.Scan() {
+ input := strings.TrimSpace(scanner.Text())
+
+ if count, err := strconv.Atoi(input); err == nil {
+ newCount := count + 1
+ fmt.Println(newCount)
+ return
+ }
+
+ fmt.Printf("Hello, %s!\\n", input)
+ } else {
+ fmt.Println("Hello from Go WebAssembly!")
+ }
+}
+`.trimStart(),
+ },
+};
diff --git a/src/livecodes/templates/starter/index.ts b/src/livecodes/templates/starter/index.ts
index 1075d26834..9f8a22eb10 100644
--- a/src/livecodes/templates/starter/index.ts
+++ b/src/livecodes/templates/starter/index.ts
@@ -21,6 +21,7 @@ import { diagramsStarter } from './diagrams-starter';
import { fennelStarter } from './fennel-starter';
import { gleamStarter } from './gleam-starter';
import { goStarter } from './go-starter';
+import { goWasmStarter } from './go-wasm-starter';
import { imbaStarter } from './imba-starter';
import { javaStarter } from './java-starter';
import { javascriptStarter } from './javascript-starter';
@@ -111,6 +112,7 @@ export const starterTemplates = [
rubyStarter,
rubyWasmStarter,
goStarter,
+ goWasmStarter,
phpStarter,
phpWasmStarter,
cppStarter,
diff --git a/src/livecodes/types/bundle-types.ts b/src/livecodes/types/bundle-types.ts
index 89da0f9284..bf03eaaa38 100644
--- a/src/livecodes/types/bundle-types.ts
+++ b/src/livecodes/types/bundle-types.ts
@@ -1,6 +1,6 @@
// based on dts-bundle
-import { pathBrowserifyUrl } from '../vendors';
+import { vendorsBaseUrl } from '../vendors';
// const dtsExp = /\.d\.ts$/;
const bomOptExp = /^\uFEFF?/;
@@ -62,7 +62,7 @@ export interface BundleResult {
}
export async function bundle(options: Options): Promise {
- const path = await import(pathBrowserifyUrl);
+ const path = (await import(vendorsBaseUrl + 'path-browserify/path-browserify.js')).default;
assert(typeof options === 'object' && options, 'options must be an object');
// option parsing & validation
diff --git a/src/livecodes/utils/utils.ts b/src/livecodes/utils/utils.ts
index b22e84b73a..5ae0cc8929 100644
--- a/src/livecodes/utils/utils.ts
+++ b/src/livecodes/utils/utils.ts
@@ -623,21 +623,37 @@ export const isFocusable = /* @__PURE__ */ (item: any | null): boolean => {
* whose values are different from the destination object.
*/
export const compareObjects = /* @__PURE__ */ (
- srcObj: Record,
- dstObj: Record,
+ srcObj: Partial>,
+ dstObj: Partial>,
) => {
const diff: string[] = [];
for (const key of Object.keys(srcObj)) {
- if (typeof srcObj[key] === 'function') {
+ 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);
+ }
+ } else if (srcObjProp !== dstObjProp) {
diff.push(key);
}
}
diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts
index 3ee6afdcfc..8f21222fc7 100644
--- a/src/livecodes/vendors.ts
+++ b/src/livecodes/vendors.ts
@@ -1,9 +1,17 @@
import { modulesService } from './services/modules';
-const { getUrl, getModuleUrl } = modulesService;
+// - only use `getUrl` (not `getModuleUrl` or plain URLs) - except `es-module-shims` and `codeMirrorBasePath`
+// - only use `gh:` or `unpkg: prefixes if required
+// - always add full version and file extension
+// - minimize usage of baseUrls if possible
+// - if es module imports others, use baseUrl instead
+// - excluding `vendorsBaseUrl`, the file is sorted alphabetically
+// see scripts/download-modules.js
+
+const { getUrl } = modulesService;
export const vendorsBaseUrl = // 'http://127.0.0.1:8081/';
- /* @__PURE__ */ getUrl('@live-codes/browser-compilers@0.22.3/dist/');
+ /* @__PURE__ */ getUrl('@live-codes/browser-compilers@0.22.4/dist/');
export const acornUrl = /* @__PURE__ */ getUrl('acorn@8.12.1/dist/acorn.js');
@@ -41,7 +49,7 @@ export const browserJestUrl = /* @__PURE__ */ getUrl(
export const brythonBaseUrl = /* @__PURE__ */ getUrl('brython@3.12.4/');
-export const chaiUrl = /* @__PURE__ */ getModuleUrl('chai@5.1.2');
+export const chaiUrl = /* @__PURE__ */ getUrl('chai@5.2.1/chai.js');
export const cherryCljsBaseUrl = /* @__PURE__ */ getUrl('cherry-cljs@0.2.19/');
@@ -85,7 +93,7 @@ export const codeiumProviderUrl = /* @__PURE__ */ getUrl(
'@live-codes/monaco-codeium-provider@0.2.2/dist/index.js',
);
-export const codeMirrorBaseUrl = /* @__PURE__ */ getUrl('@live-codes/codemirror@0.3.2/build/');
+export const codeMirrorBasePath = '@live-codes/codemirror@0.3.2/build/';
export const coffeeScriptUrl = /* @__PURE__ */ getUrl(
'coffeescript@2.7.0/lib/coffeescript-browser-compiler-legacy/coffeescript.js',
@@ -99,6 +107,8 @@ export const cppWasmBaseUrl = /* @__PURE__ */ getUrl('@chriskoch/cpp-wasm@1.0.2/
export const csharpWasmBaseUrl = /* @__PURE__ */ getUrl('@seth0x41/csharp-wasm@1.0.3/');
+export const yaegiWasmBaseUrl = /* @__PURE__ */ getUrl('yaegi-wasm@1.0.2/src/');
+
export const csstreeUrl = /* @__PURE__ */ getUrl('css-tree@2.3.1/dist/csstree.js');
export const cytoscapeSvgUrl = /* @__PURE__ */ getUrl('cytoscape-svg@0.4.0/cytoscape-svg.js');
@@ -109,7 +119,7 @@ export const ddietrCmThemesBaseUrl = /* @__PURE__ */ getUrl(
'@ddietr/codemirror-themes@1.4.2/dist/theme/',
);
-export const doppioJvmBaseUrl = 'https://unpkg.com/@seth0x41/doppio@1.0.0/';
+export const doppioJvmBaseUrl = /* @__PURE__ */ getUrl('unpkg:@seth0x41/doppio@1.0.0/');
export const dotUrl = /* @__PURE__ */ getUrl('dot@1.1.3/doT.js');
@@ -127,109 +137,111 @@ export const fflateUrl = /* @__PURE__ */ getUrl('fflate@0.8.1/esm/browser.js');
export const flexSearchUrl = /* @__PURE__ */ getUrl('flexsearch@0.7.21/dist/flexsearch.bundle.js');
-export const fontAnonymousProUrl = /* @__PURE__ */ getUrl(
- '@fontsource/anonymous-pro@4.5.9/index.css',
-);
+export const fontAnonymousProBaseUrl = /* @__PURE__ */ getUrl('@fontsource/anonymous-pro@4.5.9/');
-export const fontAstigmataUrl = /* @__PURE__ */ getUrl(
- 'gh:hatemhosny/astigmata-font@6d0ee00a07fb1932902f0b81a504d075d47bd52f/index.css',
+export const fontAstigmataBaseUrl = /* @__PURE__ */ getUrl(
+ 'gh:hatemhosny/astigmata-font@6d0ee00a07fb1932902f0b81a504d075d47bd52f/',
);
-export const fontAwesomeUrl = /* @__PURE__ */ getUrl('font-awesome@4.7.0/css/font-awesome.min.css');
+export const fontAwesomeBaseUrl = /* @__PURE__ */ getUrl('font-awesome@4.7.0/');
-export const fontCascadiaCodeUrl = /* @__PURE__ */ getUrl(
- '@fontsource/cascadia-code@4.2.1/index.css',
-);
+export const fontCascadiaCodeBaseUrl = /* @__PURE__ */ getUrl('@fontsource/cascadia-code@4.2.1/');
export const fontCodeNewRomanUrl = /* @__PURE__ */ getUrl(
- 'https://fonts.cdnfonts.com/css/code-new-roman-2',
+ 'https://fonts.cdnfonts.com/css/code-new-roman-2?style.css',
);
-export const fontComicMonoUrl = /* @__PURE__ */ getUrl('comic-mono@0.0.1/index.css');
+export const fontComicMonoBaseUrl = /* @__PURE__ */ getUrl('comic-mono@0.0.1/');
-export const fontCourierPrimeUrl = /* @__PURE__ */ getUrl(
- '@fontsource/courier-prime@4.5.9/index.css',
-);
+export const fontCourierPrimeBaseUrl = /* @__PURE__ */ getUrl('@fontsource/courier-prime@4.5.9/');
export const fontDECTerminalModernUrl = /* @__PURE__ */ getUrl(
- 'https://fonts.cdnfonts.com/css/dec-terminal-modern',
+ 'https://fonts.cdnfonts.com/css/dec-terminal-modern?style.css',
);
-export const fontDejaVuMonoUrl = /* @__PURE__ */ getUrl('@fontsource/dejavu-mono@4.5.4/index.css');
+export const fontDejaVuMonoBaseUrl = /* @__PURE__ */ getUrl('@fontsource/dejavu-mono@4.5.4/');
-export const fontFantasqueUrl = /* @__PURE__ */ getUrl(
- '@typopro/web-fantasque-sans-mono@3.7.5/TypoPRO-FantasqueSansMono.css',
+export const fontFantasqueBaseUrl = /* @__PURE__ */ getUrl(
+ '@typopro/web-fantasque-sans-mono@3.7.5/',
);
-export const fontFiraCodeUrl = /* @__PURE__ */ getUrl('firacode@6.2.0/distr/fira_code.css');
+export const fontFiraCodeBaseUrl = /* @__PURE__ */ getUrl('firacode@6.2.0/distr/');
-export const fontFixedsysUrl = /* @__PURE__ */ getUrl('https://fonts.cdnfonts.com/css/fixedsys-62');
+export const fontFixedsysUrl = /* @__PURE__ */ getUrl(
+ 'https://fonts.cdnfonts.com/css/fixedsys-62?style.css',
+);
-export const fontHackUrl = /* @__PURE__ */ getUrl('hack-font@3.3.0/build/web/hack.css');
+export const fontHackBaseUrl = /* @__PURE__ */ getUrl('hack-font@3.3.0/build/web/');
-export const fontHermitUrl = /* @__PURE__ */ getUrl('typeface-hermit@0.0.44/index.css');
+export const fontHermitBaseUrl = /* @__PURE__ */ getUrl('typeface-hermit@0.0.44/');
export const fontIBMPlexMonoUrl = /* @__PURE__ */ getUrl(
- 'https://fonts.googleapis.com/css2?family=IBM+Plex+Mono&display=swap',
+ 'https://fonts.googleapis.com/css2?family=IBM+Plex+Mono&display=swap&style.css',
);
export const fontInconsolataUrl = /* @__PURE__ */ getUrl(
- 'https://fonts.googleapis.com/css2?family=Inconsolata&display=swap',
+ 'https://fonts.googleapis.com/css2?family=Inconsolata&display=swap&style.css',
);
export const fontInterUrl = /* @__PURE__ */ getUrl(
- 'https://fonts.googleapis.com/css?family=Inter:300,400,500',
+ 'https://fonts.googleapis.com/css?family=Inter:300,400,500&style.css',
);
-export const fontIosevkaUrl = /* @__PURE__ */ getUrl('@fontsource/iosevka@4.5.4/index.css');
+export const fontIosevkaBaseUrl = /* @__PURE__ */ getUrl('@fontsource/iosevka@4.5.4/');
-export const fontJetbrainsMonoUrl = /* @__PURE__ */ getUrl(
- '@fontsource/jetbrains-mono@4.5.11/index.css',
+export const fontJetbrainsMonoBaseUrl = /* @__PURE__ */ getUrl(
+ '@fontsource/jetbrains-mono@4.5.11/',
);
export const fontMaterialIconsUrl = /* @__PURE__ */ getUrl(
- 'https://fonts.googleapis.com/css?family=Material+Icons&display=swap',
+ 'https://fonts.googleapis.com/css?family=Material+Icons&display=swap&style.css',
);
-export const fontMenloUrl = /* @__PURE__ */ getUrl('https://fonts.cdnfonts.com/css/menlo');
+export const fontMenloUrl = /* @__PURE__ */ getUrl(
+ 'https://fonts.cdnfonts.com/css/menlo?style.css',
+);
export const fontMonaspaceBaseUrl = /* @__PURE__ */ getUrl('monaspace-font@0.0.2/');
-export const fontMonofurUrl = /* @__PURE__ */ getUrl('https://fonts.cdnfonts.com/css/monofur');
+export const fontMonofurUrl = /* @__PURE__ */ getUrl(
+ 'https://fonts.cdnfonts.com/css/monofur?style.css',
+);
-export const fontMonoidUrl = /* @__PURE__ */ getUrl('@typopro/web-monoid@3.7.5/TypoPRO-Monoid.css');
+export const fontMonoidBaseUrl = /* @__PURE__ */ getUrl('@typopro/web-monoid@3.7.5/');
export const fontNotoUrl = /* @__PURE__ */ getUrl(
- 'https://fonts.googleapis.com/css2?family=Noto+Sans+Mono&display=swap',
+ 'https://fonts.googleapis.com/css2?family=Noto+Sans+Mono&display=swap&style.css',
);
export const fontNovaMonoUrl = /* @__PURE__ */ getUrl(
- 'https://fonts.googleapis.com/css2?family=Nova+Mono&display=swap',
+ 'https://fonts.googleapis.com/css2?family=Nova+Mono&display=swap&style.css',
);
-export const fontOpenDyslexicUrl = /* @__PURE__ */ getUrl(
- '@fontsource/opendyslexic@4.5.4/index.css',
-);
+export const fontOpenDyslexicBaseUrl = /* @__PURE__ */ getUrl('@fontsource/opendyslexic@4.5.4/');
export const fontProFontWindowsUrl = /* @__PURE__ */ getUrl(
- 'https://fonts.cdnfonts.com/css/profontwindows',
+ 'https://fonts.cdnfonts.com/css/profontwindows?style.css',
);
-export const fontRobotoMonoUrl = /* @__PURE__ */ getUrl('@fontsource/roboto-mono@4.5.8/index.css');
+export const fontRobotoMonoBaseUrl = /* @__PURE__ */ getUrl('@fontsource/roboto-mono@4.5.8/');
-export const fontSFMonoUrl = /* @__PURE__ */ getUrl('https://fonts.cdnfonts.com/css/sf-mono');
+export const fontSFMonoUrl = /* @__PURE__ */ getUrl(
+ 'https://fonts.cdnfonts.com/css/sf-mono?style.css',
+);
-export const fontSourceCodeProUrl = /* @__PURE__ */ getUrl(
- '@fontsource/source-code-pro@4.5.12/index.css',
+export const fontSourceCodeProBaseUrl = /* @__PURE__ */ getUrl(
+ '@fontsource/source-code-pro@4.5.12/',
);
-export const fontSpaceMonoUrl = /* @__PURE__ */ getUrl('@fontsource/space-mono@4.5.10/index.css');
+export const fontSpaceMonoBaseUrl = /* @__PURE__ */ getUrl('@fontsource/space-mono@4.5.10/');
-export const fontSudoVarUrl = /* @__PURE__ */ getUrl('https://fonts.cdnfonts.com/css/sudo-var');
+export const fontSudoVarUrl = /* @__PURE__ */ getUrl(
+ 'https://fonts.cdnfonts.com/css/sudo-var?style.css',
+);
-export const fontUbuntuMonoUrl = /* @__PURE__ */ getUrl('@fontsource/ubuntu-mono@4.5.11/index.css');
+export const fontUbuntuMonoBaseUrl = /* @__PURE__ */ getUrl('@fontsource/ubuntu-mono@4.5.11/');
-export const fontVictorMonoUrl = /* @__PURE__ */ getUrl('victormono@1.5.4/dist/index.css');
+export const fontVictorMonoBaseUrl = /* @__PURE__ */ getUrl('victormono@1.5.4/dist/');
export const fscreenUrl = /* @__PURE__ */ getUrl('fscreen@1.2.0/dist/fscreen.esm.js');
@@ -245,9 +257,7 @@ export const graphreCdnUrl = /* @__PURE__ */ getUrl('graphre@0.1.3/dist/graphre.
export const handlebarsBaseUrl = /* @__PURE__ */ getUrl('handlebars@4.7.8/dist/');
-export const highlightjsUrl = /* @__PURE__ */ getModuleUrl('highlight.js@11.11.1');
-
-export const hpccJsCdnUrl = /* @__PURE__ */ getUrl('@hpcc-js/wasm@2.13.0/dist/index.js');
+export const hpccJsCdnBaseUrl = /* @__PURE__ */ getUrl('@hpcc-js/wasm@2.13.0/dist/');
export const htmlToImageUrl = /* @__PURE__ */ getUrl('html-to-image@1.11.11/dist/html-to-image.js');
@@ -283,11 +293,11 @@ export const lunaObjViewerStylesUrl = /* @__PURE__ */ getUrl(
'luna-object-viewer@0.2.4/luna-object-viewer.css',
);
-export const malinaBaseUrl = /* @__PURE__ */ getUrl(`malinajs@0.7.19/`);
+export const malinaBaseUrl = /* @__PURE__ */ getUrl('malinajs@0.7.19/');
export const markedUrl = /* @__PURE__ */ getUrl('marked@13.0.2/marked.min.js');
-export const mermaidCdnUrl = /* @__PURE__ */ getUrl('mermaid@10.2.2/dist/mermaid.esm.mjs');
+export const mermaidCdnUrl = /* @__PURE__ */ getUrl('mermaid@10.2.2/dist/mermaid.min.js');
export const metaPngUrl = /* @__PURE__ */ getUrl('meta-png@1.0.6/dist/meta-png.umd.js');
@@ -301,9 +311,7 @@ export const monacoThemesBaseUrl = /* @__PURE__ */ getUrl('monaco-themes@0.4.4/t
export const monacoVimUrl = /* @__PURE__ */ getUrl('monaco-vim@0.4.1/dist/monaco-vim.js');
-export const monacoVolarUrl = /* @__PURE__ */ getUrl(
- '@live-codes/monaco-volar@0.1.0/dist/index.js',
-);
+export const monacoVolarBaseUrl = /* @__PURE__ */ getUrl('@live-codes/monaco-volar@0.1.0/dist/');
export const mustacheUrl = /* @__PURE__ */ getUrl('mustache@4.2.0/mustache.js');
@@ -315,13 +323,11 @@ export const normalizeCssUrl = /* @__PURE__ */ getUrl('normalize.css@8.0.1/norma
export const nunjucksBaseUrl = /* @__PURE__ */ getUrl('nunjucks@3.2.4/browser/');
-export const opalBaseUrl = /* @__PURE__ */ getUrl('https://cdn.opalrb.com/opal/1.8.2/');
+export const opalBaseUrl = /* @__PURE__ */ getUrl('gh:opal/opal-cdn@v1.8.2/opal/1.8.2/');
export const parinferUrl = /* @__PURE__ */ getUrl('parinfer@3.13.1/parinfer.js');
-export const pathBrowserifyUrl = /* @__PURE__ */ getModuleUrl('path-browserify@1.0.1');
-
-export const pgliteUrl = /* @__PURE__ */ getUrl('@electric-sql/pglite@0.1.5/dist/index.js');
+export const pgliteBaseUrl = /* @__PURE__ */ getUrl('@electric-sql/pglite@0.1.5/dist/');
export const pintoraUrl = /* @__PURE__ */ getUrl(
'@pintora/standalone@0.6.2/lib/pintora-standalone.umd.js',
@@ -352,7 +358,7 @@ export const prismThemesLaserWaveUrl = /* @__PURE__ */ getUrl(
);
export const pyodideBaseUrl = /* @__PURE__ */ getUrl(
- 'https://cdn.jsdelivr.net/pyodide/v0.25.1/full/',
+ 'https://cdn.jsdelivr.net/pyodide/v0.28.0/full/',
);
export const qrcodeUrl = /* @__PURE__ */ getUrl('easyqrcodejs@4.6.1/dist/easy.qrcode.min.js');
@@ -381,7 +387,18 @@ export const reasonReactUrl = /* @__PURE__ */ getUrl(
export const reasonStdLibBaseUrl = /* @__PURE__ */ getUrl('@rescript/std@9.1.3/lib/es6/');
-export const rescriptCdnBaseUrl = /* @__PURE__ */ getUrl('https://cdn.rescript-lang.org/v11.1.2/');
+export const rescriptCdnUrl1 = /* @__PURE__ */ getUrl(
+ 'https://cdn.rescript-lang.org/v11.1.2/compiler.js',
+);
+export const rescriptCdnUrl2 = /* @__PURE__ */ getUrl(
+ 'https://cdn.rescript-lang.org/v11.1.2/compiler-builtins/cmij.js',
+);
+export const rescriptCdnUrl3 = /* @__PURE__ */ getUrl(
+ 'https://cdn.rescript-lang.org/v11.1.2/%40rescript/react/cmij.js',
+);
+export const rescriptCdnUrl4 = /* @__PURE__ */ getUrl(
+ 'https://cdn.rescript-lang.org/v11.1.2/%40rescript/core/cmij.js',
+);
export const rescriptStdLibBaseUrl = /* @__PURE__ */ getUrl('@rescript/std@11.1.2/lib/es6/');
@@ -435,19 +452,19 @@ export const tesseractUrl = /* @__PURE__ */ getUrl('tesseract.js@6.0.1/dist/tess
export const twigUrl = /* @__PURE__ */ getUrl('twig@1.17.1/twig.min.js');
-export const typescriptUrl = /* @__PURE__ */ getUrl(`typescript@5.6.2/lib/typescript.js`);
+export const typescriptUrl = /* @__PURE__ */ getUrl('typescript@5.6.2/lib/typescript.js');
export const typescriptVfsUrl = /* @__PURE__ */ getUrl('@typescript/vfs@1.5.3/dist/vfs.esm.js');
export const uniterUrl = /* @__PURE__ */ getUrl('uniter@2.18.0/dist/uniter.js');
-export const vegaCdnUrl = /* @__PURE__ */ getUrl('vega@5.25.0/build/vega.js');
+export const vegaCdnUrl = /* @__PURE__ */ getUrl('vega@5.25.0/build/vega.min.js');
-export const vegaLiteCdnUrl = /* @__PURE__ */ getUrl('vega-lite@5.9.3/build/vega-lite.js');
+export const vegaLiteCdnUrl = /* @__PURE__ */ getUrl('vega-lite@5.9.3/build/vega-lite.min.js');
-export const vue3CdnUrl = /* @__PURE__ */ getUrl('vue@3');
+export const vue3CdnUrl = /* @__PURE__ */ getUrl('vue@3.5.17/dist/vue.global.prod.js');
-export const vue2CdnUrl = /* @__PURE__ */ getUrl('vue@2');
+export const vue2CdnUrl = /* @__PURE__ */ getUrl('vue@2.7.16/dist/vue.min.js');
export const vueRuntimeUrl = /* @__PURE__ */ getUrl('vue@3/dist/vue.runtime.esm-browser.prod.js');
diff --git a/src/sdk/models.ts b/src/sdk/models.ts
index 50695a9bdd..adebd1a1ae 100644
--- a/src/sdk/models.ts
+++ b/src/sdk/models.ts
@@ -968,6 +968,8 @@ export type Language =
| 'riotjs'
| 'malina'
| 'malinajs'
+ | 'ripple'
+ | 'ripplejs'
| 'xht'
| 'coffeescript'
| 'coffee'
@@ -998,6 +1000,9 @@ export type Language =
| 'rubywasm'
| 'go'
| 'golang'
+ | 'go-wasm'
+ | 'wasm.go'
+ | 'gowasm'
| 'php'
| 'php-wasm'
| 'phpwasm'
@@ -1350,6 +1355,7 @@ export interface Compiler {
| 'text/commonlisp'
| 'text/tcl'
| 'text/prolog'
+ | 'text/go-wasm'
| 'application/json'
| 'application/lua'
| 'text/fennel'
@@ -1418,6 +1424,7 @@ export type TemplateName =
| 'ruby'
| 'ruby-wasm'
| 'go'
+ | 'go-wasm'
| 'php'
| 'php-wasm'
| 'cpp'
diff --git a/src/sdk/vue.ts b/src/sdk/vue.ts
index 312b7f98ce..18f767a3b9 100644
--- a/src/sdk/vue.ts
+++ b/src/sdk/vue.ts
@@ -125,7 +125,7 @@ const LiveCodes: LiveCodesComponent = {
'div',
{
ref: containerRef,
- 'data-height': height,
+ 'data-height': height.value,
},
ctx.slots.default?.() || '',
);
diff --git a/vendor-licenses.md b/vendor-licenses.md
index c3049f5b7c..a22b29a64e 100644
--- a/vendor-licenses.md
+++ b/vendor-licenses.md
@@ -315,3 +315,7 @@ WebR: [License](https://github.com/r-wasm/webr/blob/e47ab9854c9306c410f302579c66
Whirl: [MIT License](https://github.com/jh3y/whirl/tree/8de79b76a13200ccbd8b0b75b4f79978ef1ee890)
Windi CSS: [MIT License](https://github.com/windicss/windicss/blob/bcd50d877e62630f191602ddeabd9f677cc6d90c/LICENSE)
+
+Yaegi: [Apache License 2.0](https://github.com/traefik/yaegi/blob/d93266d013f393a20122ef0dd3f579d411a066be/LICENSE)
+
+yaegi-wasm: [Apache License 2.0](https://github.com/Muhammad-Ayman/yaegi-wasm/blob/528a6bbac7464dc8911e50e0d617512f3e247e8c/LICENSE)