diff --git a/client/src/lit/interactive-example/index.js b/client/src/lit/interactive-example/index.js index 6eb30f44a0e2..8c4b04c4812d 100644 --- a/client/src/lit/interactive-example/index.js +++ b/client/src/lit/interactive-example/index.js @@ -1,5 +1,6 @@ import { html, LitElement } from "lit"; import { ref, createRef } from "lit/directives/ref.js"; +import { ifDefined } from "lit/directives/if-defined.js"; import { decode } from "he"; import "../play/editor.js"; @@ -17,7 +18,7 @@ import styles from "./index.scss?css" with { type: "css" }; * @import { PlayRunner } from "../play/runner.js"; */ -const LANGUAGE_CLASSES = ["html", "js", "css"]; +const LANGUAGE_CLASSES = ["html", "js", "css", "wat"]; const GLEAN_EVENT_TYPES = ["focus", "copy", "cut", "paste", "click"]; export class InteractiveExample extends GleanMixin(LitElement) { @@ -68,8 +69,9 @@ export class InteractiveExample extends GleanMixin(LitElement) { }, /** @type {Object} */ ({})); this._languages = Object.keys(code); this._template = - this._languages.length === 1 && this._languages[0] === "js" - ? "javascript" + (this._languages.length === 1 && this._languages[0] === "js") || + (this._languages.includes("js") && this._languages.includes("wat")) + ? "console" : "tabbed"; return code; } @@ -77,14 +79,10 @@ export class InteractiveExample extends GleanMixin(LitElement) { /** @param {string} lang */ _langName(lang) { switch (lang) { - case "html": - return "HTML"; - case "css": - return "CSS"; case "js": return "JavaScript"; default: - return lang; + return lang.toUpperCase(); } } @@ -110,20 +108,38 @@ export class InteractiveExample extends GleanMixin(LitElement) { this._code = this._initialCode(); } - _renderJavascript() { + _renderConsole() { return html` -
+

${decode(this.name)}

- + ${this._languages.length === 1 + ? html`` + : html` + ${this._languages.map( + (lang) => html` + ${this._langName(lang)} + + + + ` + )} + `}
- +
`; @@ -161,9 +177,14 @@ export class InteractiveExample extends GleanMixin(LitElement) { } render() { - return this._template === "javascript" - ? this._renderJavascript() - : this._renderTabbed(); + switch (this._template) { + case "console": + return this._renderConsole(); + case "tabbed": + return this._renderTabbed(); + default: + return ""; + } } firstUpdated() { diff --git a/client/src/lit/interactive-example/index.scss b/client/src/lit/interactive-example/index.scss index 2c011467ecb7..4649f6dc9f30 100644 --- a/client/src/lit/interactive-example/index.scss +++ b/client/src/lit/interactive-example/index.scss @@ -42,15 +42,15 @@ play-console { grid-area: console; } -tab-wrapper { +ix-tab-wrapper { grid-area: tabs; } // ------------------- -// JavaScript examples +// JavaScript/WAT examples // ------------------- -.template-javascript { +.template-console { align-content: start; display: grid; gap: 0.5rem; @@ -68,14 +68,15 @@ tab-wrapper { play-runner { display: none; - grid-area: runner; } - play-editor { + > play-editor, + ix-tab-wrapper { border: 1px solid var(--border-secondary); border-bottom-left-radius: var(--elem-radius); border-bottom-right-radius: var(--elem-radius); border-top: 0; + grid-area: editor; margin-top: -0.5rem; } diff --git a/client/src/lit/play/editor.js b/client/src/lit/play/editor.js index fc1b3c5f64e4..96ded22fe9f2 100644 --- a/client/src/lit/play/editor.js +++ b/client/src/lit/play/editor.js @@ -11,6 +11,7 @@ import { import { lintKeymap } from "@codemirror/lint"; import { EditorView, minimalSetup } from "codemirror"; import { javascript as langJS } from "@codemirror/lang-javascript"; +import { wast as langWat } from "@codemirror/lang-wast"; import { css as langCSS } from "@codemirror/lang-css"; import { html as langHTML } from "@codemirror/lang-html"; import { oneDark } from "@codemirror/theme-one-dark"; @@ -74,6 +75,8 @@ export class PlayEditor extends LitElement { return [langHTML()]; case "css": return [langCSS()]; + case "wat": + return [langWat()]; default: return []; } diff --git a/client/src/lit/play/runner.js b/client/src/lit/play/runner.js index 97ac7519a876..4d84a475385e 100644 --- a/client/src/lit/play/runner.js +++ b/client/src/lit/play/runner.js @@ -4,7 +4,6 @@ import { PLAYGROUND_BASE_HOST } from "../../env.ts"; import { createComponent } from "@lit/react"; import { Task } from "@lit/task"; import React from "react"; - import styles from "./runner.scss?css" with { type: "css" }; /** @import { VConsole } from "./types" */ @@ -24,7 +23,7 @@ export class PlayRunner extends LitElement { super(); /** @type {Record | undefined} */ this.code = undefined; - /** @type {"ix-tabbed" | undefined} */ + /** @type {"ix-tabbed" | "ix-wat" | undefined} */ this.defaults = undefined; /** @type {string | undefined} */ this.srcPrefix = undefined; @@ -47,6 +46,10 @@ export class PlayRunner extends LitElement { args: () => /** @type {const} */ ([this.code, this.defaults, this.srcPrefix]), task: async ([code, defaults, srcPrefix], { signal }) => { + if (code && code.js && code.wat) { + const watUrl = await compileAndEncodeWatToDataUrl(code.wat); + code.js = code.js.replace("{%wasm-url%}", watUrl); + } const { state } = await compressAndBase64Encode( JSON.stringify({ html: code?.html || "", @@ -99,6 +102,31 @@ export class PlayRunner extends LitElement { } } +/** + * Converts a Uint8Array to a base64 encoded string + * @param {Uint8Array} bytes - The array of bytes to convert + * @returns {string} The base64 encoded string representation of the input bytes + */ +function uInt8ArrayToBase64(bytes) { + const binString = Array.from(bytes, (byte) => + String.fromCodePoint(byte) + ).join(""); + return btoa(binString); +} + +/** + * compiles the wat code to wasm + * @param {string} wat + * @returns {Promise} a data-url with the compiled wasm, base64 encoded + */ +async function compileAndEncodeWatToDataUrl(wat) { + const { default: init, watify } = await import("watify"); + await init(); + const binary = watify(wat); + const b64 = `data:application/wasm;base64,${uInt8ArrayToBase64(binary)}`; + return b64; +} + customElements.define("play-runner", PlayRunner); export const ReactPlayRunner = createComponent({ diff --git a/libs/play/index.js b/libs/play/index.js index 1f5fcf13c07e..f7d1c3e8f799 100644 --- a/libs/play/index.js +++ b/libs/play/index.js @@ -16,7 +16,7 @@ export const ORIGIN_REVIEW = * @property {string} css * @property {string} js * @property {string} [src] - * @property {"ix-tabbed"} [defaults] + * @property {"ix-tabbed" | "ix-wat"} [defaults] */ /** @@ -50,6 +50,7 @@ const PLAYGROUND_UNSAFE_CSP_SCRIPT_SRC_VALUES = [ export const PLAYGROUND_UNSAFE_CSP_VALUE = cspToString({ "default-src": ["'self'", "https:"], + "connect-src": ["'self'", "https:", "data:"], "script-src": PLAYGROUND_UNSAFE_CSP_SCRIPT_SRC_VALUES, "script-src-elem": PLAYGROUND_UNSAFE_CSP_SCRIPT_SRC_VALUES, "style-src": [ @@ -419,7 +420,7 @@ export function renderHtml(state = null) { ${htmlCode} - diff --git a/libs/watify/.gitignore b/libs/watify/.gitignore new file mode 100644 index 000000000000..ea8c4bf7f35f --- /dev/null +++ b/libs/watify/.gitignore @@ -0,0 +1 @@ +/target diff --git a/libs/watify/Cargo.lock b/libs/watify/Cargo.lock new file mode 100644 index 000000000000..b0e4352401b9 --- /dev/null +++ b/libs/watify/Cargo.lock @@ -0,0 +1,173 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bumpalo" +version = "3.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "proc-macro2" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "wasm-encoder" +version = "0.201.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9c7d2731df60006819b013f64ccc2019691deccf6e11a1804bc850cd6748f1a" +dependencies = [ + "leb128", +] + +[[package]] +name = "wast" +version = "201.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ef6e1ef34d7da3e2b374fd2b1a9c0227aff6cad596e1b24df9b58d0f6222faa" +dependencies = [ + "bumpalo", + "leb128", + "memchr", + "unicode-width", + "wasm-encoder", +] + +[[package]] +name = "wat" +version = "1.201.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453d5b37a45b98dee4f4cb68015fc73634d7883bbef1c65e6e9c78d454cf3f32" +dependencies = [ + "wast", +] + +[[package]] +name = "watify" +version = "0.0.1" +dependencies = [ + "wasm-bindgen", + "wat", +] diff --git a/libs/watify/Cargo.toml b/libs/watify/Cargo.toml new file mode 100644 index 000000000000..d147b0730885 --- /dev/null +++ b/libs/watify/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "watify" +version = "0.0.1" +edition = "2021" +resolver = "2" +license = "MIT" + +[lib] +crate-type = ["cdylib"] + +[profile.release] +lto = true +opt-level = 's' + +[dependencies] +wat = "1" +wasm-bindgen = "0.2" diff --git a/libs/watify/LICENSE b/libs/watify/LICENSE new file mode 100644 index 000000000000..0851bea634f8 --- /dev/null +++ b/libs/watify/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Florian Dieminger + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/libs/watify/README.md b/libs/watify/README.md new file mode 100644 index 000000000000..9cbdfd402c1f --- /dev/null +++ b/libs/watify/README.md @@ -0,0 +1,20 @@ +# watify + +Compile WAT to WASM with WASM 🙇 + +--- + +## Running + +```bash +# optional: install wasm-pack if not already installed +cargo install wasm-pack + +# build +wasm-pack build --release --target web + +#serve +python3 -m http.server +``` + +Go to [localhost:8000](http://localhost:8000/) and look at he console output. diff --git a/libs/watify/index.html b/libs/watify/index.html new file mode 100644 index 000000000000..3e1c321df449 --- /dev/null +++ b/libs/watify/index.html @@ -0,0 +1,39 @@ + + + + + hello-wasm example + + + + + + diff --git a/libs/watify/pkg/LICENSE b/libs/watify/pkg/LICENSE new file mode 100644 index 000000000000..0851bea634f8 --- /dev/null +++ b/libs/watify/pkg/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Florian Dieminger + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/libs/watify/pkg/README.md b/libs/watify/pkg/README.md new file mode 100644 index 000000000000..9cbdfd402c1f --- /dev/null +++ b/libs/watify/pkg/README.md @@ -0,0 +1,20 @@ +# watify + +Compile WAT to WASM with WASM 🙇 + +--- + +## Running + +```bash +# optional: install wasm-pack if not already installed +cargo install wasm-pack + +# build +wasm-pack build --release --target web + +#serve +python3 -m http.server +``` + +Go to [localhost:8000](http://localhost:8000/) and look at he console output. diff --git a/libs/watify/pkg/package.json b/libs/watify/pkg/package.json new file mode 100644 index 000000000000..a87cf9dfd69f --- /dev/null +++ b/libs/watify/pkg/package.json @@ -0,0 +1,16 @@ +{ + "name": "watify", + "version": "0.0.1", + "license": "MIT", + "sideEffects": [ + "./snippets/*" + ], + "type": "module", + "main": "watify.js", + "types": "watify.d.ts", + "files": [ + "watify_bg.wasm", + "watify.js", + "watify.d.ts" + ] +} diff --git a/libs/watify/pkg/watify.d.ts b/libs/watify/pkg/watify.d.ts new file mode 100644 index 000000000000..1d064fe06c82 --- /dev/null +++ b/libs/watify/pkg/watify.d.ts @@ -0,0 +1,51 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * @param {string} text + * @returns {Uint8Array} + */ +export function watify(text: string): Uint8Array; + +export type InitInput = + | RequestInfo + | URL + | Response + | BufferSource + | WebAssembly.Module; + +export interface InitOutput { + readonly memory: WebAssembly.Memory; + readonly watify: (a: number, b: number, c: number) => void; + readonly __wbindgen_add_to_stack_pointer: (a: number) => number; + readonly __wbindgen_malloc: (a: number, b: number) => number; + readonly __wbindgen_realloc: ( + a: number, + b: number, + c: number, + d: number + ) => number; + readonly __wbindgen_free: (a: number, b: number, c: number) => void; +} + +export type SyncInitInput = BufferSource | WebAssembly.Module; +/** + * Instantiates the given `module`, which can either be bytes or + * a precompiled `WebAssembly.Module`. + * + * @param {SyncInitInput} module + * + * @returns {InitOutput} + */ +export function initSync(module: SyncInitInput): InitOutput; + +/** + * If `module_or_path` is {RequestInfo} or {URL}, makes a request and + * for everything else, calls `WebAssembly.instantiate` directly. + * + * @param {InitInput | Promise} module_or_path + * + * @returns {Promise} + */ +export default function __wbg_init( + module_or_path?: InitInput | Promise +): Promise; diff --git a/libs/watify/pkg/watify.js b/libs/watify/pkg/watify.js new file mode 100644 index 000000000000..41e3b5c21b4e --- /dev/null +++ b/libs/watify/pkg/watify.js @@ -0,0 +1,260 @@ +let wasm; + +const cachedTextDecoder = + typeof TextDecoder !== "undefined" + ? new TextDecoder("utf-8", { ignoreBOM: true, fatal: true }) + : { + decode: () => { + throw Error("TextDecoder not available"); + }, + }; + +if (typeof TextDecoder !== "undefined") { + cachedTextDecoder.decode(); +} + +let cachedUint8Memory0 = null; + +function getUint8Memory0() { + if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) { + cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer); + } + return cachedUint8Memory0; +} + +function getStringFromWasm0(ptr, len) { + ptr = ptr >>> 0; + return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); +} + +const heap = new Array(128).fill(undefined); + +heap.push(undefined, null, true, false); + +let heap_next = heap.length; + +function addHeapObject(obj) { + if (heap_next === heap.length) heap.push(heap.length + 1); + const idx = heap_next; + heap_next = heap[idx]; + + heap[idx] = obj; + return idx; +} + +let WASM_VECTOR_LEN = 0; + +const cachedTextEncoder = + typeof TextEncoder !== "undefined" + ? new TextEncoder("utf-8") + : { + encode: () => { + throw Error("TextEncoder not available"); + }, + }; + +const encodeString = + typeof cachedTextEncoder.encodeInto === "function" + ? function (arg, view) { + return cachedTextEncoder.encodeInto(arg, view); + } + : function (arg, view) { + const buf = cachedTextEncoder.encode(arg); + view.set(buf); + return { + read: arg.length, + written: buf.length, + }; + }; + +function passStringToWasm0(arg, malloc, realloc) { + if (realloc === undefined) { + const buf = cachedTextEncoder.encode(arg); + const ptr = malloc(buf.length, 1) >>> 0; + getUint8Memory0() + .subarray(ptr, ptr + buf.length) + .set(buf); + WASM_VECTOR_LEN = buf.length; + return ptr; + } + + let len = arg.length; + let ptr = malloc(len, 1) >>> 0; + + const mem = getUint8Memory0(); + + let offset = 0; + + for (; offset < len; offset++) { + const code = arg.charCodeAt(offset); + if (code > 0x7f) break; + mem[ptr + offset] = code; + } + + if (offset !== len) { + if (offset !== 0) { + arg = arg.slice(offset); + } + ptr = realloc(ptr, len, (len = offset + arg.length * 3), 1) >>> 0; + const view = getUint8Memory0().subarray(ptr + offset, ptr + len); + const ret = encodeString(arg, view); + + offset += ret.written; + ptr = realloc(ptr, len, offset, 1) >>> 0; + } + + WASM_VECTOR_LEN = offset; + return ptr; +} + +let cachedInt32Memory0 = null; + +function getInt32Memory0() { + if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) { + cachedInt32Memory0 = new Int32Array(wasm.memory.buffer); + } + return cachedInt32Memory0; +} + +function getObject(idx) { + return heap[idx]; +} + +function dropObject(idx) { + if (idx < 132) return; + heap[idx] = heap_next; + heap_next = idx; +} + +function takeObject(idx) { + const ret = getObject(idx); + dropObject(idx); + return ret; +} + +function getArrayU8FromWasm0(ptr, len) { + ptr = ptr >>> 0; + return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len); +} +/** + * @param {string} text + * @returns {Uint8Array} + */ +export function watify(text) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + text, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc + ); + const len0 = WASM_VECTOR_LEN; + wasm.watify(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r2 = getInt32Memory0()[retptr / 4 + 2]; + var r3 = getInt32Memory0()[retptr / 4 + 3]; + if (r3) { + throw takeObject(r2); + } + var v2 = getArrayU8FromWasm0(r0, r1).slice(); + wasm.__wbindgen_free(r0, r1 * 1, 1); + return v2; + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } +} + +async function __wbg_load(module, imports) { + if (typeof Response === "function" && module instanceof Response) { + if (typeof WebAssembly.instantiateStreaming === "function") { + try { + return await WebAssembly.instantiateStreaming(module, imports); + } catch (e) { + if (module.headers.get("Content-Type") != "application/wasm") { + console.warn( + "`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", + e + ); + } else { + throw e; + } + } + } + + const bytes = await module.arrayBuffer(); + return await WebAssembly.instantiate(bytes, imports); + } else { + const instance = await WebAssembly.instantiate(module, imports); + + if (instance instanceof WebAssembly.Instance) { + return { instance, module }; + } else { + return instance; + } + } +} + +function __wbg_get_imports() { + const imports = {}; + imports.wbg = {}; + imports.wbg.__wbindgen_string_new = function (arg0, arg1) { + const ret = getStringFromWasm0(arg0, arg1); + return addHeapObject(ret); + }; + + return imports; +} + +function __wbg_init_memory(imports, maybe_memory) {} + +function __wbg_finalize_init(instance, module) { + wasm = instance.exports; + __wbg_init.__wbindgen_wasm_module = module; + cachedInt32Memory0 = null; + cachedUint8Memory0 = null; + + return wasm; +} + +function initSync(module) { + if (wasm !== undefined) return wasm; + + const imports = __wbg_get_imports(); + + __wbg_init_memory(imports); + + if (!(module instanceof WebAssembly.Module)) { + module = new WebAssembly.Module(module); + } + + const instance = new WebAssembly.Instance(module, imports); + + return __wbg_finalize_init(instance, module); +} + +async function __wbg_init(input) { + if (wasm !== undefined) return wasm; + + if (typeof input === "undefined") { + input = new URL("watify_bg.wasm", import.meta.url); + } + const imports = __wbg_get_imports(); + + if ( + typeof input === "string" || + (typeof Request === "function" && input instanceof Request) || + (typeof URL === "function" && input instanceof URL) + ) { + input = fetch(input); + } + + __wbg_init_memory(imports); + + const { instance, module } = await __wbg_load(await input, imports); + + return __wbg_finalize_init(instance, module); +} + +export { initSync }; +export default __wbg_init; diff --git a/libs/watify/pkg/watify_bg.js b/libs/watify/pkg/watify_bg.js new file mode 100644 index 000000000000..cff2471bca30 --- /dev/null +++ b/libs/watify/pkg/watify_bg.js @@ -0,0 +1,171 @@ +let wasm; +export function __wbg_set_wasm(val) { + wasm = val; +} + +const lTextDecoder = + typeof TextDecoder === "undefined" + ? (0, module.require)("util").TextDecoder + : TextDecoder; + +let cachedTextDecoder = new lTextDecoder("utf-8", { + ignoreBOM: true, + fatal: true, +}); + +cachedTextDecoder.decode(); + +let cachedUint8Memory0 = null; + +function getUint8Memory0() { + if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) { + cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer); + } + return cachedUint8Memory0; +} + +function getStringFromWasm0(ptr, len) { + ptr = ptr >>> 0; + return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); +} + +const heap = new Array(128).fill(undefined); + +heap.push(undefined, null, true, false); + +let heap_next = heap.length; + +function addHeapObject(obj) { + if (heap_next === heap.length) heap.push(heap.length + 1); + const idx = heap_next; + heap_next = heap[idx]; + + heap[idx] = obj; + return idx; +} + +let WASM_VECTOR_LEN = 0; + +const lTextEncoder = + typeof TextEncoder === "undefined" + ? (0, module.require)("util").TextEncoder + : TextEncoder; + +let cachedTextEncoder = new lTextEncoder("utf-8"); + +const encodeString = + typeof cachedTextEncoder.encodeInto === "function" + ? function (arg, view) { + return cachedTextEncoder.encodeInto(arg, view); + } + : function (arg, view) { + const buf = cachedTextEncoder.encode(arg); + view.set(buf); + return { + read: arg.length, + written: buf.length, + }; + }; + +function passStringToWasm0(arg, malloc, realloc) { + if (realloc === undefined) { + const buf = cachedTextEncoder.encode(arg); + const ptr = malloc(buf.length, 1) >>> 0; + getUint8Memory0() + .subarray(ptr, ptr + buf.length) + .set(buf); + WASM_VECTOR_LEN = buf.length; + return ptr; + } + + let len = arg.length; + let ptr = malloc(len, 1) >>> 0; + + const mem = getUint8Memory0(); + + let offset = 0; + + for (; offset < len; offset++) { + const code = arg.charCodeAt(offset); + if (code > 0x7f) break; + mem[ptr + offset] = code; + } + + if (offset !== len) { + if (offset !== 0) { + arg = arg.slice(offset); + } + ptr = realloc(ptr, len, (len = offset + arg.length * 3), 1) >>> 0; + const view = getUint8Memory0().subarray(ptr + offset, ptr + len); + const ret = encodeString(arg, view); + + offset += ret.written; + ptr = realloc(ptr, len, offset, 1) >>> 0; + } + + WASM_VECTOR_LEN = offset; + return ptr; +} + +let cachedInt32Memory0 = null; + +function getInt32Memory0() { + if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) { + cachedInt32Memory0 = new Int32Array(wasm.memory.buffer); + } + return cachedInt32Memory0; +} + +function getObject(idx) { + return heap[idx]; +} + +function dropObject(idx) { + if (idx < 132) return; + heap[idx] = heap_next; + heap_next = idx; +} + +function takeObject(idx) { + const ret = getObject(idx); + dropObject(idx); + return ret; +} + +function getArrayU8FromWasm0(ptr, len) { + ptr = ptr >>> 0; + return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len); +} +/** + * @param {string} text + * @returns {Uint8Array} + */ +export function watify(text) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0( + text, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc + ); + const len0 = WASM_VECTOR_LEN; + wasm.watify(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r2 = getInt32Memory0()[retptr / 4 + 2]; + var r3 = getInt32Memory0()[retptr / 4 + 3]; + if (r3) { + throw takeObject(r2); + } + var v2 = getArrayU8FromWasm0(r0, r1).slice(); + wasm.__wbindgen_free(r0, r1 * 1, 1); + return v2; + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } +} + +export function __wbindgen_string_new(arg0, arg1) { + const ret = getStringFromWasm0(arg0, arg1); + return addHeapObject(ret); +} diff --git a/libs/watify/pkg/watify_bg.wasm b/libs/watify/pkg/watify_bg.wasm new file mode 100644 index 000000000000..f8d08ec6694f Binary files /dev/null and b/libs/watify/pkg/watify_bg.wasm differ diff --git a/libs/watify/pkg/watify_bg.wasm.d.ts b/libs/watify/pkg/watify_bg.wasm.d.ts new file mode 100644 index 000000000000..284564119f9e --- /dev/null +++ b/libs/watify/pkg/watify_bg.wasm.d.ts @@ -0,0 +1,13 @@ +/* tslint:disable */ +/* eslint-disable */ +export const memory: WebAssembly.Memory; +export function watify(a: number, b: number, c: number): void; +export function __wbindgen_add_to_stack_pointer(a: number): number; +export function __wbindgen_malloc(a: number, b: number): number; +export function __wbindgen_realloc( + a: number, + b: number, + c: number, + d: number +): number; +export function __wbindgen_free(a: number, b: number, c: number): void; diff --git a/libs/watify/src/lib.rs b/libs/watify/src/lib.rs new file mode 100644 index 000000000000..a71c247cebd4 --- /dev/null +++ b/libs/watify/src/lib.rs @@ -0,0 +1,6 @@ +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub fn watify(text: &str) -> Result, JsValue> { + wat::parse_str(text).map_err(|e| e.to_string().into()) +} diff --git a/package.json b/package.json index 6ab4e6e056c7..71f54bcd83f2 100644 --- a/package.json +++ b/package.json @@ -77,6 +77,7 @@ "@codemirror/lang-css": "^6.3.1", "@codemirror/lang-html": "^6.4.9", "@codemirror/lang-javascript": "^6.2.3", + "@codemirror/lang-wast": "^6.0.2", "@codemirror/state": "^6.5.2", "@codemirror/theme-one-dark": "^6.1.2", "@fast-csv/parse": "^5.0.2", @@ -162,6 +163,7 @@ "unified": "^11.0.5", "unist-builder": "^4.0.0", "unist-util-visit": "^5.0.0", + "watify": "file:./libs/watify/pkg", "web-features": "^2.23.0", "web-specs": "^3.41.0" }, diff --git a/yarn.lock b/yarn.lock index e36817117adb..3204ab6bedef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1175,6 +1175,16 @@ "@lezer/common" "^1.0.0" "@lezer/javascript" "^1.0.0" +"@codemirror/lang-wast@^6.0.2": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@codemirror/lang-wast/-/lang-wast-6.0.2.tgz#d2b14175e5e80d7878cbbb29e20ec90dc12d3a2b" + integrity sha512-Imi2KTpVGm7TKuUkqyJ5NRmeFWF7aMpNiwHnLQe0x9kmrxElndyH0K6H/gXtWwY6UshMRAhpENsgfpSwsgmC6Q== + dependencies: + "@codemirror/language" "^6.0.0" + "@lezer/common" "^1.2.0" + "@lezer/highlight" "^1.0.0" + "@lezer/lr" "^1.0.0" + "@codemirror/language@^6.0.0", "@codemirror/language@^6.4.0", "@codemirror/language@^6.6.0": version "6.10.3" resolved "https://registry.yarnpkg.com/@codemirror/language/-/language-6.10.3.tgz#eb25fc5ade19032e7bf1dcaa957804e5f1660585" @@ -15849,6 +15859,9 @@ watchpack@^2.4.1: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" +"watify@file:./libs/watify/pkg": + version "0.0.1" + wbuf@^1.1.0, wbuf@^1.7.3: version "1.7.3" resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df"