├── .gitattributes ├── .github └── PULL_REQUEST_TEMPLATE ├── .gitignore ├── .gitignore.travis ├── .nojekyll ├── .travis.yml ├── .vscode ├── launch.json └── settings.json ├── CNAME ├── LICENSE ├── README.md ├── bin ├── bundle-templates.js └── check-bundle-size.js ├── config.json ├── favicon.ico ├── fonts ├── octicons.css ├── octicons │ ├── OSSREADME.json │ ├── README.md │ ├── octicons-animations.css │ ├── octicons-local.ttf │ ├── octicons.css │ ├── octicons.eot │ ├── octicons.less │ ├── octicons.scss │ ├── octicons.svg │ ├── octicons.ttf │ ├── octicons.woff │ └── sprockets-octicons.scss ├── roboto.css ├── roboto.ttf ├── seti-extra.css ├── seti-extra.woff ├── seti.css ├── seti.woff ├── zilla.css └── zilla.ttf ├── img ├── logo.png ├── wa.png └── web-assembly-icon-white-64px.png ├── index.html ├── jest-puppeteer.config.js ├── jest.e2e.config.json ├── lib ├── binaryen.LICENSE ├── binaryen.js ├── capstone.x86.min.js ├── clang-format.js ├── clang-format.wasm ├── fiddle.d.ts ├── ga.js ├── lib.es6.d.ts ├── require.js ├── showdown.min.js ├── twiggy_wasm_api.js ├── twiggy_wasm_api_bg.wasm ├── vendor_libs.sh ├── viz-lite.js ├── wabt.LICENSE └── wabt.js ├── misc └── arc-templates │ ├── arc_js │ ├── README.md │ ├── build.ts │ ├── package.json │ └── src │ │ └── module.js │ ├── arc_rust │ ├── Cargo.toml │ ├── README.md │ ├── build.ts │ ├── package.json │ └── src │ │ ├── arc_module.rs │ │ ├── color.rs │ │ ├── lib.rs │ │ ├── module.js │ │ └── utils.rs │ ├── arc_rust_font │ ├── Cargo.toml │ ├── README.md │ ├── build.ts │ ├── package.json │ └── src │ │ ├── arc_module.rs │ │ ├── color.rs │ │ ├── lib.rs │ │ ├── module.js │ │ └── utils.rs │ ├── arc_rust_hello_world │ ├── Cargo.toml │ ├── README.md │ ├── build.ts │ ├── package.json │ └── src │ │ ├── arc_module.rs │ │ ├── color.rs │ │ ├── lib.rs │ │ ├── module.js │ │ └── utils.rs │ ├── arc_rust_jsconf_logo │ ├── Cargo.toml │ ├── README.md │ ├── build.ts │ ├── package.json │ └── src │ │ ├── arc_module.rs │ │ ├── color.rs │ │ ├── lib.rs │ │ ├── module.js │ │ └── utils.rs │ ├── arc_rust_random │ ├── Cargo.lock │ ├── Cargo.toml │ ├── README.md │ ├── build.ts │ ├── package.json │ └── src │ │ ├── arc_module.rs │ │ ├── browser.rs │ │ ├── color.rs │ │ ├── lib.rs │ │ ├── module.js │ │ └── utils.rs │ └── arc_wat │ ├── README.md │ ├── build.ts │ ├── package.json │ └── src │ ├── module.js │ └── module.wat ├── notes ├── help.md └── notes.md ├── package-lock.json ├── package.json ├── src ├── @types │ └── tar-js │ │ └── index.d.ts ├── actions │ ├── AppActions.ts │ └── ArcActions.ts ├── arc.ts ├── compilerServices │ ├── clangService.ts │ ├── index.ts │ ├── rustService.ts │ ├── sendRequest.ts │ ├── types.ts │ ├── utils.ts │ └── x86Service.ts ├── components │ ├── App.tsx │ ├── Binary.tsx │ ├── BrowserNotSupported.tsx │ ├── ControlCenter.tsx │ ├── DirectoryTree.tsx │ ├── EditFileDialog.tsx │ ├── ErrorBoundary.tsx │ ├── Header.tsx │ ├── Markdown.tsx │ ├── NewDirectoryDialog.tsx │ ├── NewFileDialog.tsx │ ├── NewProjectDialog.tsx │ ├── Problems.tsx │ ├── Sandbox.tsx │ ├── ShareDialog.tsx │ ├── Split.tsx │ ├── StatusBar.tsx │ ├── Toasts.tsx │ ├── Toolbar.tsx │ ├── UploadFileDialog.tsx │ ├── Viz.tsx │ ├── Widgets.tsx │ ├── Workspace.tsx │ ├── editor │ │ ├── Editor.tsx │ │ ├── Tabs.tsx │ │ ├── View.tsx │ │ ├── ViewTabs.tsx │ │ └── index.ts │ └── shared │ │ ├── Button.tsx │ │ └── Icons.tsx ├── config.ts ├── dispatcher.ts ├── errors.ts ├── gulpy.ts ├── index.tsx ├── languages │ ├── cton.ts │ ├── log.ts │ ├── rust.ts │ ├── wat.ts │ └── x86.ts ├── message.ts ├── models │ ├── Directory.ts │ ├── EventDispatcher.ts │ ├── File.ts │ ├── ModelRef.ts │ ├── Problem.ts │ ├── Project.ts │ ├── index.ts │ └── types.ts ├── monaco-controller.ts ├── monaco-dnd.ts ├── monaco-extra.ts ├── monaco-utils.ts ├── service.ts ├── stores │ └── AppStore.ts ├── util.ts ├── utils │ ├── Logger.ts │ ├── Template.ts │ ├── download.ts │ ├── fetchTemplates.ts │ ├── ga.ts │ ├── group.ts │ ├── registerLanguages.ts │ ├── registerTheme.ts │ ├── rewriteSources.ts │ ├── splitUtils.ts │ ├── taskRunner.ts │ └── zlib.ts └── worker.ts ├── stryker.conf.js ├── style ├── global.css ├── markdown.css ├── ref.css ├── split-pane.css └── theme.css ├── svg ├── close.svg ├── default_file.svg ├── default_folder.svg ├── default_folder_opened.svg ├── error-dark.svg ├── error.svg ├── favicon.psd ├── info-dark.svg ├── info.svg ├── wa-pp-black.svg ├── wa-pp-white.svg ├── wa-pp.svg ├── wa.svg ├── warning-dark.svg ├── warning.svg ├── web-assembly-logo-black.svg ├── web-assembly-logo-white.svg └── web-assembly-logo.svg ├── templates ├── empty_c │ ├── README.md │ ├── build.ts │ ├── package.json │ └── src │ │ ├── main.c │ │ ├── main.html │ │ └── main.js ├── empty_rust │ ├── README.md │ ├── build.ts │ ├── package.json │ └── src │ │ ├── main.html │ │ ├── main.js │ │ └── main.rs ├── empty_ts │ ├── README.md │ ├── assembly │ │ ├── main.ts │ │ └── tsconfig.json │ ├── gulpfile.js │ ├── package.json │ ├── setup.js │ └── src │ │ ├── main.html │ │ └── main.js ├── empty_wat │ ├── README.md │ ├── build.ts │ ├── package.json │ └── src │ │ ├── main.html │ │ ├── main.js │ │ └── main.wat ├── hello_world_c │ ├── README.md │ ├── build.ts │ ├── package.json │ └── src │ │ ├── main.c │ │ ├── main.html │ │ └── main.js └── hello_world_rust │ ├── README.md │ ├── build.ts │ ├── package.json │ └── src │ ├── lib.rs │ ├── main.html │ └── main.js ├── test-preprocessor.js ├── test-setup.js ├── test-shim.js ├── tests ├── actions │ ├── AppActions │ │ └── AppActions.spec.ts │ └── ArcActions │ │ └── ArcActions.spec.ts ├── compilerServices │ ├── clangService.spec.ts │ ├── createCompilerService.spec.ts │ ├── rustService.spec.ts │ ├── sendRequest.spec.ts │ ├── utils.spec.ts │ └── x86Service.spec.ts ├── components │ ├── App │ │ ├── App.spec.tsx │ │ └── __snapshots__ │ │ │ └── App.spec.tsx.snap │ ├── Binary │ │ └── Binary.spec.tsx │ ├── BrowserNotSupported │ │ └── BrowserNotSupported.spec.tsx │ ├── Button │ │ └── Button.spec.tsx │ ├── ControlCenter │ │ └── ControlCenter.spec.tsx │ ├── DirectoryTree │ │ └── DirectoryTree.spec.tsx │ ├── EditFileDialog │ │ └── EditFileDialog.spec.tsx │ ├── Editor │ │ ├── EditorView.spec.tsx │ │ └── Monaco.spec.tsx │ ├── ErrorBoundary │ │ └── ErrorBoundary.spec.tsx │ ├── Header │ │ └── Header.spec.tsx │ ├── Markdown │ │ └── Markdown.spec.tsx │ ├── NewDirectoryDialog │ │ ├── NewDirectoryDialog.spec.tsx │ │ └── __snapshots__ │ │ │ └── NewDirectoryDialog.spec.tsx.snap │ ├── NewFileDialog │ │ ├── NewFileDialog.spec.tsx │ │ └── __snapshots__ │ │ │ └── NewFileDialog.spec.tsx.snap │ ├── NewProjectDialog │ │ ├── NewProjectDialog.spec.tsx │ │ ├── __snapshots__ │ │ │ └── NewProjectDialog.spec.tsx.snap │ │ └── templates.json │ ├── Problems │ │ └── Problems.spec.tsx │ ├── Sandbox │ │ └── Sandbox.spec.tsx │ ├── ShareDialog │ │ ├── ShareDialog.spec.tsx │ │ └── __snapshots__ │ │ │ └── ShareDialog.spec.tsx.snap │ ├── Split │ │ └── Split.spec.tsx │ ├── StatusBar │ │ └── StatusBar.spec.tsx │ ├── Tabs │ │ ├── Tab.spec.tsx │ │ └── Tabs.spec.tsx │ ├── Toast │ │ ├── Toasts.spec.tsx │ │ └── __snapshots__ │ │ │ └── Toasts.spec.tsx.snap │ ├── Toolbar │ │ └── Toolbar.spec.tsx │ ├── UploadFileDialog │ │ └── UploadFileDialog.spec.tsx │ ├── View │ │ └── View.spec.tsx │ ├── ViewTabs │ │ └── ViewTabs.spec.tsx │ ├── Viz │ │ └── Viz.spec.tsx │ ├── Widgets │ │ └── Widgets.spec.tsx │ ├── Workspace │ │ └── Workspace.spec.tsx │ └── icons │ │ └── icons.spec.tsx ├── e2e │ └── EmptyCProject.e2e.ts ├── languages │ ├── cton.spec.ts │ ├── log.spec.ts │ ├── rust.spec.ts │ ├── wat.spec.ts │ └── x86.spec.ts ├── services │ ├── Service.spec.ts │ └── ServiceWorker.spec.ts ├── stores │ └── AppStore │ │ └── AppStore.spec.ts ├── unit │ ├── Controller.spec.ts │ ├── DragAndDrop.spec.ts │ ├── EventDispatcher.spec.ts │ ├── FileType.spec.ts │ ├── Logger.spec.ts │ ├── ModelRef.spec.ts │ ├── Problem.spec.ts │ ├── Project.spec.ts │ ├── Template.spec.ts │ ├── arc.spec.ts │ ├── directory.spec.ts │ ├── file.spec.ts │ ├── gulpy.spec.ts │ ├── index.spec.tsx │ └── splitUtils.spec.ts └── utils │ ├── config.spec.ts │ ├── download.spec.ts │ ├── fetchTemplates.spec.ts │ ├── ga.spec.ts │ ├── group.spec.tsx │ ├── registerLanguages.spec.ts │ ├── registerTheme.spec.ts │ ├── rewriteSources.spec.tsx │ ├── service.spec.tsx │ ├── util.spec.ts │ └── zlib.spec.ts ├── tsconfig.json ├── tsconfig.test.json ├── tslint.json ├── web-assembly-icon-white-64px.png └── webpack.config.js /.gitattributes: -------------------------------------------------------------------------------- 1 | bin/bundle-templates.js text eol=lf 2 | bin/check-bundle-size.js text eol=lf 3 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE: -------------------------------------------------------------------------------- 1 | Associated Issue: # 2 | 3 | Here's the contributing guide at https://github.com/wasdk/WebAssemblyStudio/wiki/Contributing 4 | 5 | ### Summary of Changes 6 | 7 | * change 1 8 | * change 2 9 | 10 | ### Test Plan 11 | 12 | Tell us a little a bit about how you tested your patch. 13 | 14 | Example test plan: 15 | 16 | - [x] Create C "hello, world" project 17 | - [x] Click Build button 18 | - [x] Click Run button, and observe the Result panel 19 | - [x] Clicking the "x" on the Result panel closes it 20 | 21 | ### Screenshots/Videos (OPTIONAL) 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | src/components/Test*.tsx 4 | coverage 5 | mutation 6 | .stryker-tmp 7 | stats 8 | .DS_Store 9 | -------------------------------------------------------------------------------- /.gitignore.travis: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | -------------------------------------------------------------------------------- /.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasdk/WebAssemblyStudio/5eda37b478139dba782974aed2bf8354bc01310a/.nojekyll -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - '8' 5 | # skipping - '6' 6 | branches: 7 | only: 8 | - master 9 | cache: 10 | directories: 11 | - node_modules 12 | notifications: 13 | email: 14 | on_success: never 15 | on_failure: always 16 | before_install: 17 | #- npm update 18 | install: 19 | - npm install 20 | script: 21 | - npm run build 22 | - npm run test:ci 23 | - cp .gitignore.travis .gitignore 24 | deploy: 25 | provider: pages 26 | skip-cleanup: true 27 | github-token: $GITHUB_TOKEN 28 | email: travis@webassembly.studio 29 | name: "WebAssemblyStudio bot" 30 | on: 31 | branch: master 32 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch Program", 11 | "program": "${file}", 12 | "preLaunchTask": "tsc: build - tsconfig.json", 13 | "outFiles": [ 14 | "${workspaceFolder}/dist/**/*.js" 15 | ] 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "Binaryen", 4 | "Repo", 5 | "Resizer", 6 | "Unmount", 7 | "Wabt", 8 | "Wasm", 9 | "canonicalize", 10 | "minimap", 11 | "multiline", 12 | "octicon", 13 | "onready", 14 | "parens", 15 | "posx", 16 | "wasmparser" 17 | ], 18 | "search.exclude": { 19 | "dist/**": true, 20 | "**/node_modules": true, 21 | "**/bower_components": true 22 | }, 23 | "files.exclude": { 24 | "node_modules/**": true, 25 | "**/.git": true, 26 | "**/.svn": true, 27 | "**/.hg": true, 28 | "**/CVS": true, 29 | "**/.DS_Store": true 30 | } 31 | } -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | webassembly.studio 2 | www.webassembly.studio 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2018 Mozilla Foundation 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | WebAssembly Studio 2 | ==== 3 | [![Build Status](https://travis-ci.org/wasdk/WebAssemblyStudio.svg?branch=master)](https://travis-ci.org/wasdk/WebAssemblyStudio) [![Coverage Status](https://coveralls.io/repos/github/wasdk/WebAssemblyStudio/badge.svg)](https://coveralls.io/github/wasdk/WebAssemblyStudio) [![Maintainance Status](https://img.shields.io/badge/maintained-seldom-yellowgreen.svg)](https://github.com/wasdk/WebAssemblyStudio/issues/381) 4 | 5 | This repository contains the (defunct) WebAssembly Studio website source code. 6 | 7 | Running your own local copy of the website 8 | === 9 | 10 | To run a local copy, you will need to install node.js and webpack on your computer, then run the following commands: 11 | 12 | ``` 13 | npm install 14 | ``` 15 | 16 | To build WebAssembly Studio whenever a file changes run: 17 | 18 | ``` 19 | npm run build-watch 20 | ``` 21 | 22 | To start a dev web server run: 23 | 24 | ``` 25 | npm run dev-server 26 | ``` 27 | 28 | Before submitting a pull request run: 29 | 30 | ``` 31 | npm test 32 | ``` 33 | 34 | ### Contributing 35 | 36 | Please get familiar with the [contributing guide](https://github.com/wasdk/WebAssemblyStudio/wiki/Contributing). 37 | 38 | Any doubts or questions? You can always find us on slack at http://wasm-studio.slack.com 39 | 40 | Need a slack invite? https://wasm-studio-invite.herokuapp.com/ 41 | 42 | ### Credits 43 | 44 | This project depends on several excellent libraries and tools: 45 | 46 | * [Monaco Editor](https://github.com/Microsoft/monaco-editor) is used for rich text editing, tree views and context menus. 47 | 48 | * [WebAssembly Binary Toolkit](https://github.com/WebAssembly/wabt) is used to assemble and disassemble `.wasm` files. 49 | 50 | * [Binaryen](https://github.com/WebAssembly/binaryen/) is used to validate and optimize `.wasm` files. 51 | 52 | * [Clang Format](https://github.com/tbfleming/cib) is used to format C/C++ files. 53 | 54 | * [Cassowary.js](https://github.com/slightlyoff/cassowary.js/) is used to make split panes work. 55 | 56 | * [Showdown](https://github.com/showdownjs/showdown) is used to automatically preview `.md` files. 57 | 58 | * [Capstone.js](https://alexaltea.github.io/capstone.js/) is used to disassemble `x86` code. 59 | 60 | * LLVM, Rust, Emscripten running server side. 61 | 62 | * And of course: React, WebPack, TypeScript and TSLint. 63 | -------------------------------------------------------------------------------- /bin/check-bundle-size.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /* 4 | This file was taken from https://github.com/devtools-html/debugger.html/blob/master/bin/ci/check-file-sizes.js 5 | */ 6 | 7 | const path = require("path"); 8 | const fs = require("fs"); 9 | 10 | const fileSizes = { 11 | "main.bundle.js": 300000 12 | }; 13 | 14 | const distPath = "./dist"; 15 | 16 | function checkFileSizes() { 17 | let success = true; 18 | 19 | Object.keys(fileSizes).forEach(key => { 20 | const fullDistPath = path.join(process.cwd(), distPath); 21 | const { size } = fs.statSync(path.join(fullDistPath, key)); 22 | 23 | if (size > fileSizes[key]) { 24 | console.log(`Oh no, ${key} is ${size} bytes, which is greater than ${fileSizes[key]}`); 25 | success = false; 26 | } else { 27 | console.log(`${key} is ${size} bytes, which is not great, but fine...`); 28 | } 29 | }); 30 | 31 | return success; 32 | } 33 | 34 | const success = checkFileSizes(); 35 | process.exit(success ? 0 : 1); 36 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "serviceUrl": "//wasmexplorer-service.herokuapp.com/service.php", 3 | "clang": "//webassembly-studio-clang.herokuapp.com/build", 4 | "rustc": "//webassembly-studio-rust.herokuapp.com/rustc", 5 | "cargo": "//webassembly-studio-rust.herokuapp.com/cargo", 6 | "templates": { 7 | "default": "/dist/templates/index.js", 8 | "arc": "/dist/arc-templates/index.js" 9 | }, 10 | "sentryDNS": "https://756ae32005ed49cf9d4dd2aa106ccd4a@sentry.io/1229949" 11 | } 12 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasdk/WebAssemblyStudio/5eda37b478139dba782974aed2bf8354bc01310a/favicon.ico -------------------------------------------------------------------------------- /fonts/octicons.css: -------------------------------------------------------------------------------- 1 | @import url(octicons/octicons.css); 2 | -------------------------------------------------------------------------------- /fonts/octicons/README.md: -------------------------------------------------------------------------------- 1 | If you intend to install Octicons locally, install `octicons-local.ttf`. It should appear as “github-octicons” in your font list. It is specially designed not to conflict with GitHub's web fonts. 2 | -------------------------------------------------------------------------------- /fonts/octicons/octicons-animations.css: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | @keyframes octicon-spin { 7 | 100% { 8 | transform:rotate(360deg); 9 | } 10 | } 11 | 12 | .octicon-animation-spin { 13 | animation: octicon-spin 2s linear infinite; 14 | } -------------------------------------------------------------------------------- /fonts/octicons/octicons-local.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasdk/WebAssemblyStudio/5eda37b478139dba782974aed2bf8354bc01310a/fonts/octicons/octicons-local.ttf -------------------------------------------------------------------------------- /fonts/octicons/octicons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasdk/WebAssemblyStudio/5eda37b478139dba782974aed2bf8354bc01310a/fonts/octicons/octicons.eot -------------------------------------------------------------------------------- /fonts/octicons/octicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasdk/WebAssemblyStudio/5eda37b478139dba782974aed2bf8354bc01310a/fonts/octicons/octicons.ttf -------------------------------------------------------------------------------- /fonts/octicons/octicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasdk/WebAssemblyStudio/5eda37b478139dba782974aed2bf8354bc01310a/fonts/octicons/octicons.woff -------------------------------------------------------------------------------- /fonts/roboto.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Roboto'; 3 | font-style: normal; 4 | font-weight: 400; 5 | src: local('Roboto'), local('Roboto-Regular'), url(roboto.ttf) format('truetype'); 6 | } 7 | -------------------------------------------------------------------------------- /fonts/roboto.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasdk/WebAssemblyStudio/5eda37b478139dba782974aed2bf8354bc01310a/fonts/roboto.ttf -------------------------------------------------------------------------------- /fonts/seti-extra.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'seti-extra'; 3 | font-style: normal; 4 | font-weight: normal; 5 | src: url(seti-extra.woff) format('woff'); 6 | } 7 | -------------------------------------------------------------------------------- /fonts/seti-extra.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasdk/WebAssemblyStudio/5eda37b478139dba782974aed2bf8354bc01310a/fonts/seti-extra.woff -------------------------------------------------------------------------------- /fonts/seti.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'seti'; 3 | font-style: normal; 4 | font-weight: normal; 5 | src: url(seti.woff) format('woff'); 6 | } 7 | -------------------------------------------------------------------------------- /fonts/seti.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasdk/WebAssemblyStudio/5eda37b478139dba782974aed2bf8354bc01310a/fonts/seti.woff -------------------------------------------------------------------------------- /fonts/zilla.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Zilla Slab'; 3 | font-style: normal; 4 | font-weight: 400; 5 | src: local('Zilla Slab'), local('ZillaSlab-Regular'), url(zilla.ttf) format('truetype'); 6 | } 7 | -------------------------------------------------------------------------------- /fonts/zilla.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasdk/WebAssemblyStudio/5eda37b478139dba782974aed2bf8354bc01310a/fonts/zilla.ttf -------------------------------------------------------------------------------- /img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasdk/WebAssemblyStudio/5eda37b478139dba782974aed2bf8354bc01310a/img/logo.png -------------------------------------------------------------------------------- /img/wa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasdk/WebAssemblyStudio/5eda37b478139dba782974aed2bf8354bc01310a/img/wa.png -------------------------------------------------------------------------------- /img/web-assembly-icon-white-64px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasdk/WebAssemblyStudio/5eda37b478139dba782974aed2bf8354bc01310a/img/web-assembly-icon-white-64px.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 23 | 24 | 25 | 26 | 27 | WebAssembly Studio 28 | 29 | 30 | 31 | 32 |
33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /jest-puppeteer.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | server: { 3 | command: 'npm run dev-server', 4 | launchTimeout: 60000, 5 | usedPortAction: 'ignore', 6 | port: 28443 7 | }, 8 | launch: { 9 | ignoreHTTPSErrors: true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /jest.e2e.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "setupFiles": [ 3 | "/test-shim.js", 4 | "/test-setup.js" 5 | ], 6 | "moduleFileExtensions": [ 7 | "ts", 8 | "tsx", 9 | "js" 10 | ], 11 | "transform": { 12 | "^.+\\.(ts|tsx)$": "/test-preprocessor.js" 13 | }, 14 | "testMatch": [ 15 | "**/tests/**/**/**.e2e.(ts|tsx|js)" 16 | ], 17 | "testURL": "https://webassembly.studio/", 18 | "preset": "jest-puppeteer" 19 | } 20 | -------------------------------------------------------------------------------- /lib/clang-format.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasdk/WebAssemblyStudio/5eda37b478139dba782974aed2bf8354bc01310a/lib/clang-format.wasm -------------------------------------------------------------------------------- /lib/fiddle.d.ts: -------------------------------------------------------------------------------- 1 | // Public API 2 | 3 | type PromiseMaker = () => Promise; 4 | 5 | declare class Gulpy { 6 | task(name: string, fn: PromiseMaker): void; 7 | task(name: string, dependencies: string[], fn: PromiseMaker): void; 8 | task(name: string, a: string [] | PromiseMaker, b?: PromiseMaker): void; 9 | } 10 | 11 | /** 12 | * Task Manager 13 | */ 14 | declare const gulp: Gulpy; 15 | 16 | declare enum Language { 17 | C = "c", 18 | Cpp = "cpp", 19 | Wat = "wat", 20 | Wasm = "wasm", 21 | Rust = "rust", 22 | Cretonne = "cton", 23 | x86 = "x86", 24 | Json = "json", 25 | JavaScript = "javascript", 26 | TypeScript = "typescript", 27 | Text = "text" 28 | } 29 | 30 | declare class Service { 31 | static compileFile(file: File, from: Language | string, to: Language | string, options?: string): Promise; 32 | /** 33 | * Disassembles WebAssembly binary into Wat format using Wabt. 34 | */ 35 | static disassembleWasm(buffer: ArrayBuffer): Promise; 36 | static assembleWat(wat: string): Promise; 37 | } 38 | declare const project: any; 39 | 40 | declare function logLn(message: string, kind?: "" | "info" | "warn" | "error"): void; 41 | 42 | /** Asynchronously requires the specified dependencies.. */ 43 | declare function require(deps: string[], fn: (...deps: any[]) => void): void; 44 | 45 | /** Synchronously requires the specified (already loaded) dependency. */ 46 | declare function require(name: string): any; 47 | 48 | declare namespace require { 49 | /** Configures external module paths etc. */ 50 | export function config(options: {}): void; 51 | } 52 | -------------------------------------------------------------------------------- /lib/ga.js: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | if (navigator.doNotTrack != "1" && window.location.origin.indexOf("webassembly.studio") >= 0) (function() { 22 | var script = document.createElement("script"); 23 | document.head.appendChild(script); 24 | script.onload = function() { 25 | window.dataLayer = window.dataLayer || []; 26 | function gtag(){dataLayer.push(arguments);} 27 | window.gtag = gtag; 28 | gtag('js', new Date()); 29 | gtag('config', 'UA-93230088-3'); 30 | }; 31 | script.src = "https://www.googletagmanager.com/gtag/js?id=UA-93230088-3"; 32 | })(); 33 | -------------------------------------------------------------------------------- /lib/twiggy_wasm_api_bg.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasdk/WebAssemblyStudio/5eda37b478139dba782974aed2bf8354bc01310a/lib/twiggy_wasm_api_bg.wasm -------------------------------------------------------------------------------- /lib/vendor_libs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # binaryen - https://github.com/WebAssembly/binaryen 4 | curl https://raw.githubusercontent.com/WebAssembly/binaryen/master/LICENSE > binaryen.LICENSE 5 | curl https://raw.githubusercontent.com/AssemblyScript/binaryen.js/v48.0.0-nightly.20180624/index.js > ./binaryen.js 6 | 7 | # wabt - https://github.com/WebAssembly/wabt/ 8 | curl https://raw.githubusercontent.com/WebAssembly/wabt/master/LICENSE > wabt.LICENSE 9 | curl https://raw.githubusercontent.com/AssemblyScript/wabt.js/v1.0.0-nightly.20180421/index.js > ./wabt.js 10 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_js/README.md: -------------------------------------------------------------------------------- 1 | # Arc project: JavaScript 2 | 3 | See `src/module.js` for source code for the module. 4 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_js/build.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from "gulp"; 2 | import { Service, Arc, project, logLn } from "@wasm/studio-utils"; 3 | 4 | gulp.task("build", async () => {}); 5 | 6 | gulp.task("publish", async () => { 7 | const rows = 44, cols = 36, frameCount = 1050, fps = 35; 8 | const { transform } = await (await Service.import('src/module.js')).default(); 9 | const buffer = new ArrayBuffer(cols * rows * frameCount * 3); 10 | transform(buffer, rows, cols, frameCount, fps, true); 11 | 12 | const jsModule = project.getFile("src/module.js").getData(); 13 | Arc.publish({ 14 | description: "ES Module Example", 15 | author: "", 16 | animation: { 17 | rows, 18 | cols, 19 | frameCount, 20 | fps, 21 | data: buffer, 22 | }, 23 | entry: "src/module.js", 24 | files: { 25 | "src/module.js": jsModule, 26 | } 27 | }); 28 | logLn("ES Module was published.") 29 | }); 30 | 31 | gulp.task("default", ["build"], async () => {}); 32 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasm/arc_js", 3 | "description": "", 4 | "version": "1.0.0", 5 | "scripts": { 6 | "build": "gulp --gulpfile ./build.ts" 7 | }, 8 | "devDependencies": { 9 | }, 10 | "wasmStudio": { 11 | "name": "ARCH JavaScript Project", 12 | "description": "# ARCH JavaScript Project\n\nThis project comes with a small example to get started scripting the ARCH with JavaScript quickly.", 13 | "icon": "js-lang-file-icon" 14 | } 15 | } -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arc_project" 3 | version = "0.1.0" 4 | authors = ["You! "] 5 | 6 | [dependencies] 7 | # Dependencies are currently deactivated 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust/README.md: -------------------------------------------------------------------------------- 1 | # Arc project: Rust 2 | 3 | Welcome to the Rust Arc project template! 4 | 5 | 6 | **To create your animation, you'll edit the `apply()` function in the `lib.rs` file.** 7 | 8 | There are several other files in the project that have some boilerplate and helper 9 | `Structs` and `functions` to make it easier for you to get up and running: 10 | 11 | - `ArcModule` is a struct (sorta like a JS Object!) that represents your module: 12 | - `rows`: the number of rows, 44 13 | - `cols`: the number of columns, 36 14 | - `animation`: a `Vector` (sorta like a JS Array) of `Rgb` structs (frame of color!) 15 | 16 | - `Color` is a struct that represents a frame of color 17 | - `r`: Red (0..255) 18 | - `g`: Green (0..255) 19 | - `b`: Blue (0..255) 20 | 21 | Rust is a compiled language- so to work with it- you'll need to have the code compile 22 | (this is how it becomes WebAssembly!) To compile your code you can click `Build` - which 23 | runs `cargo build --target wasm32-unknown-unknown`. The Rust compiler helps ensure your 24 | code will run correctly- and catch bugs for you before it runs! You'll need to make the 25 | code compile before it will run! You can look for compiler errors in the interface- 26 | be sure to read the error messages as they are very helpful and often have suggestions 27 | on how to fix your code to make it work! 28 | 29 | If you need help, you can join the Mozilla IRC #rust-wasm channel and ask questions! 30 | 31 | Here's an easy link for joining IRC: https://kiwiirc.com/client/irc.mozilla.org:+6667/#rust-wasm 32 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust/build.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from "gulp"; 2 | import { Service, Arc, project, logLn } from "@wasm/studio-utils"; 3 | 4 | gulp.task("build", async () => { 5 | const options = { debug: true, cargo: true }; 6 | const data = await Service.compileFiles([ 7 | project.getFile("src/lib.rs"), 8 | project.getFile("src/arc_module.rs"), 9 | project.getFile("src/color.rs"), 10 | project.getFile("src/utils.rs"), 11 | project.getFile("Cargo.toml") 12 | ], "rust", "wasm", options); 13 | const outWasm = project.newFile("out/lib.wasm", "wasm", true); 14 | outWasm.setData(data["a.wasm"]); 15 | }); 16 | 17 | gulp.task("publish", async () => { 18 | const rows = 44, cols = 36, frameCount = 1050, fps = 35; 19 | const { transform } = await (await Service.import('src/module.js')).default(); 20 | const buffer = new ArrayBuffer(cols * rows * frameCount * 3); 21 | transform(buffer, rows, cols, frameCount, fps, true); 22 | 23 | const jsModule = project.getFile("src/module.js").getData(); 24 | const rsSource = project.getFile("src/lib.rs").getData(); 25 | const wasmModule = project.getFile("out/lib.wasm").getData(); 26 | Arc.publish({ 27 | description: "WASM Module Example", 28 | author: "", 29 | animation: { 30 | rows, 31 | cols, 32 | frameCount, 33 | fps, 34 | data: buffer, 35 | }, 36 | entry: "src/module.js", 37 | files: { 38 | "src/module.js": jsModule, 39 | "src/lib.rs": rsSource, 40 | "out/lib.wasm": wasmModule, 41 | } 42 | }); 43 | logLn("Rust Module was published.") 44 | }); 45 | 46 | gulp.task("default", ["build"], async () => {}); 47 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasm/arc_rust", 3 | "description": "", 4 | "version": "1.0.0", 5 | "scripts": { 6 | "build": "gulp --gulpfile ./build.ts" 7 | }, 8 | "devDependencies": { 9 | }, 10 | "wasmStudio": { 11 | "name": "ARCH Rust Project", 12 | "description": "# ARCH Rust Project\n\nThis project comes with a small example to get started with the ARCH immediately.", 13 | "icon": "rust-lang-file-icon" 14 | } 15 | } -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust/src/arc_module.rs: -------------------------------------------------------------------------------- 1 | use color::Rgb; 2 | use module_instance; 3 | 4 | pub struct ArcModule { 5 | pub rows: usize, 6 | pub cols: usize, 7 | frame_count: usize, 8 | fps: usize, 9 | is_first: bool, 10 | animation: Vec, 11 | } 12 | 13 | impl ArcModule { 14 | pub fn create_instance( 15 | rows: usize, 16 | cols: usize, 17 | frame_count: usize, 18 | fps: usize, 19 | is_first: bool, 20 | ) -> &'static ArcModule { 21 | let buffer_size = rows * cols * frame_count; 22 | let mut module = ArcModule { 23 | rows, 24 | cols, 25 | frame_count, 26 | fps, 27 | is_first, 28 | animation: Vec::with_capacity(buffer_size), 29 | }; 30 | module.animation.resize(buffer_size, Rgb::new(0, 0, 0)); 31 | module.animation[0] = Rgb { r: 2, g: 4, b: 10 }; 32 | unsafe { module_instance = Box::into_raw(Box::new(module)) }; 33 | ArcModule::get_instance() 34 | } 35 | 36 | pub fn get_instance<'a>() -> &'a mut ArcModule { 37 | unsafe { &mut *module_instance } 38 | } 39 | 40 | pub fn get_animation<'a>(&'a mut self) -> &'a mut Vec { 41 | &mut self.animation 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust/src/color.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | #[derive(Copy)] 3 | pub struct Rgb { 4 | pub r: u8, 5 | pub g: u8, 6 | pub b: u8, 7 | } 8 | 9 | impl Rgb { 10 | pub fn new(r: u8, g: u8, b: u8) -> Rgb { 11 | Rgb { r, g, b } 12 | } 13 | } 14 | 15 | impl Clone for Rgb { 16 | fn clone(&self) -> Rgb { 17 | *self 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust/src/lib.rs: -------------------------------------------------------------------------------- 1 | static mut module_instance: *mut ArcModule = 0 as *mut ArcModule; 2 | 3 | // `mod` is how Rust pulls in code from other files. 4 | // They contain some boilerplate and helper code to 5 | // make it a bit easier for you to get up and running. 6 | // You can take a look at them (they're in the sidebar)! 7 | mod arc_module; 8 | mod color; 9 | mod utils; 10 | 11 | use arc_module::ArcModule; 12 | use color::Rgb; 13 | 14 | pub use utils::getAnimationBuffer; 15 | pub use utils::init; 16 | 17 | 18 | // We'll modify this apply function to create our animation. 19 | 20 | #[no_mangle] 21 | pub extern "C" fn apply() { 22 | 23 | // To create our animation we'll first create a module. We'll 24 | // mutate this to create our animation. 25 | let mut module = ArcModule::get_instance(); 26 | 27 | // There are 44 rows 28 | let rows = module.rows; 29 | 30 | // There are 36 columns 31 | let cols = module.cols; 32 | 33 | // This is our animation. 34 | let animation = module.get_animation().as_mut_slice(); 35 | for (index, frame) in animation.chunks_mut(rows * cols).enumerate() { 36 | for row in 0..rows { 37 | for col in 0..cols { 38 | frame[row * cols + col] = Rgb::new( 39 | row as u8 * 5, 40 | col as u8 * 5, 41 | ((index * 5) % 0xffusize) as u8, 42 | ); 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust/src/module.js: -------------------------------------------------------------------------------- 1 | class ArcModule { 2 | constructor(wasm) { 3 | this.initialized = false; 4 | 5 | if (typeof wasm === 'string') { 6 | if (!WebAssembly.instantiateStreaming) { 7 | this.wasmPromise = fetchAndInstantiateFallback(wasm); 8 | } else { 9 | this.wasmPromise = WebAssembly.instantiateStreaming(fetch(wasm)); 10 | } 11 | } else { 12 | this.wasmPromise = WebAssembly.instantiate(wasm); 13 | } 14 | 15 | this.wasmPromise = this.wasmPromise.then(result => { 16 | this.wasmInstance = result.instance; 17 | this.wasmExports = result.instance.exports; 18 | }); 19 | } 20 | 21 | get ready() { 22 | return this.wasmPromise; 23 | } 24 | 25 | init(rows, cols, frameCount, fps, isFirst) { 26 | if (!this.wasmInstance) { 27 | throw new Error("Wasm module not loaded"); 28 | } 29 | 30 | try { 31 | this.bufferSize = rows * cols * frameCount * 3; 32 | this.wasmExports.init(rows, cols, frameCount, fps, isFirst); 33 | this.initialized = true; 34 | } catch (e) { 35 | console.log(e.stack); 36 | } 37 | } 38 | 39 | transform(input) { 40 | if (!this.initialized) { 41 | throw new Error("Wasm module not initialized"); 42 | } 43 | 44 | let bufferOffset = this.wasmExports.getAnimationBuffer(); 45 | let animationBuffer = new Uint8Array(this.wasmExports.memory.buffer, bufferOffset, this.bufferSize); 46 | 47 | animationBuffer.set(input); 48 | this.wasmExports.apply(); 49 | return animationBuffer; 50 | } 51 | } 52 | 53 | async function fetchAndInstantiateFallback(url, imports) { 54 | const response = await fetch(url); 55 | const buffer = await response.arrayBuffer(); 56 | return WebAssembly.instantiate(buffer, imports); 57 | } 58 | 59 | export default async function () { 60 | let module = new ArcModule("../out/lib.wasm"); 61 | await module.ready; 62 | 63 | return { 64 | transform(buffer, rows, cols, frameCount, fps, isFirst) { 65 | module.init(rows, cols, frameCount, fps, isFirst); 66 | let input = new Uint8Array(buffer); 67 | let output = module.transform(input); 68 | input.set(output); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust/src/utils.rs: -------------------------------------------------------------------------------- 1 | use arc_module::ArcModule; 2 | use color::Rgb; 3 | 4 | #[no_mangle] 5 | pub extern "C" fn init(rows: usize, cols: usize, frame_count: usize, fps: usize, is_first: bool) { 6 | ArcModule::create_instance(rows, cols, frame_count, fps, is_first); 7 | } 8 | 9 | #[no_mangle] 10 | pub extern "C" fn getAnimationBuffer() -> *const Rgb { 11 | ArcModule::get_instance().get_animation().as_ptr() 12 | } 13 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_font/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arc_project" 3 | version = "0.1.0" 4 | authors = ["You! "] 5 | 6 | [dependencies] 7 | # Dependencies are currently deactivated 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_font/README.md: -------------------------------------------------------------------------------- 1 | # Arc project: Rust 2 | 3 | Welcome to the Rust Arc project template! 4 | 5 | 6 | **To create your animation, you'll edit the `apply()` function in the `lib.rs` file.** 7 | 8 | There are several other files in the project that have some boilerplate and helper 9 | `Structs` and `functions` to make it easier for you to get up and running: 10 | 11 | - `ArcModule` is a struct (sorta like a JS Object!) that represents your module: 12 | - `rows`: the number of rows, 44 13 | - `cols`: the number of columns, 36 14 | - `animation`: a `Vector` (sorta like a JS Array) of `Rgb` structs (frame of color!) 15 | 16 | - `Color` is a struct that represents a frame of color 17 | - `r`: Red (0..255) 18 | - `g`: Green (0..255) 19 | - `b`: Blue (0..255) 20 | 21 | Rust is a compiled language- so to work with it- you'll need to have the code compile 22 | (this is how it becomes WebAssembly!) To compile your code you can click `Build` - which 23 | runs `cargo build --target wasm32-unknown-unknown`. The Rust compiler helps ensure your 24 | code will run correctly- and catch bugs for you before it runs! You'll need to make the 25 | code compile before it will run! You can look for compiler errors in the interface- 26 | be sure to read the error messages as they are very helpful and often have suggestions 27 | on how to fix your code to make it work! 28 | 29 | If you need help, you can join the Mozilla IRC #rust-wasm channel and ask questions! 30 | 31 | Here's an easy link for joining IRC: https://kiwiirc.com/client/irc.mozilla.org:+6667/#rust-wasm 32 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_font/build.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from "gulp"; 2 | import { Service, Arc, project, logLn } from "@wasm/studio-utils"; 3 | 4 | gulp.task("build", async () => { 5 | const options = { debug: true, cargo: true }; 6 | const data = await Service.compileFiles([ 7 | project.getFile("src/lib.rs"), 8 | project.getFile("src/arc_module.rs"), 9 | project.getFile("src/color.rs"), 10 | project.getFile("src/utils.rs"), 11 | project.getFile("Cargo.toml") 12 | ], "rust", "wasm", options); 13 | const outWasm = project.newFile("out/lib.wasm", "wasm", true); 14 | outWasm.setData(data["a.wasm"]); 15 | }); 16 | 17 | gulp.task("publish", async () => { 18 | const rows = 44, cols = 36, frameCount = 1050, fps = 35; 19 | const { transform } = await (await Service.import('src/module.js')).default(); 20 | const buffer = new ArrayBuffer(cols * rows * frameCount * 3); 21 | transform(buffer, rows, cols, frameCount, fps, true); 22 | 23 | const jsModule = project.getFile("src/module.js").getData(); 24 | const rsSource = project.getFile("src/lib.rs").getData(); 25 | const wasmModule = project.getFile("out/lib.wasm").getData(); 26 | Arc.publish({ 27 | description: "WASM Module Example", 28 | author: "", 29 | animation: { 30 | rows, 31 | cols, 32 | frameCount, 33 | fps, 34 | data: buffer, 35 | }, 36 | entry: "src/module.js", 37 | files: { 38 | "src/module.js": jsModule, 39 | "src/lib.rs": rsSource, 40 | "out/lib.wasm": wasmModule, 41 | } 42 | }); 43 | logLn("Rust Module was published.") 44 | }); 45 | 46 | gulp.task("default", ["build"], async () => {}); 47 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_font/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasm/arc_rust", 3 | "description": "", 4 | "version": "1.0.0", 5 | "scripts": { 6 | "build": "gulp --gulpfile ./build.ts" 7 | }, 8 | "devDependencies": { 9 | }, 10 | "wasmStudio": { 11 | "name": "ARCH: Bitmap Font in Rust", 12 | "description": "# Bitmap Font rendering\n\nA small example, sliding a bitmap font over the screen.", 13 | "icon": "rust-lang-file-icon" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_font/src/arc_module.rs: -------------------------------------------------------------------------------- 1 | use color::Rgb; 2 | use module_instance; 3 | 4 | pub struct ArcModule { 5 | pub rows: usize, 6 | pub cols: usize, 7 | frame_count: usize, 8 | fps: usize, 9 | is_first: bool, 10 | animation: Vec, 11 | } 12 | 13 | impl ArcModule { 14 | pub fn create_instance( 15 | rows: usize, 16 | cols: usize, 17 | frame_count: usize, 18 | fps: usize, 19 | is_first: bool, 20 | ) -> &'static ArcModule { 21 | let buffer_size = rows * cols * frame_count; 22 | let mut module = ArcModule { 23 | rows, 24 | cols, 25 | frame_count, 26 | fps, 27 | is_first, 28 | animation: Vec::with_capacity(buffer_size), 29 | }; 30 | module.animation.resize(buffer_size, Rgb::new(0, 0, 0)); 31 | module.animation[0] = Rgb { r: 2, g: 4, b: 10 }; 32 | unsafe { module_instance = Box::into_raw(Box::new(module)) }; 33 | ArcModule::get_instance() 34 | } 35 | 36 | pub fn get_instance<'a>() -> &'a mut ArcModule { 37 | unsafe { &mut *module_instance } 38 | } 39 | 40 | pub fn get_animation<'a>(&'a mut self) -> &'a mut Vec { 41 | &mut self.animation 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_font/src/color.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | #[derive(Copy)] 3 | pub struct Rgb { 4 | pub r: u8, 5 | pub g: u8, 6 | pub b: u8, 7 | } 8 | 9 | impl Rgb { 10 | pub fn new(r: u8, g: u8, b: u8) -> Rgb { 11 | Rgb { r, g, b } 12 | } 13 | } 14 | 15 | impl Clone for Rgb { 16 | fn clone(&self) -> Rgb { 17 | *self 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_font/src/module.js: -------------------------------------------------------------------------------- 1 | class ArcModule { 2 | constructor(wasm) { 3 | this.initialized = false; 4 | 5 | if (typeof wasm === 'string') { 6 | if (!WebAssembly.instantiateStreaming) { 7 | this.wasmPromise = fetchAndInstantiateFallback(wasm); 8 | } else { 9 | this.wasmPromise = WebAssembly.instantiateStreaming(fetch(wasm)); 10 | } 11 | } else { 12 | this.wasmPromise = WebAssembly.instantiate(wasm); 13 | } 14 | 15 | this.wasmPromise = this.wasmPromise.then(result => { 16 | this.wasmInstance = result.instance; 17 | this.wasmExports = result.instance.exports; 18 | }); 19 | } 20 | 21 | get ready() { 22 | return this.wasmPromise; 23 | } 24 | 25 | init(rows, cols, frameCount, fps, isFirst) { 26 | if (!this.wasmInstance) { 27 | throw new Error("Wasm module not loaded"); 28 | } 29 | 30 | try { 31 | this.bufferSize = rows * cols * frameCount * 3; 32 | this.wasmExports.init(rows, cols, frameCount, fps, isFirst); 33 | this.initialized = true; 34 | } catch (e) { 35 | console.log(e.stack); 36 | } 37 | } 38 | 39 | transform(input) { 40 | if (!this.initialized) { 41 | throw new Error("Wasm module not initialized"); 42 | } 43 | 44 | let bufferOffset = this.wasmExports.getAnimationBuffer(); 45 | let animationBuffer = new Uint8Array(this.wasmExports.memory.buffer, bufferOffset, this.bufferSize); 46 | 47 | animationBuffer.set(input); 48 | this.wasmExports.apply(); 49 | return animationBuffer; 50 | } 51 | } 52 | 53 | async function fetchAndInstantiateFallback(url, imports) { 54 | const response = await fetch(url); 55 | const buffer = await response.arrayBuffer(); 56 | return WebAssembly.instantiate(buffer, imports); 57 | } 58 | 59 | export default async function () { 60 | let module = new ArcModule("../out/lib.wasm"); 61 | await module.ready; 62 | 63 | return { 64 | transform(buffer, rows, cols, frameCount, fps, isFirst) { 65 | module.init(rows, cols, frameCount, fps, isFirst); 66 | let input = new Uint8Array(buffer); 67 | let output = module.transform(input); 68 | input.set(output); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_font/src/utils.rs: -------------------------------------------------------------------------------- 1 | use arc_module::ArcModule; 2 | use color::Rgb; 3 | 4 | #[no_mangle] 5 | pub extern "C" fn init(rows: usize, cols: usize, frame_count: usize, fps: usize, is_first: bool) { 6 | ArcModule::create_instance(rows, cols, frame_count, fps, is_first); 7 | } 8 | 9 | #[no_mangle] 10 | pub extern "C" fn getAnimationBuffer() -> *const Rgb { 11 | ArcModule::get_instance().get_animation().as_ptr() 12 | } 13 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_hello_world/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arc_project" 3 | version = "0.1.0" 4 | authors = ["You! "] 5 | 6 | [dependencies] 7 | # Dependencies are currently deactivated 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_hello_world/README.md: -------------------------------------------------------------------------------- 1 | # ARCH project: Rust Hello World 2 | 3 | This template renders a Hello World on the Arch! 4 | 5 | The text is encoded as a list of 64 base-2 literals in `src/lib.rs`. You can change the text by 6 | changing which bits are set or unset. 7 | 8 | **For further changes to the rendering, the `Glow.fill_frame` and `apply` functions in `src/lib.rs` are good starting points.** 9 | 10 | ## Further information about the file structure 11 | 12 | There are several other files in the project that have some boilerplate and helper 13 | `Structs` and `functions` to make it easier for you to get up and running: 14 | 15 | - `ArcModule` is a struct (sorta like a JS Object!) that represents your module: 16 | - `rows`: the number of rows, 44 17 | - `cols`: the number of columns, 36 18 | - `animation`: a `Vector` (sorta like a JS Array) of `Rgb` structs (frame of color!) 19 | 20 | - `Color` is a struct that represents a frame of color 21 | - `r`: Red (0..255) 22 | - `g`: Green (0..255) 23 | - `b`: Blue (0..255) 24 | 25 | ## Background on Rust 26 | 27 | Rust is a compiled language- so to work with it- you'll need to have the code compile 28 | (this is how it becomes WebAssembly!) To compile your code you can click `Build` - which 29 | runs `cargo build --target wasm32-unknown-unknown`. The Rust compiler helps ensure your 30 | code will run correctly- and catch bugs for you before it runs! You'll need to make the 31 | code compile before it will run! You can look for compiler errors in the interface- 32 | be sure to read the error messages as they are very helpful and often have suggestions 33 | on how to fix your code to make it work! 34 | 35 | ## How to get more help 36 | 37 | If you need help, you can join the Mozilla IRC #rust-wasm channel and ask questions! 38 | 39 | Here's an easy link for joining IRC: https://kiwiirc.com/client/irc.mozilla.org:+6667/#rust-wasm 40 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_hello_world/build.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from "gulp"; 2 | import { Service, Arc, project, logLn } from "@wasm/studio-utils"; 3 | 4 | gulp.task("build", async () => { 5 | const options = { debug: true, cargo: true }; 6 | const data = await Service.compileFiles([ 7 | project.getFile("src/lib.rs"), 8 | project.getFile("src/arc_module.rs"), 9 | project.getFile("src/color.rs"), 10 | project.getFile("src/utils.rs"), 11 | project.getFile("Cargo.toml") 12 | ], "rust", "wasm", options); 13 | const outWasm = project.newFile("out/lib.wasm", "wasm", true); 14 | outWasm.setData(data["a.wasm"]); 15 | }); 16 | 17 | gulp.task("publish", async () => { 18 | const rows = 44, cols = 36, frameCount = 1050, fps = 35; 19 | const { transform } = await (await Service.import('src/module.js')).default(); 20 | const buffer = new ArrayBuffer(cols * rows * frameCount * 3); 21 | transform(buffer, rows, cols, frameCount, fps, true); 22 | 23 | const jsModule = project.getFile("src/module.js").getData(); 24 | const rsSource = project.getFile("src/lib.rs").getData(); 25 | const wasmModule = project.getFile("out/lib.wasm").getData(); 26 | Arc.publish({ 27 | description: "WASM Module Example", 28 | author: "", 29 | animation: { 30 | rows, 31 | cols, 32 | frameCount, 33 | fps, 34 | data: buffer, 35 | }, 36 | entry: "src/module.js", 37 | files: { 38 | "src/module.js": jsModule, 39 | "src/lib.rs": rsSource, 40 | "out/lib.wasm": wasmModule, 41 | } 42 | }); 43 | logLn("Rust Module was published.") 44 | }); 45 | 46 | gulp.task("default", ["build"], async () => {}); 47 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_hello_world/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasm/arc_rust", 3 | "description": "", 4 | "version": "1.0.0", 5 | "scripts": { 6 | "build": "gulp --gulpfile ./build.ts" 7 | }, 8 | "devDependencies": { 9 | }, 10 | "wasmStudio": { 11 | "name": "ARCH Rust Hello World Project", 12 | "description": "# ARCH Rust Hello World Project\n\nThis project comes with a small example to get started with rendering text on the ARCH.", 13 | "icon": "rust-lang-file-icon" 14 | } 15 | } -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_hello_world/src/arc_module.rs: -------------------------------------------------------------------------------- 1 | use color::Rgb; 2 | use module_instance; 3 | 4 | pub struct ArcModule { 5 | pub rows: usize, 6 | pub cols: usize, 7 | frame_count: usize, 8 | fps: usize, 9 | is_first: bool, 10 | animation: Vec, 11 | } 12 | 13 | impl ArcModule { 14 | pub fn create_instance( 15 | rows: usize, 16 | cols: usize, 17 | frame_count: usize, 18 | fps: usize, 19 | is_first: bool, 20 | ) -> &'static ArcModule { 21 | let buffer_size = rows * cols * frame_count; 22 | let mut module = ArcModule { 23 | rows, 24 | cols, 25 | frame_count, 26 | fps, 27 | is_first, 28 | animation: Vec::with_capacity(buffer_size), 29 | }; 30 | module.animation.resize(buffer_size, Rgb::new(0, 0, 0)); 31 | module.animation[0] = Rgb { r: 2, g: 4, b: 10 }; 32 | unsafe { module_instance = Box::into_raw(Box::new(module)) }; 33 | ArcModule::get_instance() 34 | } 35 | 36 | pub fn get_instance<'a>() -> &'a mut ArcModule { 37 | unsafe { &mut *module_instance } 38 | } 39 | 40 | pub fn get_animation<'a>(&'a mut self) -> &'a mut Vec { 41 | &mut self.animation 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_hello_world/src/color.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | #[derive(Copy)] 3 | pub struct Rgb { 4 | pub r: u8, 5 | pub g: u8, 6 | pub b: u8, 7 | } 8 | 9 | impl Rgb { 10 | pub fn new(r: u8, g: u8, b: u8) -> Rgb { 11 | Rgb { r, g, b } 12 | } 13 | } 14 | 15 | impl Clone for Rgb { 16 | fn clone(&self) -> Rgb { 17 | *self 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_hello_world/src/module.js: -------------------------------------------------------------------------------- 1 | class ArcModule { 2 | constructor(wasm) { 3 | this.initialized = false; 4 | 5 | if (typeof wasm === 'string') { 6 | if (!WebAssembly.instantiateStreaming) { 7 | this.wasmPromise = fetchAndInstantiateFallback(wasm); 8 | } else { 9 | this.wasmPromise = WebAssembly.instantiateStreaming(fetch(wasm)); 10 | } 11 | } else { 12 | this.wasmPromise = WebAssembly.instantiate(wasm); 13 | } 14 | 15 | this.wasmPromise = this.wasmPromise.then(result => { 16 | this.wasmInstance = result.instance; 17 | this.wasmExports = result.instance.exports; 18 | }); 19 | } 20 | 21 | get ready() { 22 | return this.wasmPromise; 23 | } 24 | 25 | init(rows, cols, frameCount, fps, isFirst) { 26 | if (!this.wasmInstance) { 27 | throw new Error("Wasm module not loaded"); 28 | } 29 | 30 | try { 31 | this.bufferSize = rows * cols * frameCount * 3; 32 | this.wasmExports.init(rows, cols, frameCount, fps, isFirst); 33 | this.initialized = true; 34 | } catch (e) { 35 | console.log(e.stack); 36 | } 37 | } 38 | 39 | transform(input) { 40 | if (!this.initialized) { 41 | throw new Error("Wasm module not initialized"); 42 | } 43 | 44 | let bufferOffset = this.wasmExports.getAnimationBuffer(); 45 | let animationBuffer = new Uint8Array(this.wasmExports.memory.buffer, bufferOffset, this.bufferSize); 46 | 47 | animationBuffer.set(input); 48 | this.wasmExports.apply(); 49 | return animationBuffer; 50 | } 51 | } 52 | 53 | async function fetchAndInstantiateFallback(url, imports) { 54 | const response = await fetch(url); 55 | const buffer = await response.arrayBuffer(); 56 | return WebAssembly.instantiate(buffer, imports); 57 | } 58 | 59 | export default async function () { 60 | let module = new ArcModule("../out/lib.wasm"); 61 | await module.ready; 62 | 63 | return { 64 | transform(buffer, rows, cols, frameCount, fps, isFirst) { 65 | module.init(rows, cols, frameCount, fps, isFirst); 66 | let input = new Uint8Array(buffer); 67 | let output = module.transform(input); 68 | input.set(output); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_hello_world/src/utils.rs: -------------------------------------------------------------------------------- 1 | use arc_module::ArcModule; 2 | use color::Rgb; 3 | 4 | #[no_mangle] 5 | pub extern "C" fn init(rows: usize, cols: usize, frame_count: usize, fps: usize, is_first: bool) { 6 | ArcModule::create_instance(rows, cols, frame_count, fps, is_first); 7 | } 8 | 9 | #[no_mangle] 10 | pub extern "C" fn getAnimationBuffer() -> *const Rgb { 11 | ArcModule::get_instance().get_animation().as_ptr() 12 | } 13 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_jsconf_logo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arc_project" 3 | version = "0.1.0" 4 | authors = ["You! "] 5 | 6 | [dependencies] 7 | # Dependencies are currently deactivated 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_jsconf_logo/README.md: -------------------------------------------------------------------------------- 1 | # Arc project: Rust 2 | 3 | Welcome to the Rust Arc project template! 4 | 5 | 6 | **To create your animation, you'll edit the `apply()` function in the `lib.rs` file.** 7 | 8 | There are several other files in the project that have some boilerplate and helper 9 | `Structs` and `functions` to make it easier for you to get up and running: 10 | 11 | - `ArcModule` is a struct (sorta like a JS Object!) that represents your module: 12 | - `rows`: the number of rows, 44 13 | - `cols`: the number of columns, 36 14 | - `animation`: a `Vector` (sorta like a JS Array) of `Rgb` structs (frame of color!) 15 | 16 | - `Color` is a struct that represents a frame of color 17 | - `r`: Red (0..255) 18 | - `g`: Green (0..255) 19 | - `b`: Blue (0..255) 20 | 21 | Rust is a compiled language- so to work with it- you'll need to have the code compile 22 | (this is how it becomes WebAssembly!) To compile your code you can click `Build` - which 23 | runs `cargo build --target wasm32-unknown-unknown`. The Rust compiler helps ensure your 24 | code will run correctly- and catch bugs for you before it runs! You'll need to make the 25 | code compile before it will run! You can look for compiler errors in the interface- 26 | be sure to read the error messages as they are very helpful and often have suggestions 27 | on how to fix your code to make it work! 28 | 29 | If you need help, you can join the Mozilla IRC #rust-wasm channel and ask questions! 30 | 31 | Here's an easy link for joining IRC: https://kiwiirc.com/client/irc.mozilla.org:+6667/#rust-wasm 32 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_jsconf_logo/build.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from "gulp"; 2 | import { Service, Arc, project, logLn } from "@wasm/studio-utils"; 3 | 4 | gulp.task("build", async () => { 5 | const options = { debug: true, cargo: true }; 6 | const data = await Service.compileFiles([ 7 | project.getFile("src/lib.rs"), 8 | project.getFile("src/arc_module.rs"), 9 | project.getFile("src/color.rs"), 10 | project.getFile("src/utils.rs"), 11 | project.getFile("Cargo.toml") 12 | ], "rust", "wasm", options); 13 | const outWasm = project.newFile("out/lib.wasm", "wasm", true); 14 | outWasm.setData(data["a.wasm"]); 15 | }); 16 | 17 | gulp.task("publish", async () => { 18 | const rows = 44, cols = 36, frameCount = 1050, fps = 35; 19 | const { transform } = await (await Service.import('src/module.js')).default(); 20 | const buffer = new ArrayBuffer(cols * rows * frameCount * 3); 21 | transform(buffer, rows, cols, frameCount, fps, true); 22 | 23 | const jsModule = project.getFile("src/module.js").getData(); 24 | const rsSource = project.getFile("src/lib.rs").getData(); 25 | const wasmModule = project.getFile("out/lib.wasm").getData(); 26 | Arc.publish({ 27 | description: "WASM Module Example", 28 | author: "", 29 | animation: { 30 | rows, 31 | cols, 32 | frameCount, 33 | fps, 34 | data: buffer, 35 | }, 36 | entry: "src/module.js", 37 | files: { 38 | "src/module.js": jsModule, 39 | "src/lib.rs": rsSource, 40 | "out/lib.wasm": wasmModule, 41 | } 42 | }); 43 | logLn("Rust Module was published.") 44 | }); 45 | 46 | gulp.task("default", ["build"], async () => {}); 47 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_jsconf_logo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasm/arc_rust", 3 | "description": "", 4 | "version": "1.0.0", 5 | "scripts": { 6 | "build": "gulp --gulpfile ./build.ts" 7 | }, 8 | "devDependencies": { 9 | }, 10 | "wasmStudio": { 11 | "name": "ARCH: JSConf Logo in Rust", 12 | "description": "# JSconf Logo in Rust\n\nA pulsating JSConf logo in Rust.", 13 | "icon": "rust-lang-file-icon" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_jsconf_logo/src/arc_module.rs: -------------------------------------------------------------------------------- 1 | use color::Rgb; 2 | use module_instance; 3 | 4 | pub struct ArcModule { 5 | pub rows: usize, 6 | pub cols: usize, 7 | frame_count: usize, 8 | fps: usize, 9 | is_first: bool, 10 | animation: Vec, 11 | } 12 | 13 | impl ArcModule { 14 | pub fn create_instance( 15 | rows: usize, 16 | cols: usize, 17 | frame_count: usize, 18 | fps: usize, 19 | is_first: bool, 20 | ) -> &'static ArcModule { 21 | let buffer_size = rows * cols * frame_count; 22 | let mut module = ArcModule { 23 | rows, 24 | cols, 25 | frame_count, 26 | fps, 27 | is_first, 28 | animation: Vec::with_capacity(buffer_size), 29 | }; 30 | module.animation.resize(buffer_size, Rgb::new(0, 0, 0)); 31 | module.animation[0] = Rgb { r: 2, g: 4, b: 10 }; 32 | unsafe { module_instance = Box::into_raw(Box::new(module)) }; 33 | ArcModule::get_instance() 34 | } 35 | 36 | pub fn get_instance<'a>() -> &'a mut ArcModule { 37 | unsafe { &mut *module_instance } 38 | } 39 | 40 | pub fn get_animation<'a>(&'a mut self) -> &'a mut Vec { 41 | &mut self.animation 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_jsconf_logo/src/color.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | #[derive(Copy)] 3 | pub struct Rgb { 4 | pub r: u8, 5 | pub g: u8, 6 | pub b: u8, 7 | } 8 | 9 | impl Rgb { 10 | pub fn new(r: u8, g: u8, b: u8) -> Rgb { 11 | Rgb { r, g, b } 12 | } 13 | } 14 | 15 | impl Clone for Rgb { 16 | fn clone(&self) -> Rgb { 17 | *self 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_jsconf_logo/src/module.js: -------------------------------------------------------------------------------- 1 | class ArcModule { 2 | constructor(wasm) { 3 | this.initialized = false; 4 | 5 | if (typeof wasm === 'string') { 6 | if (!WebAssembly.instantiateStreaming) { 7 | this.wasmPromise = fetchAndInstantiateFallback(wasm); 8 | } else { 9 | this.wasmPromise = WebAssembly.instantiateStreaming(fetch(wasm)); 10 | } 11 | } else { 12 | this.wasmPromise = WebAssembly.instantiate(wasm); 13 | } 14 | 15 | this.wasmPromise = this.wasmPromise.then(result => { 16 | this.wasmInstance = result.instance; 17 | this.wasmExports = result.instance.exports; 18 | }); 19 | } 20 | 21 | get ready() { 22 | return this.wasmPromise; 23 | } 24 | 25 | init(rows, cols, frameCount, fps, isFirst) { 26 | if (!this.wasmInstance) { 27 | throw new Error("Wasm module not loaded"); 28 | } 29 | 30 | try { 31 | this.bufferSize = rows * cols * frameCount * 3; 32 | this.wasmExports.init(rows, cols, frameCount, fps, isFirst); 33 | this.initialized = true; 34 | } catch (e) { 35 | console.log(e.stack); 36 | } 37 | } 38 | 39 | transform(input) { 40 | if (!this.initialized) { 41 | throw new Error("Wasm module not initialized"); 42 | } 43 | 44 | let bufferOffset = this.wasmExports.getAnimationBuffer(); 45 | let animationBuffer = new Uint8Array(this.wasmExports.memory.buffer, bufferOffset, this.bufferSize); 46 | 47 | animationBuffer.set(input); 48 | this.wasmExports.apply(); 49 | return animationBuffer; 50 | } 51 | } 52 | 53 | async function fetchAndInstantiateFallback(url, imports) { 54 | const response = await fetch(url); 55 | const buffer = await response.arrayBuffer(); 56 | return WebAssembly.instantiate(buffer, imports); 57 | } 58 | 59 | export default async function () { 60 | let module = new ArcModule("../out/lib.wasm"); 61 | await module.ready; 62 | 63 | return { 64 | transform(buffer, rows, cols, frameCount, fps, isFirst) { 65 | module.init(rows, cols, frameCount, fps, isFirst); 66 | let input = new Uint8Array(buffer); 67 | let output = module.transform(input); 68 | input.set(output); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_jsconf_logo/src/utils.rs: -------------------------------------------------------------------------------- 1 | use arc_module::ArcModule; 2 | use color::Rgb; 3 | 4 | #[no_mangle] 5 | pub extern "C" fn init(rows: usize, cols: usize, frame_count: usize, fps: usize, is_first: bool) { 6 | ArcModule::create_instance(rows, cols, frame_count, fps, is_first); 7 | } 8 | 9 | #[no_mangle] 10 | pub extern "C" fn getAnimationBuffer() -> *const Rgb { 11 | ArcModule::get_instance().get_animation().as_ptr() 12 | } 13 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_random/Cargo.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "arc_project" 3 | version = "0.1.0" 4 | 5 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_random/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arc_project" 3 | version = "0.1.0" 4 | authors = ["You! "] 5 | 6 | [dependencies] 7 | # Dependencies are currently deactivated 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_random/README.md: -------------------------------------------------------------------------------- 1 | # Arc project: Rust with external functions 2 | 3 | This is an example for using browser functions from WASM. Rust supplies no `random` function, so we are going to use the browsers. 4 | 5 | Have a look at `src/browser.rs` for the necessary definitions on the Rust side,`src/lib.rs` for calling and `src/module.js` for the necessary JavaScript setup. 6 | 7 | The example implements Conway's Game of Life. 8 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_random/build.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from "gulp"; 2 | import { Service, Arc, project, logLn } from "@wasm/studio-utils"; 3 | 4 | gulp.task("build", async () => { 5 | const options = { debug: true, cargo: true }; 6 | const data = await Service.compileFiles([ 7 | project.getFile("src/lib.rs"), 8 | project.getFile("src/arc_module.rs"), 9 | project.getFile("src/color.rs"), 10 | project.getFile("src/utils.rs"), 11 | project.getFile("src/browser.rs"), 12 | project.getFile("Cargo.toml") 13 | ], "rust", "wasm", options); 14 | const outWasm = project.newFile("out/lib.wasm", "wasm", true); 15 | outWasm.setData(data["a.wasm"]); 16 | }); 17 | 18 | gulp.task("publish", async () => { 19 | const rows = 44, cols = 36, frameCount = 1050, fps = 35; 20 | const { transform } = await (await Service.import('src/module.js')).default(); 21 | const buffer = new ArrayBuffer(cols * rows * frameCount * 3); 22 | transform(buffer, rows, cols, frameCount, fps, true); 23 | 24 | const jsModule = project.getFile("src/module.js").getData(); 25 | const rsSource = project.getFile("src/lib.rs").getData(); 26 | const wasmModule = project.getFile("out/lib.wasm").getData(); 27 | Arc.publish({ 28 | description: "WASM Module Example", 29 | author: "", 30 | animation: { 31 | rows, 32 | cols, 33 | frameCount, 34 | fps, 35 | data: buffer, 36 | }, 37 | entry: "src/module.js", 38 | files: { 39 | "src/module.js": jsModule, 40 | "src/lib.rs": rsSource, 41 | "out/lib.wasm": wasmModule, 42 | } 43 | }); 44 | logLn("Rust Module was published.") 45 | }); 46 | 47 | gulp.task("default", ["build"], async () => {}); 48 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_random/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasm/arc_rust", 3 | "description": "", 4 | "version": "1.0.0", 5 | "scripts": { 6 | "build": "gulp --gulpfile ./build.ts" 7 | }, 8 | "devDependencies": { 9 | }, 10 | "wasmStudio": { 11 | "name": "ARCH: External random() Function", 12 | "description": "# Calling browser functions from Rust\n\nAn example that binds to the browsers `random()` function and implements a Game of Life. Contributed by @finnpauls.", 13 | "icon": "rust-lang-file-icon" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_random/src/arc_module.rs: -------------------------------------------------------------------------------- 1 | use color::Rgb; 2 | use module_instance; 3 | 4 | pub struct ArcModule { 5 | pub rows: usize, 6 | pub cols: usize, 7 | pub frame_count: usize, 8 | fps: usize, 9 | is_first: bool, 10 | animation: Vec 11 | } 12 | 13 | impl ArcModule { 14 | pub fn create_instance(rows: usize, cols: usize, frame_count: usize, fps: usize, is_first: bool) -> &'static ArcModule { 15 | let buffer_size = rows * cols * frame_count; 16 | let mut module = ArcModule { 17 | rows, 18 | cols, 19 | frame_count, 20 | fps, 21 | is_first, 22 | animation: Vec::with_capacity(buffer_size) 23 | }; 24 | module.animation.resize(buffer_size, Rgb::new(0, 0, 0)); 25 | module.animation[0] = Rgb {r: 2, g: 4, b: 10}; 26 | unsafe { module_instance = Box::into_raw(Box::new(module)) }; 27 | ArcModule::get_instance() 28 | } 29 | 30 | pub fn get_instance<'a>() -> &'a mut ArcModule { 31 | unsafe { &mut *module_instance } 32 | } 33 | 34 | pub fn get_animation<'a>(&'a mut self) -> &'a mut Vec { 35 | &mut self.animation 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_random/src/browser.rs: -------------------------------------------------------------------------------- 1 | /// This module makes it known to Rust that 2 | /// there is an external (non-Rust) function 3 | /// called `random`. It takes no arguments 4 | /// and returns a float. 5 | 6 | extern { 7 | pub fn random() -> f64; 8 | } -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_random/src/color.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | #[derive(Copy)] 3 | pub struct Rgb { 4 | pub r: u8, 5 | pub g: u8, 6 | pub b: u8, 7 | } 8 | 9 | impl Rgb { 10 | pub fn new(r: u8, g: u8, b: u8) -> Rgb { 11 | Rgb {r, g, b} 12 | } 13 | } 14 | 15 | impl Clone for Rgb { 16 | fn clone(&self) -> Rgb { *self } 17 | } 18 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_random/src/module.js: -------------------------------------------------------------------------------- 1 | class ArcModule { 2 | constructor(wasm) { 3 | this.initialized = false; 4 | // We setup an object mapping 5 | // names to functions here and 6 | // then pass it into the WebAssembly 7 | // instantiation function further down. 8 | var foreignFunctions = {env: { 9 | random: Math.random, 10 | }}; 11 | 12 | if (typeof wasm === 'string') { 13 | if (!WebAssembly.instantiateStreaming) { 14 | this.wasmPromise = fetchAndInstantiateFallback(wasm, foreignFunctions); 15 | } else { 16 | this.wasmPromise = WebAssembly.instantiateStreaming(fetch(wasm), foreignFunctions); 17 | } 18 | } else { 19 | this.wasmPromise = WebAssembly.instantiate(wasm, foreignFunctions); 20 | } 21 | 22 | this.wasmPromise = this.wasmPromise.then(result => { 23 | this.wasmInstance = result.instance; 24 | this.wasmExports = result.instance.exports; 25 | }); 26 | } 27 | 28 | get ready() { 29 | return this.wasmPromise; 30 | } 31 | 32 | init(rows, cols, frameCount, fps, isFirst) { 33 | if (!this.wasmInstance) { 34 | throw new Error("Wasm module not loaded"); 35 | } 36 | 37 | try { 38 | this.bufferSize = rows * cols * frameCount * 3; 39 | this.wasmExports.init(rows, cols, frameCount, fps, isFirst); 40 | this.initialized = true; 41 | } catch (e) { 42 | console.log(e.stack); 43 | } 44 | } 45 | 46 | transform(input) { 47 | if (!this.initialized) { 48 | throw new Error("Wasm module not initialized"); 49 | } 50 | 51 | let bufferOffset = this.wasmExports.getAnimationBuffer(); 52 | let animationBuffer = new Uint8Array(this.wasmExports.memory.buffer, bufferOffset, this.bufferSize); 53 | 54 | animationBuffer.set(input); 55 | this.wasmExports.apply(); 56 | return animationBuffer; 57 | } 58 | } 59 | 60 | async function fetchAndInstantiateFallback(url, imports) { 61 | const response = await fetch(url); 62 | const buffer = await response.arrayBuffer(); 63 | return WebAssembly.instantiate(buffer, imports); 64 | } 65 | 66 | export default async function () { 67 | let module = new ArcModule("../out/lib.wasm"); 68 | await module.ready; 69 | 70 | return { 71 | transform(buffer, rows, cols, frameCount, fps, isFirst) { 72 | module.init(rows, cols, frameCount, fps, isFirst); 73 | let input = new Uint8Array(buffer); 74 | let output = module.transform(input); 75 | input.set(output); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_rust_random/src/utils.rs: -------------------------------------------------------------------------------- 1 | use color::Rgb; 2 | use arc_module::ArcModule; 3 | 4 | #[no_mangle] 5 | pub extern fn init(rows: usize, cols: usize, frame_count: usize, fps: usize, is_first: bool) { 6 | ArcModule::create_instance(rows, cols, frame_count, fps, is_first); 7 | } 8 | 9 | #[no_mangle] 10 | pub extern fn getAnimationBuffer() -> *const Rgb { 11 | ArcModule::get_instance().get_animation().as_ptr() 12 | } 13 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_wat/README.md: -------------------------------------------------------------------------------- 1 | # Arc project: WebAssembly text 2 | 3 | See `src/module.wat` for source code for the module, and `src/module.js` for the integration stuff. -------------------------------------------------------------------------------- /misc/arc-templates/arc_wat/build.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from "gulp"; 2 | import { Service, Arc, project, logLn } from "@wasm/studio-utils"; 3 | 4 | gulp.task("build", async () => { 5 | const data = await Service.assembleWat(project.getFile("src/module.wat").getData()); 6 | const outWasm = project.newFile("out/module.wasm", "wasm", true); 7 | outWasm.setData(data); 8 | }); 9 | 10 | gulp.task("publish", async () => { 11 | const rows = 44, cols = 36, frameCount = 1050, fps = 35; 12 | const { transform } = await (await Service.import('src/module.js')).default(); 13 | const buffer = new ArrayBuffer(cols * rows * frameCount * 3); 14 | transform(buffer, rows, cols, frameCount, fps, true); 15 | 16 | const jsModule = project.getFile("src/module.js").getData(); 17 | const watSource = project.getFile("src/module.wat").getData(); 18 | const wasmModule = project.getFile("out/module.wasm").getData(); 19 | Arc.publish({ 20 | description: "WASM Module Example", 21 | author: "", 22 | animation: { 23 | rows, 24 | cols, 25 | frameCount, 26 | fps, 27 | data: buffer, 28 | }, 29 | entry: "src/module.js", 30 | files: { 31 | "src/module.js": jsModule, 32 | "src/module.wat": watSource, 33 | "out/module.wasm": wasmModule, 34 | } 35 | }); 36 | logLn("WASM Module was published.") 37 | }); 38 | 39 | gulp.task("default", ["build"], async () => {}); 40 | -------------------------------------------------------------------------------- /misc/arc-templates/arc_wat/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasm/arc_wat", 3 | "description": "", 4 | "version": "1.0.0", 5 | "scripts": { 6 | "build": "gulp --gulpfile ./build.ts" 7 | }, 8 | "devDependencies": { 9 | }, 10 | "wasmStudio": { 11 | "name": "Empty ARCH Wat Project", 12 | "description": "# Empty ARCH Wat Project\n\nHigh-level languages are not for you? Write WebAssembly directly!", 13 | "icon": "wat-lang-file-icon" 14 | } 15 | } -------------------------------------------------------------------------------- /misc/arc-templates/arc_wat/src/module.js: -------------------------------------------------------------------------------- 1 | export default function () { 2 | // Loading wasm modules 3 | return WebAssembly.instantiateStreaming(fetch("../out/module.wasm")).then(({instance}) => { 4 | return { 5 | transform(buffer, rows, cols, frameCount, fps, isFirst) { 6 | const size = rows * cols * frameCount * 3; 7 | // Allocate memory in the wasm memory (and copy input buffer). 8 | const p = instance.exports.alloc(size); 9 | const temp = new Uint8Array(instance.exports.memory.buffer, p, size); 10 | const out = new Uint8Array(buffer, 0, size); 11 | if (!isFirst) temp.set(out); 12 | // Transform 13 | instance.exports.transform(p, rows, cols, frameCount, fps, isFirst); 14 | // Transfer data to the output buffer and release wasm memory 15 | out.set(temp); 16 | instance.exports.free(p); 17 | }, 18 | }; 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /notes/help.md: -------------------------------------------------------------------------------- 1 | # WebAssembly Studio 2 | 3 | ## Privacy Notice 4 | 5 | Updated on Februrary 26, 2018 6 | 7 | The WebAssembly Studio has a client-server architecture. Some of the functionality resides on servers, which means that the application might send user source files to the servers and back. This information is temporarily stored on servers, but will not be shared with general public. 8 | 9 | The WebAssembly Studio provides functionality to share user files with the public (via the Share or Fork action). The shared information cannot be made private once shared. The application may use third-party storage for storing this information. 10 | 11 | The WebAssembly Studio may track its usage through telemetry. We use this information to improve user experience. This information is not made publicly available. 12 | -------------------------------------------------------------------------------- /notes/notes.md: -------------------------------------------------------------------------------- 1 | # WebAssembly Studio 2 | 3 | Learn, Teach, Work and Play in the [WebAssembly Studio](https://docs.google.com/presentation/d/1JviCYrWtAQd8DiAimLZnexzyLMY0fST8L-vNTp2yMZk/edit?usp=sharing) -------------------------------------------------------------------------------- /src/@types/tar-js/index.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for [tar-js] 2 | // Project: [WebAssemblyStudios] 3 | // Definitions by: [Florian Gilcher] 4 | 5 | declare module '*'; 6 | 7 | -------------------------------------------------------------------------------- /src/actions/ArcActions.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | import { pushStatus, popStatus, runTask } from "./AppActions"; 23 | import { RunTaskExternals } from "../utils/taskRunner"; 24 | import { notifyAboutFork } from "../arc"; 25 | 26 | export async function publishArc() { 27 | pushStatus("Previewing Arc Project"); 28 | await runTask("publish", false, RunTaskExternals.Arc); 29 | popStatus(); 30 | } 31 | 32 | export function notifyArcAboutFork(fiddle: string) { 33 | notifyAboutFork(fiddle); 34 | } 35 | -------------------------------------------------------------------------------- /src/arc.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | export interface PublishManifest { 23 | description?: string; 24 | author?: string; 25 | image: { 26 | rows: number; 27 | cols: number; 28 | frameCount: number; 29 | fps: number; 30 | data: Uint8Array|number[]; 31 | }; 32 | entry?: string; 33 | files?: { [name: string]: (string | Uint8Array); }; 34 | } 35 | 36 | export function notifyAboutFork(fiddle: string) { 37 | window.parent.postMessage({ 38 | type: "wasm-studio/fork", 39 | fiddle, 40 | }, "*"); 41 | } 42 | 43 | export class Arc { 44 | public static publish(manifest: PublishManifest) { 45 | window.parent.postMessage({ 46 | type: "wasm-studio/module-publish", 47 | manifest, 48 | }, "*"); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/compilerServices/index.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | import { CompilerService, Language } from "./types"; 22 | import { RustService } from "./rustService"; 23 | import { ClangService } from "./clangService"; 24 | import { X86Service } from "./x86Service"; 25 | 26 | export { 27 | ServiceInput, 28 | ServiceOutput, 29 | CompilerService, 30 | InputFile, 31 | OutputItem, 32 | Language, 33 | } from "./types"; 34 | 35 | export async function createCompilerService(from: Language, to: Language): Promise { 36 | if (from === Language.Rust && to === Language.Wasm) { 37 | return new RustService(); 38 | } 39 | if ((from === Language.C || from === Language.Cpp) && to === Language.Wasm) { 40 | return new ClangService(from); 41 | } 42 | if (from === Language.Wasm && to === Language.x86) { 43 | return new X86Service(); 44 | } 45 | throw new Error(`createCompilerService: not supported ${from}->${to}`); 46 | } 47 | -------------------------------------------------------------------------------- /src/compilerServices/types.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | export enum Language { 22 | C = "c", 23 | Cpp = "cpp", 24 | Wat = "wat", 25 | Wasm = "wasm", 26 | Rust = "rust", 27 | Cretonne = "cton", 28 | x86 = "x86", 29 | Json = "json", 30 | JavaScript = "javascript", 31 | TypeScript = "typescript", 32 | Toml = "toml", 33 | Text = "text" 34 | } 35 | 36 | export interface InputFile { 37 | content: string | ArrayBuffer; 38 | options?: any; 39 | } 40 | 41 | export interface ServiceInput { 42 | files: { [name: string]: InputFile; }; 43 | options?: any; 44 | } 45 | 46 | export interface OutputItem { 47 | content?: string | ArrayBuffer; 48 | fileRef?: string; 49 | console?: string; 50 | } 51 | 52 | export interface ServiceOutput { 53 | success: boolean; 54 | items: { [name: string]: OutputItem; }; 55 | console?: string; 56 | } 57 | 58 | export interface CompilerService { 59 | compile(input: ServiceInput): Promise; 60 | } 61 | -------------------------------------------------------------------------------- /src/compilerServices/utils.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | import { decodeRestrictedBase64ToBytes } from "../util"; 22 | import { isZlibData, decompressZlib } from "../utils/zlib"; 23 | import { fromByteArray } from "base64-js"; 24 | 25 | export async function decodeBinary(input: string): Promise { 26 | let data = decodeRestrictedBase64ToBytes(input); 27 | if (isZlibData(data)) { 28 | data = await decompressZlib(data); 29 | } 30 | return data.buffer as ArrayBuffer; 31 | } 32 | 33 | export function encodeBinary(input: ArrayBuffer): string { 34 | return fromByteArray(new Uint8Array(input)); 35 | } 36 | -------------------------------------------------------------------------------- /src/compilerServices/x86Service.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | import { CompilerService, ServiceInput, ServiceOutput } from "./types"; 22 | import { sendRequest, ServiceTypes } from "./sendRequest"; 23 | import { encodeBinary } from "./utils"; 24 | 25 | export class X86Service implements CompilerService { 26 | async compile(input: ServiceInput): Promise { 27 | const files = Object.values(input.files); 28 | if (files.length !== 1) { 29 | throw new Error(`Supporting compilation of a single file, but ${files.length} file(s) found`); 30 | } 31 | const wasm = files[0].content as ArrayBuffer; 32 | const options = input.options; 33 | const encodedWasm = encodeURIComponent(encodeBinary(wasm)); 34 | const content: any = await sendRequest("input=" + encodedWasm + "&action=wasm2assembly&options=" + encodeURIComponent(options), ServiceTypes.Service); 35 | return { 36 | success: true, 37 | items: { 38 | "a.json": { content, }, 39 | }, 40 | }; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/components/BrowserNotSupported.tsx: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | import * as React from "react"; 23 | import * as ReactModal from "react-modal"; 24 | 25 | export class BrowserNotSupported extends React.Component<{ 26 | }, { 27 | }> { 28 | constructor(props: any) { 29 | super(props); 30 | } 31 | render() { 32 | return 39 |
40 |
41 | Browser Version Not Supported 42 |
43 |
44 | WebAssembly is not available in your browser. Please try using the latest version of Edge, Safari, Chrome or Firefox. 45 |
46 |
47 |
; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/components/Header.tsx: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | import * as React from "react"; 23 | 24 | export class Header extends React.Component<{}, {}> { 25 | render() { 26 | return
27 | WebAssembly Studio 28 |
; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/components/StatusBar.tsx: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | import * as React from "react"; 23 | import appStore from "../stores/AppStore"; 24 | 25 | export class StatusBar extends React.Component<{}, { 26 | hasStatus: boolean; 27 | status: string; 28 | }> { 29 | constructor(props: any) { 30 | super(props); 31 | this.state = { 32 | hasStatus: false, 33 | status: "" 34 | }; 35 | } 36 | onDidChangeStatus = () => { 37 | this.setState({ 38 | hasStatus: appStore.hasStatus(), 39 | status: appStore.getStatus() 40 | }); 41 | } 42 | componentDidMount() { 43 | appStore.onDidChangeStatus.register(this.onDidChangeStatus); 44 | } 45 | componentWillUnmount() { 46 | appStore.onDidChangeStatus.unregister(this.onDidChangeStatus); 47 | } 48 | render() { 49 | let className = "status-bar"; 50 | if (this.state.hasStatus) { 51 | className += " active"; 52 | } 53 | return
54 |
55 | {this.state.status} 56 |
57 |
; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/components/Toolbar.tsx: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | import * as React from "react"; 23 | 24 | export class Toolbar extends React.Component<{}, {}> { 25 | render() { 26 | return
27 | {this.props.children} 28 |
; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/components/editor/View.tsx: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | import { File, FileType } from "../../models"; 23 | 24 | export enum ViewType { 25 | Editor, 26 | Markdown, 27 | Binary, 28 | Viz 29 | } 30 | 31 | export function defaultViewTypeForFileType(type: FileType) { 32 | switch (type) { 33 | case FileType.Markdown: 34 | return ViewType.Markdown; 35 | case FileType.DOT: 36 | return ViewType.Viz; 37 | default: 38 | return ViewType.Editor; 39 | } 40 | } 41 | 42 | export function isViewFileDirty(view: View) { 43 | if (!view || !view.file) { 44 | return false; 45 | } 46 | return view.file.isDirty; 47 | } 48 | 49 | export class View { 50 | public file: File; 51 | public type: ViewType; 52 | public state: monaco.editor.ICodeEditorViewState; 53 | 54 | constructor(file: File, type = ViewType.Editor) { 55 | this.file = file; 56 | this.type = type; 57 | } 58 | clone(): View { 59 | return new View(this.file, this.type); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/components/editor/index.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | export { EditorView } from "./Editor"; 23 | export { ViewTabs } from "./ViewTabs"; 24 | export { View } from "./View"; 25 | export { Tab, Tabs } from "./Tabs"; 26 | -------------------------------------------------------------------------------- /src/components/shared/Button.tsx: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | import * as React from "react"; 23 | 24 | export class Button extends React.Component<{ 25 | icon?: JSX.Element; 26 | label?: string; 27 | title?: string; 28 | isDisabled?: boolean; 29 | onClick?: Function; 30 | customClassName?: string; 31 | href?: string, 32 | target?: string, 33 | rel?: string 34 | }, {}> { 35 | render() { 36 | let className = "button "; 37 | if (this.props.customClassName) { 38 | className += this.props.customClassName; 39 | } 40 | if (this.props.isDisabled) { 41 | className += " disabled"; 42 | } 43 | if (this.props.href && !this.props.isDisabled) { 44 | return ( 45 | 52 | {this.props.icon} {this.props.label} 53 | 54 | ); 55 | } 56 | return
{ 59 | if (this.props.onClick && !this.props.isDisabled) { 60 | this.props.onClick(); 61 | } 62 | }} 63 | title={this.props.title} 64 | > 65 | {this.props.icon} {this.props.label} 66 |
; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | export interface IConfig { 23 | serviceUrl: string; 24 | clang: string; 25 | rustc: string; 26 | cargo: string; 27 | templates: { [name: string]: string }; 28 | } 29 | 30 | const configUrl = "./config.json"; 31 | let config: IConfig; 32 | 33 | export default async function getConfig() { 34 | if (!config) { 35 | config = await fetch(configUrl).then(resp => resp.json()); 36 | } 37 | 38 | return config; 39 | } 40 | -------------------------------------------------------------------------------- /src/dispatcher.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | import { Dispatcher } from "flux"; 23 | 24 | export default new Dispatcher(); 25 | -------------------------------------------------------------------------------- /src/errors.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | export const Errors = { 23 | BuildFileMissing: "Build File (build.ts / build.js) is missing." 24 | }; 25 | -------------------------------------------------------------------------------- /src/languages/log.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | import IRichLanguageConfiguration = monaco.languages.LanguageConfiguration; 23 | import ILanguage = monaco.languages.IMonarchLanguage; 24 | import IModel = monaco.editor.IModel; 25 | import IPosition = monaco.IPosition; 26 | 27 | export const Log = { 28 | MonarchTokensProvider: { 29 | tokenizer: { 30 | root: [ 31 | [/\[error.*/, "custom-error"], 32 | [/\[warn.*/, "custom-warn"], 33 | [/\[notice.*/, "custom-notice"], 34 | [/\[info.*/, "custom-info"] 35 | ] 36 | } 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /src/message.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | export enum WorkerCommand { 23 | OptimizeWasmWithBinaryen, 24 | ValidateWasmWithBinaryen, 25 | CreateWasmCallGraphWithBinaryen, 26 | ConvertWasmToAsmWithBinaryen, 27 | DisassembleWasmWithBinaryen, 28 | AssembleWatWithBinaryen, 29 | DisassembleWasmWithWabt, 30 | AssembleWatWithWabt, 31 | TwiggyWasm 32 | } 33 | 34 | /** 35 | * Worker requests. 36 | */ 37 | export interface IWorkerRequest { 38 | id: number; 39 | payload: ArrayBuffer | string; 40 | command: WorkerCommand; 41 | } 42 | 43 | /** 44 | * Worker response. 45 | */ 46 | export interface IWorkerResponse { 47 | id: number; 48 | payload: ArrayBuffer | string | Object; 49 | success: boolean; 50 | } 51 | -------------------------------------------------------------------------------- /src/models/EventDispatcher.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | export class EventDispatcher { 23 | readonly name: string; 24 | private callbacks: Function[] = []; 25 | constructor(name: string) { 26 | this.name = name; 27 | } 28 | register(callback: Function) { 29 | if (this.callbacks.indexOf(callback) >= 0) { 30 | return; 31 | } 32 | this.callbacks.push(callback); 33 | } 34 | unregister(callback: Function) { 35 | const i = this.callbacks.indexOf(callback); 36 | if (i < 0) { 37 | throw new Error("Unknown callback."); 38 | } 39 | this.callbacks.splice(i, 1); 40 | } 41 | dispatch(target?: any) { 42 | // console.log("Dispatching " + this.name); 43 | this.callbacks.forEach(callback => { 44 | callback(target); 45 | }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/models/ModelRef.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | const modelRefMap: WeakMap = new WeakMap(); 23 | 24 | export class ModelRef { 25 | obj: T; 26 | private constructor(obj: T) { 27 | this.obj = obj; 28 | } 29 | public getModel(): T { 30 | return this.obj; 31 | } 32 | public static getRef(obj: T): ModelRef { 33 | if (modelRefMap.has(obj)) { 34 | return modelRefMap.get(obj); 35 | } 36 | const ref = new ModelRef(obj); 37 | modelRefMap.set(obj, ref); 38 | return ref; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/models/Problem.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | import { getNextKey } from "../util"; 23 | import { File } from "./File"; 24 | 25 | export function monacoSeverityToString(severity: monaco.MarkerSeverity) { 26 | switch (severity) { 27 | case monaco.MarkerSeverity.Info: return "info"; 28 | case monaco.MarkerSeverity.Warning: return "warning"; 29 | case monaco.MarkerSeverity.Error: return "error"; 30 | } 31 | } 32 | 33 | export class Problem { 34 | readonly key = String(getNextKey()); 35 | constructor( 36 | public file: File, 37 | public description: string, 38 | public severity: "error" | "warning" | "info" | "ignore", 39 | public marker?: monaco.editor.IMarkerData) { 40 | } 41 | 42 | static fromMarker(file: File, marker: monaco.editor.IMarkerData) { 43 | return new Problem( 44 | file, 45 | `${marker.message} (${marker.startLineNumber}, ${marker.startColumn})`, 46 | monacoSeverityToString(marker.severity), 47 | marker); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/models/Project.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | import { assert } from "../util"; 23 | import { EventDispatcher } from "./EventDispatcher"; 24 | import { Directory } from "./Directory"; 25 | 26 | export class Project extends Directory { 27 | onDidChangeStatus = new EventDispatcher("Status Change"); 28 | onChange = new EventDispatcher("Project Change"); 29 | onDirtyFileUsed = new EventDispatcher("Dirty File Used"); 30 | 31 | constructor() { 32 | super("Project"); 33 | } 34 | 35 | private status: string [] = ["Idle"]; 36 | hasStatus() { 37 | return this.status.length > 1; 38 | } 39 | getStatus() { 40 | if (this.hasStatus()) { 41 | return this.status[this.status.length - 1]; 42 | } 43 | return ""; 44 | } 45 | pushStatus(status: string) { 46 | this.status.push(status); 47 | this.onDidChangeStatus.dispatch(); 48 | } 49 | popStatus() { 50 | assert(this.status.length); 51 | this.status.pop(); 52 | this.onDidChangeStatus.dispatch(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/models/index.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | export { 23 | FileType, 24 | SandboxRun, 25 | IStatusProvider, 26 | isBinaryFileType, 27 | languageForFileType, 28 | nameForFileType, 29 | extensionForFileType, 30 | fileTypeFromFileName, 31 | fileTypeForExtension, 32 | mimeTypeForFileType, 33 | fileTypeForMimeType, 34 | getIconForFileType 35 | } from "./types"; 36 | export { Problem } from "./Problem"; 37 | export { Project } from "./Project"; 38 | export { EventDispatcher } from "./EventDispatcher"; 39 | export { ModelRef } from "./ModelRef"; 40 | export { Directory } from "./Directory"; 41 | export { File } from "./File"; 42 | -------------------------------------------------------------------------------- /src/utils/Logger.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | import * as Raven from "raven-js"; 23 | import config from "../../config.json"; 24 | 25 | export class Logger { 26 | static init() { 27 | if (Logger.isRunningInProduction()) { 28 | Raven.config(config.sentryDNS).install(); 29 | } 30 | } 31 | static captureException(e: any, additionalData?: Raven.RavenOptions) { 32 | if (Logger.isRunningInProduction()) { 33 | Raven.captureException(e, additionalData); 34 | } 35 | } 36 | static captureMessage(message: string, additionalData?: Raven.RavenOptions) { 37 | if (Logger.isRunningInProduction()) { 38 | Raven.captureMessage(message, additionalData); 39 | } 40 | } 41 | static getLastEventId() { 42 | return Raven.lastEventId(); 43 | } 44 | static isRunningInProduction() { 45 | return window.location.hostname === "webassembly.studio"; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/utils/download.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | import { File, Project, Directory } from "../models"; 23 | import * as JSZip from "jszip"; 24 | 25 | export async function downloadProject(project: Project, uri?: string) { 26 | const zipFile: JSZip = new JSZip(); 27 | let zipName: string = "wasm-project.zip"; 28 | if (uri !== undefined) { 29 | zipName = `wasm-project-${uri}.zip`; 30 | } 31 | const queue: Array<{filePrefix: string; file: File}> = []; 32 | project.mapEachFile((f: File) => queue.push({filePrefix: "", file: f})); 33 | while (queue.length > 0) { 34 | const {filePrefix, file} = queue.shift(); 35 | const fileName = filePrefix + file.name; 36 | if (file instanceof Directory) { 37 | file.mapEachFile(f => queue.push({filePrefix: fileName + "/", file: f})); 38 | zipFile.folder(fileName); 39 | continue; 40 | } 41 | zipFile.file(fileName, file.data); 42 | } 43 | await zipFile.generateAsync({type: "blob", mimeType: "application/zip"}).then((blob: Blob) => { 44 | // Creating to programmatically click for downloading zip via blob's URL 45 | const link = document.createElement("a"); 46 | link.download = zipName; 47 | link.href = URL.createObjectURL(blob); 48 | // A fix for making link clickable in Firefox 49 | // Explicity adding link to DOM for Firefox 50 | document.body.appendChild(link); 51 | link.click(); 52 | document.body.removeChild(link); 53 | }); 54 | } 55 | -------------------------------------------------------------------------------- /src/utils/fetchTemplates.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | export default async function fetchTemplates(src: string) { 23 | const response = await fetch(src); 24 | return JSON.parse(await response.text()); 25 | } 26 | -------------------------------------------------------------------------------- /src/utils/ga.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | declare const gtag: Function; 23 | 24 | export function gaEvent(action: string, category?: string, label?: string, value?: number) { 25 | if (typeof gtag !== "function") { 26 | return; 27 | } 28 | gtag("event", action, { 29 | event_category: category, 30 | event_label: label, 31 | value, 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /src/utils/registerTheme.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | export default async function registerTheme() { 23 | monaco.editor.defineTheme("fiddle-theme", { 24 | base: "vs-dark", 25 | inherit: true, 26 | rules: [ 27 | { token: "custom-info", foreground: "d4d4d4" }, 28 | { token: "custom-warn", foreground: "ff9900" }, 29 | { token: "custom-error", background: "00ff00", foreground: "ff0000", fontStyle: "bold" } 30 | ] 31 | } as any); 32 | } 33 | -------------------------------------------------------------------------------- /src/utils/splitUtils.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | import {SplitInfo} from "../components/Split"; 23 | 24 | export function toCSSPx(x: number) { 25 | return (x | 0) + "px"; 26 | } 27 | 28 | export function assignObject(to: any, from: any) { 29 | for (const x in from) { 30 | if (!(x in to)) { 31 | to[x] = from[x]; 32 | } 33 | } 34 | return to; 35 | } 36 | -------------------------------------------------------------------------------- /src/utils/zlib.ts: -------------------------------------------------------------------------------- 1 | /* Copyright 2018 Mozilla Foundation 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all 11 | * copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | export function isZlibData(data: Uint8Array): boolean { 23 | const [ firstByte, secondByte ] = data; 24 | return firstByte === 0x78 && (secondByte === 0x01 || secondByte === 0x9C || secondByte === 0xDA); 25 | } 26 | 27 | export async function decompressZlib(data: Uint8Array): Promise { 28 | const { inflate } = await import("pako"); 29 | return inflate(data); 30 | } 31 | -------------------------------------------------------------------------------- /stryker.conf.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = function(config) { 4 | config.set({ 5 | testRunner: "jest", 6 | mutator: "typescript", 7 | reporters: ["html", "progress", "clear-text"], 8 | htmlReporter: { 9 | baseDir: "mutation/html", 10 | }, 11 | coverageAnalysis: "off", 12 | mutate: [ 13 | "src/**/*.ts?(x)", 14 | "!src/**/**.d.ts" 15 | ], 16 | timeoutMS: 60000, 17 | logLevel: "fatal" 18 | }); 19 | }; 20 | -------------------------------------------------------------------------------- /style/ref.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasdk/WebAssemblyStudio/5eda37b478139dba782974aed2bf8354bc01310a/style/ref.css -------------------------------------------------------------------------------- /style/split-pane.css: -------------------------------------------------------------------------------- 1 | .Resizer { 2 | -moz-box-sizing: border-box; 3 | -webkit-box-sizing: border-box; 4 | box-sizing: border-box; 5 | background: rgb(110, 110, 110); 6 | opacity: .4; 7 | z-index: 30; 8 | -moz-background-clip: padding; 9 | -webkit-background-clip: padding; 10 | background-clip: padding-box; 11 | } 12 | 13 | .Resizer:hover { 14 | -webkit-transition: all 0.3s ease; 15 | transition: all 0.3s ease; 16 | } 17 | 18 | .Resizer.horizontal { 19 | height: 11px; 20 | margin: -5px 0; 21 | border-top: 5px solid rgba(0, 0, 0, 0); 22 | border-bottom: 5px solid rgba(0, 0, 0, 0); 23 | cursor: row-resize; 24 | width: 100%; 25 | } 26 | 27 | .Resizer.horizontal:hover { 28 | border-top: 5px solid rgba(0, 0, 0, 0.5); 29 | border-bottom: 5px solid rgba(0, 0, 0, 0.5); 30 | } 31 | 32 | .Resizer.vertical { 33 | width: 11px; 34 | margin: 0 -5px; 35 | border-left: 5px solid rgba(0, 0, 0, 0); 36 | border-right: 5px solid rgba(0, 0, 0, 0); 37 | cursor: col-resize; 38 | } 39 | 40 | .Resizer.vertical:hover { 41 | border-left: 5px solid rgba(0, 0, 0, 0.5); 42 | border-right: 5px solid rgba(0, 0, 0, 0.5); 43 | } -------------------------------------------------------------------------------- /svg/close.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /svg/default_file.svg: -------------------------------------------------------------------------------- 1 | default_file -------------------------------------------------------------------------------- /svg/default_folder.svg: -------------------------------------------------------------------------------- 1 | default_folder -------------------------------------------------------------------------------- /svg/default_folder_opened.svg: -------------------------------------------------------------------------------- 1 | default_folder_opened -------------------------------------------------------------------------------- /svg/error-dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /svg/error.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /svg/favicon.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasdk/WebAssemblyStudio/5eda37b478139dba782974aed2bf8354bc01310a/svg/favicon.psd -------------------------------------------------------------------------------- /svg/info-dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /svg/info.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /svg/wa-pp-black.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | -------------------------------------------------------------------------------- /svg/wa-pp-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | -------------------------------------------------------------------------------- /svg/wa-pp.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | -------------------------------------------------------------------------------- /svg/wa.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /svg/warning-dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /svg/warning.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /templates/empty_c/README.md: -------------------------------------------------------------------------------- 1 | # Empty C Project 2 | -------------------------------------------------------------------------------- /templates/empty_c/build.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from "gulp"; 2 | import { Service, project } from "@wasm/studio-utils"; 3 | 4 | gulp.task("build", async () => { 5 | const data = await Service.compileFile(project.getFile("src/main.c"), "c", "wasm", "-g -O3"); 6 | const outWasm = project.newFile("out/main.wasm", "wasm", true); 7 | outWasm.setData(data); 8 | }); 9 | 10 | gulp.task("default", ["build"], async () => {}); 11 | -------------------------------------------------------------------------------- /templates/empty_c/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasm/empty_c", 3 | "description": "", 4 | "version": "1.0.0", 5 | "scripts": { 6 | "build": "gulp --gulpfile ./build.ts" 7 | }, 8 | "devDependencies": { 9 | "@wasm/studio-utils": "*", 10 | "gulp": "~3.9.1", 11 | "ts-node": "~5.0.0", 12 | "typescript": "~2.7.2" 13 | }, 14 | "wasmStudio": { 15 | "name": "Empty C Project", 16 | "description": "# Empty C Project", 17 | "icon": "c-lang-file-icon" 18 | } 19 | } -------------------------------------------------------------------------------- /templates/empty_c/src/main.c: -------------------------------------------------------------------------------- 1 | #define WASM_EXPORT __attribute__((visibility("default"))) 2 | 3 | WASM_EXPORT 4 | int main() { 5 | return 42; 6 | } 7 | -------------------------------------------------------------------------------- /templates/empty_c/src/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /templates/empty_c/src/main.js: -------------------------------------------------------------------------------- 1 | fetch('../out/main.wasm').then(response => 2 | response.arrayBuffer() 3 | ).then(bytes => WebAssembly.instantiate(bytes)).then(results => { 4 | instance = results.instance; 5 | document.getElementById("container").textContent = instance.exports.main(); 6 | }).catch(console.error); 7 | -------------------------------------------------------------------------------- /templates/empty_rust/README.md: -------------------------------------------------------------------------------- 1 | # Empty Rust Project 2 | -------------------------------------------------------------------------------- /templates/empty_rust/build.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from "gulp"; 2 | import { Service, project } from "@wasm/studio-utils"; 3 | 4 | gulp.task("build", async () => { 5 | const options = { lto: true, opt_level: 's', debug: true }; 6 | const data = await Service.compileFile(project.getFile("src/main.rs"), "rust", "wasm", options); 7 | const outWasm = project.newFile("out/main.wasm", "wasm", true); 8 | outWasm.setData(data); 9 | }); 10 | 11 | gulp.task("default", ["build"], async () => {}); 12 | -------------------------------------------------------------------------------- /templates/empty_rust/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasm/empty_rust", 3 | "description": "", 4 | "version": "1.0.0", 5 | "scripts": { 6 | "build": "gulp --gulpfile ./build.ts" 7 | }, 8 | "devDependencies": { 9 | "@wasm/studio-utils": "*", 10 | "gulp": "~3.9.1", 11 | "ts-node": "~5.0.0", 12 | "typescript": "~2.7.2" 13 | }, 14 | "wasmStudio": { 15 | "name": "Empty Rust Project", 16 | "description": "# Empty Rust Project", 17 | "icon": "rust-lang-file-icon" 18 | } 19 | } -------------------------------------------------------------------------------- /templates/empty_rust/src/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /templates/empty_rust/src/main.js: -------------------------------------------------------------------------------- 1 | fetch('../out/main.wasm').then(response => 2 | response.arrayBuffer() 3 | ).then(bytes => WebAssembly.instantiate(bytes)).then(results => { 4 | instance = results.instance; 5 | document.getElementById("container").textContent = instance.exports.add_one(41); 6 | }).catch(console.error); 7 | -------------------------------------------------------------------------------- /templates/empty_rust/src/main.rs: -------------------------------------------------------------------------------- 1 | #[no_mangle] 2 | pub extern "C" fn add_one(x: i32) -> i32 { 3 | x + 1 4 | } -------------------------------------------------------------------------------- /templates/empty_ts/README.md: -------------------------------------------------------------------------------- 1 | # Empty AssemblyScript Project 2 | -------------------------------------------------------------------------------- /templates/empty_ts/assembly/main.ts: -------------------------------------------------------------------------------- 1 | declare function sayHello(): void; 2 | 3 | sayHello(); 4 | 5 | export function add(x: i32, y: i32): i32 { 6 | return x + y; 7 | } 8 | -------------------------------------------------------------------------------- /templates/empty_ts/assembly/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../node_modules/assemblyscript/std/assembly.json", 3 | "include": [ 4 | "./**/*.ts" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /templates/empty_ts/gulpfile.js: -------------------------------------------------------------------------------- 1 | const gulp = require("gulp"); 2 | /* 3 | Runtime variants: 4 | 5 | "--runtime", "full" (default) 6 | A proper memory manager and reference-counting based garbage collector, with runtime interfaces 7 | being exported to the host for being able to create managed objects externally. 8 | 9 | "--runtime", "half" 10 | The same as full but without any exports, i.e. where creating objects externally is not required. 11 | This allows the optimizer to eliminate parts of the runtime that are not needed. 12 | 13 | "--runtime", "stub" 14 | A minimalist arena memory manager without any means of freeing up memory again, but the same external 15 | interface as full. Useful for very short-lived programs or programs with hardly any memory footprint, 16 | while keeping the option to switch to full without any further changes. No garbage collection. 17 | 18 | "--runtime", "none" 19 | The same as stub but without any exports, for the same reasons as explained in half. Essentially 20 | evaporates entirely after optimizations. 21 | 22 | For more information see: https://docs.assemblyscript.org/details/runtime 23 | */ 24 | gulp.task("build", callback => { 25 | const asc = require("assemblyscript/bin/asc"); 26 | asc.main([ 27 | "main.ts", 28 | "--baseDir", "assembly", 29 | "--binaryFile", "../out/main.wasm", 30 | "--sourceMap", 31 | "--measure", 32 | "--runtime", "stub", // Please use "incremental" if you need GC 33 | "-O3" // Please use "-O3z" if you need optimize for size 34 | ], callback); 35 | }); 36 | 37 | gulp.task("default", ["build"]); 38 | 39 | // This task is not required when running the project locally. Its purpose is to set up the 40 | // AssemblyScript compiler when a new project has been loaded in WebAssembly Studio. 41 | gulp.task("project:load", () => { 42 | const utils = require("@wasm/studio-utils"); 43 | utils.eval(utils.project.getFile("setup.js").getData(), { 44 | logLn, 45 | project, 46 | monaco, 47 | fileTypeForExtension, 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /templates/empty_ts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasm/empty_ts", 3 | "description": "", 4 | "version": "1.0.0", 5 | "scripts": { 6 | "build": "gulp" 7 | }, 8 | "devDependencies": { 9 | "assemblyscript": "AssemblyScript/assemblyscript", 10 | "gulp": "^3" 11 | }, 12 | "wasmStudio": { 13 | "name": "Empty AssemblyScript Project", 14 | "description": "# Empty AssemblyScript Project\n\n[AssemblyScript](https://github.com/AssemblyScript/assemblyscript) compiles strictly typed TypeScript to WebAssembly using Binaryen.\n\nSee the [AssemblyScript wiki](https://github.com/AssemblyScript/assemblyscript/wiki) for further instructions and documentation.", 15 | "icon": "typescript-lang-file-icon" 16 | } 17 | } -------------------------------------------------------------------------------- /templates/empty_ts/setup.js: -------------------------------------------------------------------------------- 1 | // This file is not required when running the project locally. Its purpose is to set up the 2 | // AssemblyScript compiler when a new project has been loaded in WebAssembly Studio. 3 | require.config({ 4 | paths: { 5 | "binaryen": "https://cdn.jsdelivr.net/npm/binaryen@latest/index", 6 | "assemblyscript": "https://cdn.jsdelivr.net/npm/assemblyscript@latest/dist/assemblyscript", 7 | "assemblyscript/bin/asc": "https://cdn.jsdelivr.net/npm/assemblyscript@latest/dist/asc", 8 | } 9 | }); 10 | logLn("Loading AssemblyScript compiler ..."); 11 | require(["assemblyscript/bin/asc"], asc => { 12 | monaco.languages.typescript.typescriptDefaults.addExtraLib(asc.definitionFiles.assembly); 13 | asc.main = (main => (args, options, fn) => { 14 | if (typeof options === "function") { 15 | fn = options; 16 | options = undefined; 17 | } 18 | return main(args, options || { 19 | stdout: asc.createMemoryStream(), 20 | stderr: asc.createMemoryStream(logLn), 21 | readFile: (filename, baseDir) => { 22 | const file = project.getFile(baseDir + "/" + filename.replace(/^\//, "")); 23 | return file ? file.data : null; 24 | }, 25 | writeFile: (filename, contents) => { 26 | const name = filename.startsWith("../") ? filename.substring(3) : filename; 27 | const type = fileTypeForExtension(name.substring(name.lastIndexOf(".") + 1)); 28 | project.newFile(name, type, true).setData(contents); 29 | }, 30 | listFiles: () => [] 31 | }, fn); 32 | })(asc.main); 33 | logLn("AssemblyScript compiler is ready!"); 34 | }); 35 | -------------------------------------------------------------------------------- /templates/empty_ts/src/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /templates/empty_ts/src/main.js: -------------------------------------------------------------------------------- 1 | WebAssembly.instantiateStreaming(fetch("../out/main.wasm"), { 2 | main: { 3 | sayHello() { 4 | console.log("Hello from WebAssembly!"); 5 | } 6 | }, 7 | env: { 8 | abort(_msg, _file, line, column) { 9 | console.error("abort called at main.ts:" + line + ":" + column); 10 | } 11 | }, 12 | }).then(result => { 13 | const exports = result.instance.exports; 14 | document.getElementById("container").textContent = "Result: " + exports.add(19, 23); 15 | }).catch(console.error); 16 | -------------------------------------------------------------------------------- /templates/empty_wat/README.md: -------------------------------------------------------------------------------- 1 | # Empty Wat Project 2 | -------------------------------------------------------------------------------- /templates/empty_wat/build.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from "gulp"; 2 | import { Service, project } from "@wasm/studio-utils"; 3 | 4 | gulp.task("build", async () => { 5 | const data = await Service.assembleWat(project.getFile("src/main.wat").getData()); 6 | const outWasm = project.newFile("out/main.wasm", "wasm", true); 7 | outWasm.setData(data); 8 | }); 9 | 10 | gulp.task("default", ["build"], async () => {}); 11 | -------------------------------------------------------------------------------- /templates/empty_wat/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasm/empty_wat", 3 | "description": "", 4 | "version": "1.0.0", 5 | "scripts": { 6 | "build": "gulp --gulpfile ./build.ts" 7 | }, 8 | "devDependencies": { 9 | "@wasm/studio-utils": "*", 10 | "gulp": "~3.9.1", 11 | "ts-node": "~5.0.0", 12 | "typescript": "~2.7.2" 13 | }, 14 | "wasmStudio": { 15 | "name": "Empty Wat Project", 16 | "description": "# Empty Wat Project", 17 | "icon": "wat-lang-file-icon" 18 | } 19 | } -------------------------------------------------------------------------------- /templates/empty_wat/src/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /templates/empty_wat/src/main.js: -------------------------------------------------------------------------------- 1 | fetch('../out/main.wasm').then(response => 2 | response.arrayBuffer() 3 | ).then(bytes => WebAssembly.instantiate(bytes)).then(results => { 4 | instance = results.instance; 5 | document.getElementById("container").textContent = instance.exports.add(1,1); 6 | }).catch(console.error); 7 | 8 | -------------------------------------------------------------------------------- /templates/empty_wat/src/main.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (func $add (param $lhs i32) (param $rhs i32) (result i32) 3 | get_local $lhs 4 | get_local $rhs 5 | i32.add) 6 | (export "add" (func $add)) 7 | ) -------------------------------------------------------------------------------- /templates/hello_world_c/build.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from "gulp"; 2 | import { Service, project } from "@wasm/studio-utils"; 3 | 4 | gulp.task("build", async () => { 5 | const data = await Service.compileFile(project.getFile("src/main.c"), "c", "wasm", "-g -O3"); 6 | const outWasm = project.newFile("out/main.wasm", "wasm", true); 7 | outWasm.setData(data); 8 | }); 9 | 10 | gulp.task("default", ["build"], async () => {}); 11 | -------------------------------------------------------------------------------- /templates/hello_world_c/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasm/hello_world_c", 3 | "description": "", 4 | "version": "1.0.0", 5 | "scripts": { 6 | "build": "gulp --gulpfile ./build.ts" 7 | }, 8 | "devDependencies": { 9 | "@wasm/studio-utils": "*", 10 | "gulp": "~3.9.1", 11 | "ts-node": "~5.0.0", 12 | "typescript": "~2.7.2" 13 | }, 14 | "wasmStudio": { 15 | "name": "Hello World in C", 16 | "description": "# Hello World in C\n\nPrint \\`Hello World\\` using a minimal POSIX API.\nLevel: *Advanced*\nTopics: Low-Level, Memory, Linux, System Calls", 17 | "icon": "c-lang-file-icon" 18 | } 19 | } -------------------------------------------------------------------------------- /templates/hello_world_c/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define WASM_EXPORT __attribute__((visibility("default"))) 5 | 6 | WASM_EXPORT 7 | int main(void) { 8 | printf("Hello World\n"); 9 | } 10 | 11 | /* External function that is implemented in JavaScript. */ 12 | extern void putc_js(char c); 13 | 14 | /* Basic implementation of the writev sys call. */ 15 | WASM_EXPORT 16 | size_t writev_c(int fd, const struct iovec *iov, int iovcnt) { 17 | size_t cnt = 0; 18 | for (int i = 0; i < iovcnt; i++) { 19 | for (int j = 0; j < iov[i].iov_len; j++) { 20 | putc_js(((char *)iov[i].iov_base)[j]); 21 | } 22 | cnt += iov[i].iov_len; 23 | } 24 | return cnt; 25 | } 26 | -------------------------------------------------------------------------------- /templates/hello_world_c/src/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /templates/hello_world_c/src/main.js: -------------------------------------------------------------------------------- 1 | let x = '../out/main.wasm'; 2 | 3 | let instance = null; 4 | let memoryStates = new WeakMap(); 5 | 6 | function syscall(instance, n, args) { 7 | switch (n) { 8 | default: 9 | // console.log("Syscall " + n + " NYI."); 10 | break; 11 | case /* brk */ 45: return 0; 12 | case /* writev */ 146: 13 | return instance.exports.writev_c(args[0], args[1], args[2]); 14 | case /* mmap2 */ 192: 15 | debugger; 16 | const memory = instance.exports.memory; 17 | let memoryState = memoryStates.get(instance); 18 | const requested = args[1]; 19 | if (!memoryState) { 20 | memoryState = { 21 | object: memory, 22 | currentPosition: memory.buffer.byteLength, 23 | }; 24 | memoryStates.set(instance, memoryState); 25 | } 26 | let cur = memoryState.currentPosition; 27 | if (cur + requested > memory.buffer.byteLength) { 28 | const need = Math.ceil((cur + requested - memory.buffer.byteLength) / 65536); 29 | memory.grow(need); 30 | } 31 | memoryState.currentPosition += requested; 32 | return cur; 33 | } 34 | } 35 | 36 | let s = ""; 37 | fetch(x).then(response => 38 | response.arrayBuffer() 39 | ).then(bytes => 40 | WebAssembly.instantiate(bytes, { 41 | env: { 42 | __syscall0: function __syscall0(n) { return syscall(instance, n, []); }, 43 | __syscall1: function __syscall1(n, a) { return syscall(instance, n, [a]); }, 44 | __syscall2: function __syscall2(n, a, b) { return syscall(instance, n, [a, b]); }, 45 | __syscall3: function __syscall3(n, a, b, c) { return syscall(instance, n, [a, b, c]); }, 46 | __syscall4: function __syscall4(n, a, b, c, d) { return syscall(instance, n, [a, b, c, d]); }, 47 | __syscall5: function __syscall5(n, a, b, c, d, e) { return syscall(instance, n, [a, b, c, d, e]); }, 48 | __syscall6: function __syscall6(n, a, b, c, d, e, f) { return syscall(instance, n, [a, b, c, d, e, f]); }, 49 | putc_js: function (c) { 50 | c = String.fromCharCode(c); 51 | if (c == "\n") { 52 | console.log(s); 53 | s = ""; 54 | } else { 55 | s += c; 56 | } 57 | } 58 | } 59 | }) 60 | ).then(results => { 61 | instance = results.instance; 62 | document.getElementById("container").textContent = instance.exports.main(); 63 | }).catch(console.error); 64 | -------------------------------------------------------------------------------- /templates/hello_world_rust/README.md: -------------------------------------------------------------------------------- 1 | # "Hello, World!" Rust Project 2 | 3 | This is a sample Rust project which uses the [`wasm_bindgen` crate][crate] to 4 | enable richer interactions between Rust and JS such as communicating with 5 | strings rather than just numbers. 6 | 7 | Typically `wasm-bindgen` is paired with a bundler but here we're not using a 8 | bundler so you can poke around all the raw output! 9 | 10 | Some files you may be interested in are: 11 | 12 | * `lib.rs` - this is the main body of Rust code, annotated with 13 | `#[wasm_bindgen]` to have its functionality exported to JS. 14 | * `main.js` - this is the application's supporting JS, automatically run by 15 | `main.html`. Here you'll import items implemented in Rust through the 16 | `wasmBindgen` global. 17 | 18 | When building the project you'll get `out/main_bg.wasm`, the generated wasm 19 | filtered through the `wasm-bindgen` CLI tool, as well as `out/main.js` which is 20 | an auxiliary JS file generated by the `wasm-bindgen` tool, included by default 21 | in `main.html`. The `out/main.js` file is responsible for creating the 22 | `wasmBindgen` global and filling it in. 23 | 24 | [crate]: https://github.com/rustwasm/wasm-bindgen 25 | -------------------------------------------------------------------------------- /templates/hello_world_rust/build.ts: -------------------------------------------------------------------------------- 1 | import * as gulp from "gulp"; 2 | import { Service, project } from "@wasm/studio-utils"; 3 | 4 | gulp.task("build", async () => { 5 | // Optimize for small builds for now 6 | const options = { lto: true, opt_level: 's', debug: true }; 7 | const libSrc = project.getFile("src/lib.rs"); 8 | const data = await Service.compileFileWithBindings(libSrc, "rust", "wasm", options); 9 | 10 | const outWasm = project.newFile("out/main_bg.wasm", "wasm", true); 11 | outWasm.setData(data.wasm); 12 | const outJs = project.newFile("out/main.js", "javascript", true); 13 | outJs.setData(data.wasmBindgenJs); 14 | }); 15 | 16 | gulp.task("default", ["build"], async () => {}); 17 | -------------------------------------------------------------------------------- /templates/hello_world_rust/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wasm/hello_world_rust", 3 | "description": "", 4 | "version": "1.0.0", 5 | "scripts": { 6 | "build": "gulp --gulpfile ./build.ts" 7 | }, 8 | "devDependencies": { 9 | "@wasm/studio-utils": "*", 10 | "gulp": "~3.9.1", 11 | "ts-node": "~5.0.0", 12 | "typescript": "~2.7.2" 13 | }, 14 | "wasmStudio": { 15 | "name": "Hello World Rust Project", 16 | "description": "# Hello World Rust Project", 17 | "icon": "rust-lang-file-icon" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /templates/hello_world_rust/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Current prelude for using `wasm_bindgen`, and this'll get smaller over time! 2 | #![feature(proc_macro, wasm_custom_section, wasm_import_module)] 3 | extern crate wasm_bindgen; 4 | use wasm_bindgen::prelude::*; 5 | 6 | // Here we're importing the `alert` function from the browser, using 7 | // `#[wasm_bindgen]` to generate correct wrappers. 8 | #[wasm_bindgen] 9 | extern { 10 | fn alert(s: &str); 11 | } 12 | 13 | // Here we're exporting a function called `greet` which will display a greeting 14 | // for `name` through a dialog. 15 | #[wasm_bindgen] 16 | pub fn greet(name: &str) { 17 | alert(&format!("Hello, {}!", name)); 18 | } 19 | -------------------------------------------------------------------------------- /templates/hello_world_rust/src/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /templates/hello_world_rust/src/main.js: -------------------------------------------------------------------------------- 1 | const { greet } = wasm_bindgen; 2 | 3 | function runApp() { 4 | greet('World'); 5 | } 6 | 7 | // Load and instantiate the wasm file, and we specify the source of the wasm 8 | // file here. Once the returned promise is resolved we're ready to go and 9 | // use our imports. 10 | wasm_bindgen('../out/main_bg.wasm').then(runApp).catch(console.error); 11 | -------------------------------------------------------------------------------- /test-preprocessor.js: -------------------------------------------------------------------------------- 1 | const tsc = require('typescript'); 2 | const tsConfig = require('./tsconfig.test.json'); 3 | 4 | module.exports = { 5 | process(src, path) { 6 | if (path.endsWith('.ts') || path.endsWith('.tsx') || path.endsWith('.js')) { 7 | return tsc.transpile(src, tsConfig.compilerOptions, path, []); 8 | } 9 | return src; 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /test-setup.js: -------------------------------------------------------------------------------- 1 | const enzyme = require("enzyme"); 2 | const Adapter = require("enzyme-adapter-react-16"); 3 | 4 | enzyme.configure({ adapter: new Adapter() }); 5 | 6 | // Make sure any console.error calls from React results in an error 7 | const errorReporter = jest.spyOn(console, "error"); 8 | errorReporter.mockImplementation((error) => { throw error }); 9 | -------------------------------------------------------------------------------- /test-shim.js: -------------------------------------------------------------------------------- 1 | global.requestAnimationFrame = function(callback) { 2 | setTimeout(callback, 0); 3 | }; 4 | 5 | global.Worker = function() { 6 | this.addEventListener = function () { 7 | // Nop 8 | } 9 | } 10 | 11 | global.monaco = { 12 | editor: { 13 | onDidChangeContent() { }, 14 | getLineMaxColumn() { }, 15 | applyEdits() { }, 16 | setValue() { }, 17 | getValue() { }, 18 | toString() { }, 19 | onDidFocusEditorText() { }, 20 | onDidFocusEditorWidget() { }, 21 | onContextMenu() { }, 22 | setModelLanguage() { }, 23 | setModelMarkers() { }, 24 | addAction() { }, 25 | addCommand() { }, 26 | setModel() {}, 27 | getLineCount() {}, 28 | revealLine() {}, 29 | restoreViewState() { }, 30 | saveViewState() { }, 31 | updateOptions() { }, 32 | layout() {}, 33 | createModel() { 34 | return this; 35 | }, 36 | create() { 37 | return this; 38 | }, 39 | getModel() { 40 | return this; 41 | }, 42 | IEditorConstructionOptions: { 43 | value: String 44 | }, 45 | uri: { 46 | toString: () => "uri" 47 | }, 48 | defineTheme() { }, 49 | 50 | }, 51 | Range: function (l1, c1, l2, c2) { 52 | this.r = [l1, c1, l2, c2]; 53 | }, 54 | languages: { 55 | CompletionItemKind: { 56 | Keyword: 12 57 | }, 58 | typescript: { 59 | getTypeScriptWorker() { }, 60 | typescriptDefaults: { 61 | addExtraLib() {}, 62 | setCompilerOptions() {} 63 | }, 64 | javascriptDefaults: { 65 | setCompilerOptions() {} 66 | } 67 | }, 68 | register() {}, 69 | onLanguage() {}, 70 | setMonarchTokensProvider() {}, 71 | setLanguageConfiguration() {}, 72 | registerCompletionItemProvider() {}, 73 | registerHoverProvider() {}, 74 | 75 | }, 76 | KeyMod: { 77 | CtrlCmd: 0, 78 | Alt: 2 79 | }, 80 | KeyCode: { 81 | KEY_S: 83, 82 | KEY_B: 66, 83 | Enter: 13, 84 | }, 85 | MarkerSeverity: { 86 | Info: 2, 87 | Warning: 4, 88 | Error: 8 89 | }, 90 | Promise: { 91 | as: (args) => Promise.resolve(args) 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /tests/actions/ArcActions/ArcActions.spec.ts: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | import * as React from "react"; 5 | import { RunTaskExternals } from "../../../src/utils/taskRunner"; 6 | 7 | const pushStatus = jest.fn(); 8 | const popStatus = jest.fn(); 9 | const runTask = jest.fn(); 10 | const notifyAboutFork = jest.fn(); 11 | 12 | jest.mock("../../../src/actions/AppActions", () => ({ pushStatus, popStatus, runTask })); 13 | jest.mock("../../../src/arc", () => ({ notifyAboutFork })); 14 | 15 | import { publishArc, notifyArcAboutFork } from "../../../src/actions/ArcActions"; 16 | 17 | describe("ArcActions tests", () => { 18 | afterAll(() => { 19 | jest.unmock("../../../src/actions/AppActions"); 20 | jest.unmock("../../../src/arc"); 21 | }); 22 | it("should publish arc project on action: publishArc", async () => { 23 | await publishArc(); 24 | expect(pushStatus).toHaveBeenCalledWith("Previewing Arc Project"); 25 | expect(runTask).toHaveBeenCalledWith("publish", false, RunTaskExternals.Arc); 26 | expect(popStatus).toHaveBeenCalled(); 27 | }); 28 | it("should notify arc about fork on action: notifyArcAboutFork", () => { 29 | const fiddle = "fiddle"; 30 | notifyArcAboutFork(fiddle); 31 | expect(notifyAboutFork).toHaveBeenCalledWith(fiddle); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /tests/compilerServices/createCompilerService.spec.ts: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | import { createCompilerService, Language } from "../../src/compilerServices"; 5 | import { RustService } from "../../src/compilerServices/rustService"; 6 | import { ClangService } from "../../src/compilerServices/clangService"; 7 | import { X86Service } from "../../src/compilerServices/x86Service"; 8 | 9 | describe("Tests for createCompilerService", () => { 10 | it("should be able to create a RustService (Rust -> Wasm)", async () => { 11 | const service = await createCompilerService(Language.Rust, Language.Wasm); 12 | expect(service).toBeInstanceOf(RustService); 13 | }); 14 | it("should be able to create a ClangService (C -> Wasm)", async () => { 15 | const service = await createCompilerService(Language.C, Language.Wasm); 16 | expect(service).toBeInstanceOf(ClangService); 17 | }); 18 | it("should be able to create a ClangService (C++ -> Wasm)", async () => { 19 | const service = await createCompilerService(Language.Cpp, Language.Wasm); 20 | expect(service).toBeInstanceOf(ClangService); 21 | }); 22 | it("should be able to create a X86Service (Wasm -> x86)", async () => { 23 | const service = await createCompilerService(Language.Wasm, Language.x86); 24 | expect(service).toBeInstanceOf(X86Service); 25 | }); 26 | it("should throw an error for non supported from/to languages", async () => { 27 | await expect(createCompilerService(Language.TypeScript, Language.JavaScript)) 28 | .rejects 29 | .toThrow("createCompilerService: not supported typescript->javascript"); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /tests/compilerServices/utils.spec.ts: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | const isZlibData = jest.fn(); 5 | const decompressZlib = jest.fn(); 6 | const fromByteArray = jest.fn(); 7 | const decodeRestrictedBase64ToBytes = jest.fn(); 8 | 9 | jest.mock("../../src/utils/zlib", () => ({ 10 | isZlibData, 11 | decompressZlib 12 | })); 13 | 14 | jest.mock("../../src/util", () => ({ 15 | decodeRestrictedBase64ToBytes 16 | })); 17 | 18 | jest.mock("base64-js", () => ({ 19 | fromByteArray 20 | })); 21 | 22 | import { decodeBinary, encodeBinary } from "../../src/compilerServices/utils"; 23 | 24 | describe("Tests for compilerServices utils", () => { 25 | afterAll(() => { 26 | jest.unmock("../../src/utils/zlib"); 27 | jest.unmock("../../src/util"); 28 | jest.unmock("base64-js"); 29 | }); 30 | describe("decodeBinary", () => { 31 | it("should decode Binary -> ArrayBuffer", async () => { 32 | const data = { buffer: new ArrayBuffer(8) }; 33 | isZlibData.mockImplementation(() => false); 34 | decodeRestrictedBase64ToBytes.mockImplementation(() => data); 35 | await expect(decodeBinary("binary-string")).resolves.toBe(data.buffer); 36 | expect(decodeRestrictedBase64ToBytes).toHaveBeenCalledWith("binary-string"); 37 | expect(isZlibData).toHaveBeenCalledWith(data); 38 | expect(decompressZlib).not.toHaveBeenCalled(); 39 | isZlibData.mockClear(); 40 | }); 41 | it("should decode Binary -> ArrayBuffer (zlib)", async () => { 42 | const data = { buffer: new ArrayBuffer(8) }; 43 | isZlibData.mockImplementation(() => true); 44 | decodeRestrictedBase64ToBytes.mockImplementation(() => data); 45 | decompressZlib.mockImplementation((arg) => arg); 46 | await expect(decodeBinary("binary-string")).resolves.toBe(data.buffer); 47 | expect(decompressZlib).toHaveBeenCalledWith(data); 48 | }); 49 | }); 50 | describe("encodeBinary", () => { 51 | it("should encode ArrayBuffer -> Binary", () => { 52 | fromByteArray.mockImplementation((args) => args); 53 | const buffer = new ArrayBuffer(8); 54 | const encoded = encodeBinary(buffer); 55 | expect(encoded).toHaveLength(8); 56 | expect(encoded).toBeInstanceOf(Uint8Array); 57 | }); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /tests/compilerServices/x86Service.spec.ts: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | const sendRequest = jest.fn(); 5 | 6 | jest.mock("../../src/compilerServices/sendRequest", () => ({ 7 | sendRequest: sendRequest.mockImplementation(() => "response"), 8 | ServiceTypes: { Service: 3 } 9 | })); 10 | 11 | jest.mock("../../src/compilerServices/utils", () => ({ 12 | encodeBinary: jest.fn().mockImplementation((args) => args) 13 | })); 14 | 15 | import { createCompilerService, Language } from "../../src/compilerServices"; 16 | 17 | describe("Tests for x86Service", () => { 18 | afterAll(() => { 19 | jest.unmock("../../src/compilerServices/sendRequest"); 20 | jest.unmock("../../src/compilerServices/utils"); 21 | }); 22 | it("should compile Wasm -> x86", async () => { 23 | const x86Service = await createCompilerService(Language.Wasm, Language.x86); 24 | const input = { files: { a: { content: "a" }}, options: "options"}; 25 | const output = await x86Service.compile(input); 26 | expect(sendRequest).toHaveBeenCalledWith("input=a&action=wasm2assembly&options=options", 3); 27 | expect(output).toEqual({ 28 | success: true, 29 | items: { "a.json": { content: "response" }}, 30 | }); 31 | }); 32 | it("should throw an error when trying to compile more than one file", async () => { 33 | const x86Service = await createCompilerService(Language.Wasm, Language.x86); 34 | const input = { files: { a: { content: "a" }, b: { content: "b" }}}; 35 | await expect(x86Service.compile(input)) 36 | .rejects 37 | .toThrow("Supporting compilation of a single file, but 2 file(s) found"); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /tests/components/BrowserNotSupported/BrowserNotSupported.spec.tsx: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | import "jest-enzyme"; 5 | import * as ReactModal from "react-modal"; 6 | import * as React from "react"; 7 | import { shallow } from "enzyme"; 8 | import { BrowserNotSupported } from "../../../src/components/BrowserNotSupported"; 9 | 10 | describe("Tests for BrowserNotSupported", () => { 11 | it("should render correctly", () => { 12 | const wrapper = shallow(); 13 | const modal = wrapper.find(ReactModal); 14 | expect(modal).toHaveProp("isOpen", true); 15 | expect(modal).toHaveProp("contentLabel", "Browser Not Supported"); 16 | expect(modal).toHaveProp("className", "modal"); 17 | expect(modal).toHaveProp("overlayClassName", "overlay"); 18 | expect(modal).toHaveProp("ariaHideApp", false); 19 | expect(modal.childAt(0)).toHaveStyle({ display: "flex", flexDirection: "column", height: "100%" }); 20 | expect(modal.find(".modal-title-bar")).toHaveText("Browser Version Not Supported"); 21 | expect(modal.find(".browser-not-supported-description")).toHaveText("WebAssembly is not available in your browser. Please try using the latest version of Edge, Safari, Chrome or Firefox."); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /tests/components/Editor/EditorView.spec.tsx: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | import "jest-enzyme"; 5 | import * as React from "react"; 6 | import {mount} from "enzyme"; 7 | import {EditorView} from "../../../src/components/editor/Editor"; 8 | import {View} from "../../../src/components/editor"; 9 | import {File, FileType} from "../../../src/models"; 10 | 11 | declare var monaco: { 12 | editor 13 | }; 14 | 15 | describe("Tests for Editor.tsx/EditorView", () => { 16 | const setup = (description?) => { 17 | const file = new File("test.js", FileType.JavaScript); 18 | const view = new View(file); 19 | if (description) { 20 | file.description = description; 21 | } 22 | return mount(); 23 | }; 24 | beforeAll(() => { 25 | // tslint:disable-next-line 26 | jest.spyOn(console, "info").mockImplementation(() => {}); 27 | }); 28 | afterAll(() => { 29 | jest.restoreAllMocks(); 30 | }); 31 | it("should render a status bar if the open file has a description", () => { 32 | const wrapper = setup("test"); 33 | expect(wrapper.find(".status-bar-item")).toHaveText("test"); 34 | expect(wrapper.find(".editor-container").length).toEqual(1); 35 | wrapper.unmount(); 36 | }); 37 | it("should NOT render a status bar if the open file does not have a description", () => { 38 | const wrapper = setup(); 39 | expect(wrapper.find(".status-bar-item").length).toEqual(0); 40 | expect(wrapper.find(".editor-container").length).toEqual(0); 41 | wrapper.unmount(); 42 | }); 43 | it("should reveal the last line of the open file when calling revealLastLine", () => { 44 | const wrapper = setup(); 45 | const instance = wrapper.instance() as EditorView; 46 | const getModelSpy = jest.spyOn(monaco.editor, "getModel"); 47 | const getLineCountSpy = jest.spyOn(monaco.editor, "getLineCount"); 48 | const revealLineSpy = jest.spyOn(monaco.editor, "revealLine"); 49 | instance.revealLastLine(); 50 | expect(getModelSpy).toHaveBeenCalled(); 51 | expect(getLineCountSpy).toHaveBeenCalled(); 52 | expect(revealLineSpy).toHaveBeenCalled(); 53 | wrapper.unmount(); 54 | getModelSpy.mockRestore(); 55 | getLineCountSpy.mockRestore(); 56 | revealLineSpy.mockRestore(); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /tests/components/Header/Header.spec.tsx: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | import "jest-enzyme"; 5 | import * as React from "react"; 6 | import {shallow} from "enzyme"; 7 | import {Header} from "../../../src/components/Header"; 8 | 9 | describe("Tests for Header component", () => { 10 | const setup = () => { 11 | return shallow(
); 12 | }; 13 | it("Header renders correctly", () => { 14 | const header = setup(); 15 | expect(header).toHaveText("WebAssembly Studio"); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /tests/components/NewProjectDialog/__snapshots__/NewProjectDialog.spec.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Tests for NewProjectDialog component should render correctly 1`] = ` 4 | 20 |
29 |
32 | Create New Project 33 |
34 |
35 |
42 |
49 | 54 |
55 |
63 |
71 |
72 |
73 |
74 |
82 |
83 |
97 |
98 | 99 | `; 100 | -------------------------------------------------------------------------------- /tests/components/ShareDialog/ShareDialog.spec.tsx: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | import "jest-enzyme"; 5 | import * as React from "react"; 6 | import { shallow } from "enzyme"; 7 | import { ShareDialog } from "../../../src/components/ShareDialog"; 8 | import { Button } from "../../../src/components/shared/Button"; 9 | 10 | describe("Tests for ShareDialog", () => { 11 | const setup = (props?) => { 12 | return shallow(); 13 | }; 14 | it("should render correctly", () => { 15 | const wrapper = setup({ isOpen: true, fiddle: "fiddle" }); 16 | expect(wrapper).toMatchSnapshot(); 17 | }); 18 | it("should invoke onCancel when clicking the cancel button", () => { 19 | const onCancel = jest.fn(); 20 | const wrapper = setup({ onCancel }); 21 | wrapper.find(Button).simulate("click"); 22 | expect(onCancel).toHaveBeenCalled(); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /tests/components/ShareDialog/__snapshots__/ShareDialog.spec.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Tests for ShareDialog should render correctly 1`] = ` 4 | 20 |
29 |
32 | Share Project 33 |
34 |
42 | 46 | " 49 | /> 50 |
51 |
52 |
59 |
60 |
61 | `; 62 | -------------------------------------------------------------------------------- /tests/components/StatusBar/StatusBar.spec.tsx: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | import "jest-enzyme"; 5 | import * as React from "react"; 6 | import {shallow} from "enzyme"; 7 | import {StatusBar} from "../../../src/components/StatusBar"; 8 | import {initStore} from "../../../src/actions/AppActions"; 9 | import appStore from "../../../src/stores/AppStore"; 10 | 11 | describe("Tests for StatusBar", () => { 12 | const setup = () => { 13 | return shallow(); 14 | }; 15 | beforeAll(() => { 16 | initStore(); 17 | }); 18 | it("should render empty string if project has no status", () => { 19 | const wrapper = setup(); 20 | expect(wrapper).toHaveText(""); 21 | }); 22 | it("should not apply active className if project has no status", () => { 23 | const wrapper = setup(); 24 | expect(wrapper.find(".active")).not.toExist(); 25 | }); 26 | it("should update text and className on status change", () => { 27 | const project = appStore.getProject().getModel(); 28 | const wrapper = setup(); 29 | project.pushStatus("test"); 30 | wrapper.update(); 31 | expect(wrapper).toHaveText("test"); 32 | expect(wrapper.find(".active")).toExist(); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /tests/components/Tabs/Tabs.spec.tsx: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | import "jest-enzyme"; 5 | import * as React from "react"; 6 | import {shallow, mount} from "enzyme"; 7 | import {Button} from "../../../src/components/shared/Button"; 8 | 9 | jest.mock("../../../src/util", () => { 10 | return { 11 | clamp: (x, min, max) => x + min + max 12 | }; 13 | }); 14 | 15 | import {Tabs, Tab} from "../../../src/components/editor/Tabs"; 16 | 17 | describe("Tests for Tabs.tsx/Tabs", () => { 18 | const setup = (props) => { 19 | return shallow({...props.children}); 20 | }; 21 | afterAll(() => { 22 | jest.unmock("../../../src/util"); 23 | }); 24 | it("should render correctly", () => { 25 | const tabA = ; 26 | const tabB = ; 27 | const button =
23 |
24 | `; 25 | 26 | exports[`Tests for Toasts Toast should render correctly when passing the kind prop 1`] = ` 27 |
30 |
33 | 36 | Label 37 | 38 |
46 |
47 | `; 48 | 49 | exports[`Tests for Toasts ToastContainer should render correctly 1`] = ` 50 |
53 | 60 | ToastA 61 | 62 | } 63 | onDismiss={[Function]} 64 | /> 65 | 72 | ToastB 73 | 74 | } 75 | onDismiss={[Function]} 76 | /> 77 | 84 | ToastC 85 | 86 | } 87 | onDismiss={[Function]} 88 | /> 89 |
90 | `; 91 | -------------------------------------------------------------------------------- /tests/components/Toolbar/Toolbar.spec.tsx: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | import "jest-enzyme"; 5 | import * as React from "react"; 6 | import { shallow } from "enzyme"; 7 | import { Toolbar } from "../../../src/components/Toolbar"; 8 | 9 | describe("Tests for Toolbar", () => { 10 | it("should render correctly", () => { 11 | const childA =
; 12 | const childB =
; 13 | const wrapper = shallow( 14 | 15 | {childA} 16 | {childB} 17 | 18 | ); 19 | expect(wrapper).toHaveClassName("toolbar"); 20 | expect(wrapper.childAt(0)).toContainReact(childA); 21 | expect(wrapper.childAt(1)).toContainReact(childB); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /tests/components/View/View.spec.tsx: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | import * as React from "react"; 5 | import {View, ViewType, defaultViewTypeForFileType, isViewFileDirty} from "../../../src/components/editor/View"; 6 | import {File, FileType} from "../../../src/models"; 7 | 8 | describe("Tests for View", () => { 9 | it("should be constructable", () => { 10 | const file = new File("fileA", FileType.Markdown); 11 | const view = new View(file, ViewType.Markdown); 12 | expect(view.file).toBe(file); 13 | expect(view.type).toEqual(ViewType.Markdown); 14 | }); 15 | it("should use ViewType.Editor as default type", () => { 16 | const file = new File("fileA", FileType.JavaScript); 17 | const view = new View(file); 18 | expect(view.type).toEqual(ViewType.Editor); 19 | }); 20 | it("should be clonable", () => { 21 | const file = new File("fileA", FileType.Markdown); 22 | const view = new View(file, ViewType.Markdown); 23 | const clone = view.clone(); 24 | expect(view).not.toBe(clone); 25 | expect(clone.type).toEqual(view.type); 26 | expect(clone.file).toBe(file); 27 | }); 28 | describe("defaultViewTypeForFileType", () => { 29 | it("should return default ViewType for FileType", () => { 30 | expect(defaultViewTypeForFileType(FileType.Markdown)).toEqual(ViewType.Markdown); 31 | expect(defaultViewTypeForFileType(FileType.DOT)).toEqual(ViewType.Viz); 32 | expect(defaultViewTypeForFileType(null)).toEqual(ViewType.Editor); 33 | }); 34 | }); 35 | describe("isViewFileDirty", () => { 36 | it("should return true if the views file is dirty", () => { 37 | const file = new File("file", FileType.JavaScript); 38 | file.isDirty = true; 39 | const view = new View(file); 40 | expect(isViewFileDirty(view)).toEqual(true); 41 | }); 42 | it("should return false if the views file is not dirty", () => { 43 | const file = new File("file", FileType.JavaScript); 44 | const view = new View(file); 45 | expect(isViewFileDirty(view)).toEqual(false); 46 | }); 47 | it("should return false if no view is provided", () => { 48 | expect(isViewFileDirty(null)).toEqual(false); 49 | }); 50 | it("should return false if the view does not have a file", () => { 51 | const view = new View(null); 52 | expect(isViewFileDirty(view)).toEqual(false); 53 | }); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /tests/e2e/EmptyCProject.e2e.ts: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | async function getDirectoryStructure() { 5 | return await page.evaluate((selector) => { 6 | const elements = Array.from(document.querySelectorAll(selector)); 7 | return elements.map(element => element.textContent); 8 | }, "a.label-name"); 9 | } 10 | 11 | async function getRunResults() { 12 | return await page.evaluate((selector) => { 13 | const iframe = document.querySelector(selector); 14 | return iframe.contentWindow.document.body.querySelector("span#container").textContent; 15 | }, "iframe"); 16 | } 17 | 18 | describe("Empty C Project: Create, Build and Run", () => { 19 | beforeAll(async () => { 20 | jest.setTimeout(30000); 21 | await page.goto("https://localhost:28443"); 22 | }); 23 | it("should initialy display the Create New Project dialog", async () => { 24 | await expect(page).toMatch("Empty C Project"); 25 | }); 26 | it("should create an Empty C Project when clicking the Create button", async () => { 27 | await page.click("div.button[title=\"Create\"]"); 28 | await page.waitForSelector("a.label-name"); 29 | await expect(getDirectoryStructure()).resolves.toEqual([ 30 | "README.md", 31 | "build.ts", 32 | "package.json", 33 | "src", 34 | "main.c", 35 | "main.html", 36 | "main.js" 37 | ]); 38 | }); 39 | xit("should build the project when clicking the Build button", async () => { 40 | // Click the build button and wait for the request to finish 41 | await page.click("div.button[title=\"Build Project: CtrlCmd + B\"]"); 42 | await page.waitFor(3000); // TODO: Remove hardcoded wait duration 43 | // Build a second time 44 | await page.click("div.button[title=\"Build Project: CtrlCmd + B\"]"); 45 | await page.waitFor(3000); // TODO: Remove hardcoded wait duration 46 | await expect(getDirectoryStructure()).resolves.toEqual([ 47 | "README.md", 48 | "build.ts", 49 | "package.json", 50 | "src", 51 | "main.c", 52 | "main.html", 53 | "main.js", 54 | "out", 55 | "main.wasm" 56 | ]); 57 | }); 58 | xit("should run the project when clicking the Run button", async () => { 59 | // Click the run button and wait for the results 60 | await page.click("div.button[title=\"Run Project: CtrlCmd + Enter\"]"); 61 | await page.waitFor(1000); // TODO: Remove hardcoded wait duration 62 | await expect(getRunResults()).resolves.toEqual("42"); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /tests/languages/log.spec.ts: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | import { Log } from "../../src/languages/log"; 5 | 6 | describe("Tests for Log", () => { 7 | describe("MonarchTokensProvider", () => { 8 | it("should expose the correct MonarchTokensProvider", () => { 9 | expect(Log.MonarchTokensProvider).toEqual({ 10 | tokenizer: { 11 | root: [ 12 | [/\[error.*/, "custom-error"], 13 | [/\[warn.*/, "custom-warn"], 14 | [/\[notice.*/, "custom-notice"], 15 | [/\[info.*/, "custom-info"] 16 | ] 17 | } 18 | }); 19 | }); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /tests/unit/ModelRef.spec.ts: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | import { ModelRef, File, FileType } from "../../src/models"; 5 | 6 | describe("ModelRef tests", () => { 7 | describe("getRef", () => { 8 | it("should create and return a new reference if it does not already exist", () => { 9 | const file = new File("file", FileType.JavaScript); 10 | const ref = ModelRef.getRef(file); 11 | expect(ref.obj).toBe(file); 12 | }); 13 | it("should return the reference if it already exist", () => { 14 | const file = new File("file", FileType.JavaScript); 15 | const refA = ModelRef.getRef(file); 16 | const refB = ModelRef.getRef(file); 17 | expect(refA).toBe(refB); 18 | }); 19 | }); 20 | describe("getModel", () => { 21 | it("should return the model", () => { 22 | const file = new File("file", FileType.JavaScript); 23 | const ref = ModelRef.getRef(file); 24 | expect(ref.getModel()).toBe(file); 25 | }); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /tests/unit/Problem.spec.ts: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | import { Problem, File, FileType } from "../../src/models"; 5 | 6 | declare var monaco: { MarkerSeverity }; 7 | 8 | describe("Problem tests", () => { 9 | it("should be constructable", () => { 10 | const file = new File("file", FileType.JavaScript); 11 | const description = "problem"; 12 | const severity = "warning"; 13 | const problem = new Problem(file, description, severity); 14 | expect(problem.file).toBe(file); 15 | expect(problem.description).toEqual(description); 16 | expect(problem.severity).toEqual(severity); 17 | }); 18 | it("should be constructable from marker", () => { 19 | const file = new File("file", FileType.JavaScript); 20 | const severity = monaco.MarkerSeverity.Info; 21 | const marker = { message: "test", startLineNumber: 1, startColumn: 1, severity }; 22 | const problem = Problem.fromMarker(file, marker); 23 | expect(problem.file).toBe(file); 24 | expect(problem.description).toEqual("test (1, 1)"); 25 | expect(problem.severity).toEqual("info"); 26 | expect(problem.marker).toBe(marker); 27 | }); 28 | it("should generate a unique key for each problem", () => { 29 | const problemA = new Problem(new File("file", FileType.JavaScript), "", "info"); 30 | const problemB = new Problem(new File("file", FileType.JavaScript), "", "info"); 31 | expect(Number(problemB.key)).toBeGreaterThan(Number(problemA.key)); 32 | }); 33 | it("should convert marker severity (monaco.MarkerSeverity) to string", () => { 34 | const file = new File("file", FileType.JavaScript); 35 | const problemA = Problem.fromMarker(file, { severity: monaco.MarkerSeverity.Info }); 36 | const problemB = Problem.fromMarker(file, { severity: monaco.MarkerSeverity.Warning }); 37 | const problemC = Problem.fromMarker(file, { severity: monaco.MarkerSeverity.Error }); 38 | expect(problemA.severity).toEqual("info"); 39 | expect(problemB.severity).toEqual("warning"); 40 | expect(problemC.severity).toEqual("error"); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /tests/unit/arc.spec.ts: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | import { PublishManifest, notifyAboutFork, Arc } from "../../src/arc"; 5 | 6 | describe("Arc tests", () => { 7 | it("should post a message to window.parent on notifyAboutFork", () => { 8 | const postMessage = jest.spyOn(window.parent, "postMessage"); 9 | const fiddle = "fiddle"; 10 | notifyAboutFork(fiddle); 11 | expect(postMessage).toHaveBeenCalledWith({ 12 | type: "wasm-studio/fork", 13 | fiddle, 14 | }, "*"); 15 | postMessage.mockRestore(); 16 | }); 17 | it("should post a message to window.parent on Arc.publish", () => { 18 | const postMessage = jest.spyOn(window.parent, "postMessage"); 19 | const manifest = {} as PublishManifest; 20 | Arc.publish(manifest); 21 | expect(postMessage).toHaveBeenCalledWith({ 22 | type: "wasm-studio/module-publish", 23 | manifest, 24 | }, "*"); 25 | postMessage.mockRestore(); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /tests/unit/gulpy.spec.ts: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | import { Gulpy } from "../../src/gulpy"; 5 | 6 | describe("Gulpy tests", () => { 7 | it("check gulp dependencies", async () => { 8 | const gulp = new Gulpy(); 9 | let results = ""; 10 | 11 | gulp.task("b", async () => { 12 | await Promise.resolve(); 13 | results += "B"; 14 | }); 15 | 16 | gulp.task("c", [], async () => { 17 | await Promise.resolve(); 18 | await Promise.resolve(); 19 | await Promise.resolve(); 20 | results += "C"; 21 | }); 22 | 23 | gulp.task("a", ["b", "c"], async () => { 24 | results += "A"; 25 | }); 26 | 27 | await gulp.run("a"); 28 | 29 | expect(results).toBe("BCA"); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /tests/unit/splitUtils.spec.ts: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | import * as React from "react"; 5 | import * as splitUtils from "../../src/utils/splitUtils"; 6 | 7 | describe("Tests for splitUtils", () => { 8 | describe("toCSSPx", () => { 9 | it("should transform a number to CSS px value", () => { 10 | expect(splitUtils.toCSSPx(10)).toEqual("10px"); 11 | }); 12 | it("should default to 0px", () => { 13 | expect(splitUtils.toCSSPx(null)).toEqual("0px"); 14 | }); 15 | }); 16 | describe("assignObject", () => { 17 | it("should assign properties", () => { 18 | const to = { a: 1 }; 19 | const from = { b: 2 }; 20 | expect(splitUtils.assignObject(to, from)).toEqual({ a: 1, b: 2}); 21 | }); 22 | it("should only assign non existing properties", () => { 23 | const to = { a: 1 }; 24 | const from = { a: 2, b: 3 }; 25 | expect(splitUtils.assignObject(to, from)).toEqual({ a: 1, b: 3}); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /tests/utils/config.spec.ts: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | import getConfig from "../../src/config"; 5 | 6 | function mockFetchToReturnConfig() { 7 | const config = require("../../config.json"); 8 | (global as any).fetch = jest.fn().mockImplementation(() => Promise.resolve({ 9 | json: () => config 10 | })); 11 | return () => (global as any).fetch = undefined; 12 | } 13 | 14 | describe("Tests for getConfig", () => { 15 | it("should load the config from config.json", async () => { 16 | const restoreFetch = mockFetchToReturnConfig(); 17 | await expect(getConfig()).resolves.toEqual({ 18 | cargo: "//webassembly-studio-rust.herokuapp.com/cargo", 19 | clang: "//webassembly-studio-clang.herokuapp.com/build", 20 | rustc: "//webassembly-studio-rust.herokuapp.com/rustc", 21 | sentryDNS: "https://756ae32005ed49cf9d4dd2aa106ccd4a@sentry.io/1229949", 22 | serviceUrl: "//wasmexplorer-service.herokuapp.com/service.php", 23 | templates: { 24 | arc: "/dist/arc-templates/index.js", 25 | default: "/dist/templates/index.js" 26 | } 27 | }); 28 | expect((global as any).fetch).toHaveBeenCalledWith("./config.json"); 29 | restoreFetch(); 30 | }); 31 | it("should return the config if it is already loaded", async () => { 32 | const restoreFetch = mockFetchToReturnConfig(); 33 | await getConfig(); 34 | expect((global as any).fetch).not.toHaveBeenCalled(); 35 | restoreFetch(); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /tests/utils/fetchTemplates.spec.ts: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | import fetchTemplates from "../../src/utils/fetchTemplates"; 5 | 6 | function mockFetch() { 7 | (global as any).fetch = jest.fn().mockImplementation((arg) => { 8 | return { text: () => JSON.stringify({ a: 1, b: 2 }) }; 9 | }); 10 | return () => (global as any).fetch = undefined; 11 | } 12 | 13 | describe("Tests for fetchTemplates", () => { 14 | it("should fetch a template and parse the JSON response", async () => { 15 | const restoreFetch = mockFetch(); 16 | const response = await fetchTemplates("/dist/templates/index.js"); 17 | expect(response).toEqual({ a: 1, b: 2 }); 18 | expect(window.fetch).toHaveBeenCalledWith("/dist/templates/index.js"); 19 | restoreFetch(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /tests/utils/ga.spec.ts: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | import { gaEvent } from "../../src/utils/ga"; 5 | 6 | describe("Tests for ga (google analytics)", () => { 7 | it("should generate an event", () => { 8 | const gtag = jest.fn(); 9 | (window as any).gtag = gtag; 10 | gaEvent("action", "category", "label", 1); 11 | expect(gtag).toHaveBeenCalledWith("event", "action", { 12 | event_category: "category", 13 | event_label: "label", 14 | value: 1, 15 | }); 16 | }); 17 | it("should not generate an event if window.gtag is not a function", () => { 18 | (window as any).gtag = undefined; 19 | expect(gaEvent("action", "category", "label", 1)).toEqual(undefined); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /tests/utils/group.spec.tsx: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | import Group from "../../src/utils/group"; 5 | import { View } from "../../src/components/editor/View"; 6 | import { File, FileType } from "../../src/models"; 7 | 8 | function generateFiles() { 9 | return { 10 | a: new File("A", FileType.JavaScript), 11 | b: new File("B", FileType.JavaScript), 12 | c: new File("C", FileType.JavaScript) 13 | }; 14 | } 15 | 16 | describe("Tab Group tests", () => { 17 | it("should open a file", () => { 18 | const files = generateFiles(); 19 | const a = new View(files.a); 20 | const b = new View(files.b); 21 | const group = new Group(a, [a, b]); 22 | 23 | group.openFile(files.c); 24 | 25 | expect(group.currentView.file.name).toBe("C"); 26 | expect(group.preview.file.name).toBe("C"); 27 | }); 28 | it("should switch between views", () => { 29 | const files = generateFiles(); 30 | const a = new View(files.a); 31 | const b = new View(files.b); 32 | const group = new Group(a, [a, b]); 33 | 34 | group.openFile(files.c); 35 | expect(group.currentView.file.name).toBe("C"); 36 | 37 | group.open(a); 38 | 39 | expect(group.currentView.file.name).toBe("A"); 40 | expect(group.preview.file.name).toBe("C"); 41 | }); 42 | it("should close a view", () => { 43 | const files = generateFiles(); 44 | const a = new View(files.a); 45 | const b = new View(files.b); 46 | const group = new Group(a, [a, b]); 47 | 48 | group.openFile(files.c); 49 | group.close(group.preview); 50 | 51 | expect(group.currentView.file.name).toBe("B"); 52 | expect(group.preview).toBe(null); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /tests/utils/registerTheme.spec.ts: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | import registerTheme from "../../src/utils/registerTheme"; 5 | 6 | declare var monaco: { editor }; 7 | 8 | describe("Tests for registerTheme", () => { 9 | it("should register a correct theme", async () => { 10 | const defineTheme = jest.spyOn(monaco.editor, "defineTheme"); 11 | await registerTheme(); 12 | expect(defineTheme).toHaveBeenCalledWith("fiddle-theme", { 13 | base: "vs-dark", 14 | inherit: true, 15 | rules: [ 16 | { token: "custom-info", foreground: "d4d4d4" }, 17 | { token: "custom-warn", foreground: "ff9900" }, 18 | { token: "custom-error", background: "00ff00", foreground: "ff0000", fontStyle: "bold" } 19 | ] 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /tests/utils/rewriteSources.spec.tsx: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | import { 5 | rewriteHTML, rewriteJS, RewriteSourcesContext 6 | } from "../../src/utils/rewriteSources"; 7 | 8 | class ProjectMock { 9 | public files: any; 10 | constructor() { 11 | this.files = Object.create(null); 12 | } 13 | getFile(name: string) { 14 | return this.files[name]; 15 | } 16 | setFile(name: string, data: string) { 17 | this.files[name] = { 18 | getData() { 19 | return data; 20 | }, 21 | }; 22 | } 23 | toProject() { 24 | return this as any; 25 | } 26 | } 27 | 28 | describe("Rewrite sources tests", () => { 29 | it("html not changed", () => { 30 | const projectStub = new ProjectMock(); 31 | projectStub.setFile("main.html", "test"); 32 | 33 | const context = new RewriteSourcesContext(projectStub.toProject()); 34 | const srcHTML = rewriteHTML(context, "main.html"); 35 | 36 | expect(srcHTML).toBe("test"); 37 | }); 38 | it("html changed", () => { 39 | const projectStub = new ProjectMock(); 40 | projectStub.setFile("main.html", 41 | "test"); 42 | projectStub.setFile("test.js", "void 0"); 43 | 44 | const context = new RewriteSourcesContext(projectStub.toProject()); 45 | context.createFile = (content: ArrayBuffer|string, type: string): string => { 46 | expect(content).toBe("void 0"); 47 | return "fake-url:test"; 48 | }; 49 | const srcHTML = rewriteHTML(context, "main.html"); 50 | 51 | expect(srcHTML).toBe("test"); 52 | }); 53 | it("html and js changed", () => { 54 | const projectStub = new ProjectMock(); 55 | projectStub.setFile("main.html", 56 | "test"); 57 | projectStub.setFile("test.js", "import { test } from 'test2.js'; test();"); 58 | projectStub.setFile("test2.js", "void 0"); 59 | 60 | const context = new RewriteSourcesContext(projectStub.toProject()); 61 | context.createFile = (content: ArrayBuffer|string, type: string): string => { 62 | if (content === "void 0") { 63 | return "fake-url:test2"; 64 | } 65 | expect(content).toBe("import { test } from \"fake-url:test2\"; test();"); 66 | return "fake-url:test"; 67 | }; 68 | context.logLn = console.error; 69 | const srcHTML = rewriteHTML(context, "main.html"); 70 | 71 | expect(srcHTML).toBe("test"); 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /tests/utils/service.spec.tsx: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | const compile = jest.fn(); 5 | const createCompilerServices = jest.fn(); 6 | 7 | jest.mock("../../src/compilerServices", () => ({ 8 | createCompilerService: createCompilerServices.mockImplementation(async () => ({ 9 | compile: compile.mockImplementation(async () => ({ 10 | success: true, 11 | items: { "a.txt": { content: "text" } } 12 | })) 13 | })), 14 | Language: { 15 | JavaScript: "javascript", 16 | Text: "text", 17 | } 18 | })); 19 | 20 | import { Project, Directory, File, FileType } from "../../src/models"; 21 | import { Service, Language } from "../../src/service"; 22 | 23 | function generateFiles() { 24 | const project = new Project(); 25 | const dir = new Directory("dir"); 26 | project.addFile(dir); 27 | const subdir = new Directory("subdir"); 28 | dir.addFile(subdir); 29 | const a = new File("a.js", FileType.JavaScript); 30 | project.addFile(a); 31 | const b = new File("main.ts", FileType.HTML); 32 | dir.addFile(b); 33 | const c = new File("c.md", FileType.Markdown); 34 | subdir.addFile(c); 35 | return { a, b, c, }; 36 | } 37 | 38 | describe("Service.compileFiles tests", () => { 39 | afterAll(() => { 40 | jest.unmock("../../src/compilerServices"); 41 | }); 42 | 43 | it("should pass full file path", async () => { 44 | const { a, b, c } = generateFiles(); 45 | 46 | const result = await Service.compileFiles([c, a, b], Language.JavaScript, Language.Text); 47 | expect(result["a.txt"]).toBeTruthy(); 48 | expect(createCompilerServices).toHaveBeenCalledTimes(1); 49 | expect(createCompilerServices).toHaveBeenCalledWith(Language.JavaScript, Language.Text); 50 | expect(compile).toHaveBeenCalledTimes(1); 51 | const compileInput = compile.mock.calls[0][0]; 52 | expect(Object.keys(compileInput.files)).toEqual(["dir/subdir/c.md", "a.js", "dir/main.ts"]); 53 | 54 | createCompilerServices.mockReset(); 55 | compile.mockReset(); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /tests/utils/zlib.spec.ts: -------------------------------------------------------------------------------- 1 | /* Any copyright is dedicated to the Public Domain. 2 | * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 | 4 | const pako = { inflate: jest.fn(() => "inflated") }; 5 | jest.mock("pako", () => pako); 6 | 7 | import { isZlibData, decompressZlib } from "../../src/utils/zlib"; 8 | 9 | describe("Tests for zlib", () => { 10 | afterAll(() => { 11 | jest.restoreAllMocks(); 12 | }); 13 | describe("isZlibData", () => { 14 | it("should tell if the given data is zlib compressed", () => { 15 | const dataA = new Uint8Array([0x78, 0x01]); 16 | const dataB = new Uint8Array([0x78, 0x9C]); 17 | const dataC = new Uint8Array([0x78, 0xDA]); 18 | const dataD = new Uint8Array([0x78, 0]); 19 | const dataE = new Uint8Array([0x01, 0x01]); 20 | expect(isZlibData(dataA)).toEqual(true); 21 | expect(isZlibData(dataB)).toEqual(true); 22 | expect(isZlibData(dataC)).toEqual(true); 23 | expect(isZlibData(dataD)).toEqual(false); 24 | expect(isZlibData(dataE)).toEqual(false); 25 | }); 26 | }); 27 | describe("decompressZlib", () => { 28 | it("should decompress the given data", async () => { 29 | const data = new Uint8Array([0x78, 0x01]); 30 | const decompressed = await decompressZlib(data); 31 | expect(decompressed).toEqual("inflated"); 32 | expect(pako.inflate).toHaveBeenCalledWith(data); 33 | }); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./dist/", 4 | "sourceMap": true, 5 | "noImplicitAny": true, 6 | "skipLibCheck": true, 7 | "module": "esnext", 8 | "moduleResolution": "node", 9 | "target": "esnext", 10 | "lib": ["dom", "esnext", "es2017.object"], 11 | "jsx": "react", 12 | "declaration": true, 13 | "removeComments": false 14 | }, 15 | "include": [ 16 | "./src/**/*", 17 | "node_modules/monaco-editor/monaco.d.ts" 18 | ], 19 | "exclude": [ 20 | "./templates/**/*" 21 | ] 22 | } -------------------------------------------------------------------------------- /tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noImplicitAny": true, 4 | "skipLibCheck": true, 5 | "module": "commonjs", 6 | "target": "es6", 7 | "lib": ["dom", "es6"], 8 | "jsx": "react", 9 | "declaration": true, 10 | "inlineSourceMap": true, 11 | "allowSyntheticDefaultImports": true 12 | }, 13 | "include": [ 14 | "./tests/**/*", 15 | "node_modules/monaco-editor/monaco.d.ts" 16 | ], 17 | "exclude": [ 18 | "./templates/**/*" 19 | ] 20 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint:recommended", 5 | "tslint-react" 6 | ], 7 | "linterOptions": { 8 | "exclude": [ 9 | "src/languages/*.ts", 10 | "src/monaco-extra.ts", 11 | "lib/**/*.ts" 12 | ] 13 | }, 14 | "jsRules": {}, 15 | "rules": { 16 | "no-string-literal": false, 17 | "semicolon": [true, "always"], 18 | "no-bitwise": false, 19 | "interface-name": [true, "always-prefix"], 20 | "ban-types": false, 21 | "max-classes-per-file": false, 22 | "only-arrow-functions": false, 23 | "member-ordering": false, 24 | "no-console": false, 25 | "object-literal-sort-keys": false, 26 | "no-var-requires": false, 27 | "prefer-for-of": false, 28 | "trailing-comma": false, 29 | "no-eval": false, 30 | "max-line-length": [true, { "ignore-pattern": "" }], 31 | "no-shadowed-variable": false, 32 | "no-conditional-assignment": false, 33 | "member-access": false, 34 | "ordered-imports": false, 35 | "arrow-parens": false, 36 | "interface-name": false, 37 | "object-literal-shorthand": false, 38 | "no-empty-interface": false, 39 | "variable-name": [true, "check-format", "allow-leading-underscore", "allow-pascal-case"], 40 | "jsx-wrap-multiline": false, 41 | "jsx-no-multiline-js": false, 42 | "jsx-no-lambda": false, 43 | "jsx-boolean-value": false, 44 | "file-header": [true, "(Mozilla Foundation|the Public Domain)"], 45 | "no-namespace": false, 46 | "no-unused-expression": false 47 | }, 48 | "rulesDirectory": [] 49 | } 50 | -------------------------------------------------------------------------------- /web-assembly-icon-white-64px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wasdk/WebAssemblyStudio/5eda37b478139dba782974aed2bf8354bc01310a/web-assembly-icon-white-64px.png --------------------------------------------------------------------------------