wasm-idle 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,6 +18,7 @@ export default class Clang {
18
18
  log: boolean;
19
19
  lastCode: string;
20
20
  path: string;
21
+ wasm?: WebAssembly.Instance;
21
22
  constructor(options: APIOption);
22
23
  hostLog(message: string): void;
23
24
  hostLogAsync(message: string, promise: Promise<any>): Promise<any>;
@@ -25,6 +26,7 @@ export default class Clang {
25
26
  compile(options: any): Promise<App | null>;
26
27
  link(obj: string, wasm: string): Promise<App | null>;
27
28
  run(module: WebAssembly.Module, out: boolean, ...args: string[]): Promise<App | null>;
29
+ compileLink(code: string): Promise<any>;
28
30
  compileLinkRun(code: string): Promise<App | null>;
29
31
  }
30
32
  export {};
@@ -22,6 +22,7 @@ export default class Clang {
22
22
  log;
23
23
  lastCode = '';
24
24
  path;
25
+ wasm;
25
26
  constructor(options) {
26
27
  this.moduleCache = {};
27
28
  this.stdout = options.stdout;
@@ -94,14 +95,16 @@ export default class Clang {
94
95
  this.stdout(`${green}(${start - instantiate}ms/${end - instantiate}ms)${normal}\n`);
95
96
  return stillRunning ? app : null;
96
97
  }
97
- async compileLinkRun(code) {
98
+ async compileLink(code) {
98
99
  const input = `test.cc`, obj = `test.o`, wasm = `test.wasm`;
99
- if (this.lastCode !== code) {
100
- await this.compile({ input, code, obj });
101
- await this.link(obj, wasm);
102
- }
100
+ if (this.lastCode === code)
101
+ return this.wasm;
102
+ await this.compile({ input, code, obj });
103
+ await this.link(obj, wasm);
103
104
  this.lastCode = code;
104
- const testMod = await this.hostLogAsync(`Compiling ${wasm}`, WebAssembly.compile(this.memfs.getFileContents(wasm)));
105
- return await this.run(testMod, true, wasm);
105
+ return this.wasm = await this.hostLogAsync(`Compiling ${wasm}`, WebAssembly.compile(this.memfs.getFileContents(wasm)));
106
+ }
107
+ async compileLinkRun(code) {
108
+ return await this.run(await this.compileLink(code), true, `test.wasm`);
106
109
  }
107
110
  }
@@ -1,7 +1,7 @@
1
1
  import type Sandbox from './sandbox';
2
2
  declare class Clang implements Sandbox {
3
3
  ts: number;
4
- output: null;
4
+ output: any;
5
5
  worker: Worker;
6
6
  buffer: SharedArrayBuffer;
7
7
  interruptBuffer: SharedArrayBuffer;
@@ -13,7 +13,7 @@ declare class Clang implements Sandbox {
13
13
  write(input: string): void;
14
14
  _write(input: string): void;
15
15
  eof(): void;
16
- run(code: string): Promise<string>;
16
+ run(code: string, prepare: boolean): Promise<string>;
17
17
  terminate(): void;
18
18
  clear(): Promise<void>;
19
19
  }
@@ -13,9 +13,7 @@ class Clang {
13
13
  this.internalBuffer = [];
14
14
  if (!this.worker) {
15
15
  this.worker = new (await import('./worker/clang?worker')).default();
16
- this.worker.onmessage = (event) => {
17
- resolve();
18
- };
16
+ this.worker.onmessage = () => resolve();
19
17
  this.worker.postMessage({ load: true, path, log, code });
20
18
  }
21
19
  else
@@ -37,14 +35,12 @@ class Clang {
37
35
  }
38
36
  eof() {
39
37
  }
40
- run(code) {
38
+ run(code, prepare) {
41
39
  return new Promise(async (resolve, reject) => {
42
40
  const interrupt = new Uint8Array(this.interruptBuffer), _uid = ++this.uid;
43
41
  const handler = (event) => {
44
- if (_uid !== this.uid) {
45
- this.worker.onmessage = null;
46
- return;
47
- }
42
+ if (_uid !== this.uid)
43
+ return this.worker.onmessage = null;
48
44
  const { id, output, results, log, error, buffer } = event.data;
49
45
  if (buffer && this.internalBuffer.length)
50
46
  this._write(this.internalBuffer.splice(0, 1)[0]);
@@ -66,6 +62,7 @@ class Clang {
66
62
  this.begin = Date.now();
67
63
  this.worker.postMessage({
68
64
  code,
65
+ prepare,
69
66
  buffer: this.buffer,
70
67
  interrupt: this.interruptBuffer,
71
68
  context: {}
@@ -73,8 +70,7 @@ class Clang {
73
70
  });
74
71
  }
75
72
  terminate() {
76
- const interrupt = new Uint8Array(this.interruptBuffer);
77
- interrupt[0] = 2;
73
+ new Uint8Array(this.interruptBuffer)[0] = 2;
78
74
  }
79
75
  async clear() {
80
76
  this.terminate();
@@ -1,7 +1,7 @@
1
1
  import type Sandbox from './sandbox';
2
2
  declare class Python implements Sandbox {
3
3
  ts: number;
4
- output: null;
4
+ output: any;
5
5
  worker: Worker;
6
6
  buffer: SharedArrayBuffer;
7
7
  interruptBuffer: SharedArrayBuffer;
@@ -13,7 +13,7 @@ declare class Python implements Sandbox {
13
13
  write(input: string): void;
14
14
  _write(input: string): void;
15
15
  eof(): void;
16
- run(code: string): Promise<string>;
16
+ run(code: string, prepare: boolean): Promise<string>;
17
17
  terminate(): void;
18
18
  clear(): Promise<void>;
19
19
  }
@@ -13,9 +13,7 @@ class Python {
13
13
  this.internalBuffer = [];
14
14
  if (!this.worker) {
15
15
  this.worker = new (await import('./worker/python?worker')).default();
16
- this.worker.onmessage = (event) => {
17
- resolve();
18
- };
16
+ this.worker.onmessage = () => resolve();
19
17
  this.worker.postMessage({ load: true, path, log, code });
20
18
  }
21
19
  else
@@ -37,14 +35,12 @@ class Python {
37
35
  }
38
36
  eof() {
39
37
  }
40
- run(code) {
38
+ run(code, prepare) {
41
39
  return new Promise(async (resolve, reject) => {
42
40
  const interrupt = new Uint8Array(this.interruptBuffer), _uid = ++this.uid;
43
41
  const handler = (event) => {
44
- if (_uid !== this.uid) {
45
- this.worker.onmessage = null;
46
- return;
47
- }
42
+ if (_uid !== this.uid)
43
+ return this.worker.onmessage = null;
48
44
  const { id, output, results, log, error, buffer } = event.data;
49
45
  if (buffer && this.internalBuffer.length)
50
46
  this._write(this.internalBuffer.splice(0, 1)[0]);
@@ -66,6 +62,7 @@ class Python {
66
62
  this.begin = Date.now();
67
63
  this.worker.postMessage({
68
64
  code,
65
+ prepare,
69
66
  buffer: this.buffer,
70
67
  interrupt: this.interruptBuffer,
71
68
  context: {}
@@ -2,7 +2,7 @@ interface sandbox {
2
2
  constructor: any;
3
3
  eof: () => void;
4
4
  load: (path: string, code?: string, log?: boolean) => Promise<void>;
5
- run: (code: string) => Promise<string>;
5
+ run: (code: string, prepare: boolean) => Promise<string>;
6
6
  terminate: () => void;
7
7
  clear: () => Promise<void>;
8
8
  }
@@ -26,11 +26,22 @@ async function loadClang(path, log) {
26
26
  });
27
27
  }
28
28
  self.onmessage = async (event) => {
29
- const { code, buffer, load, interrupt, log, path } = event.data;
29
+ const { code, buffer, load, interrupt, log, path, prepare } = event.data;
30
30
  if (load) {
31
31
  await loadClang(path, log);
32
32
  postMessage({ load: true });
33
33
  }
34
+ else if (prepare) {
35
+ stdinBufferClang = new Int32Array(buffer);
36
+ interruptBufferClang = new Uint8Array(interrupt);
37
+ try {
38
+ await clang.compileLink(code);
39
+ self.postMessage({ results: true });
40
+ }
41
+ catch (error) {
42
+ self.postMessage({ error: error.message });
43
+ }
44
+ }
34
45
  else if (code) {
35
46
  stdinBufferClang = new Int32Array(buffer);
36
47
  interruptBufferClang = new Uint8Array(interrupt);
@@ -1,16 +1,34 @@
1
- let stdinBufferPyodide, interruptBufferPyodide, pyodide;
2
- async function loadPyodideAndPackages(path) {
1
+ let stdinBufferPyodide, interruptBufferPyodide, pyodide, path = '';
2
+ async function loadPyodide(path) {
3
+ if (pyodide)
4
+ return;
3
5
  const { loadPyodide } = await import('pyodide');
4
6
  pyodide = await loadPyodide({ indexURL: path + '/pyodide' });
5
7
  }
6
8
  self.onmessage = async (event) => {
7
- const { code, buffer, load, interrupt, path } = event.data;
9
+ const { code, buffer, load, interrupt, path: _p, prepare } = event.data;
8
10
  if (load) {
9
- await loadPyodideAndPackages(path);
10
- await pyodide.loadPackagesFromImports(code);
11
+ path = _p;
12
+ postMessage({ output: 'Loading Pyodide...' });
13
+ await loadPyodide(path);
14
+ postMessage({ output: ' Done.\n\r' });
11
15
  postMessage({ load: true });
12
16
  }
17
+ else if (prepare) {
18
+ postMessage({ output: 'Loading packages...' });
19
+ try {
20
+ await loadPyodide(path);
21
+ await pyodide.loadPackagesFromImports(code);
22
+ postMessage({ output: ' Done.\n\r' });
23
+ self.postMessage({ results: true });
24
+ }
25
+ catch (e) {
26
+ self.postMessage({ error: e.message || 'Unknown error' });
27
+ }
28
+ }
13
29
  else if (code) {
30
+ await loadPyodide(path);
31
+ await pyodide.loadPackagesFromImports(code);
14
32
  const ts = Date.now();
15
33
  stdinBufferPyodide = new Int32Array(buffer);
16
34
  interruptBufferPyodide = new Uint8Array(interrupt);
@@ -57,7 +75,7 @@ self.onmessage = async (event) => {
57
75
  postMessage({ output });
58
76
  };
59
77
  try {
60
- let results = await pyodide.runPythonAsync(`import asyncio
78
+ await pyodide.runPythonAsync(`import asyncio
61
79
  from js import __pyodide__input_${ts}, __pyodide__output_${ts}
62
80
 
63
81
  input = __pyodide__input_${ts}
@@ -69,8 +87,8 @@ __builtins__.print = __pyodide__output_${ts}
69
87
  ${code}`);
70
88
  self.postMessage({ results: true });
71
89
  }
72
- catch (error) {
73
- self.postMessage({ error: error.message });
90
+ catch (e) {
91
+ self.postMessage({ error: e.message || 'Unknown error' });
74
92
  }
75
93
  }
76
94
  };
@@ -1,62 +1,70 @@
1
- <script>import { onMount } from "svelte";
2
- import { Theme, registerAllPlugins } from "./";
3
- import { createEventDispatcher } from "svelte";
1
+ <script>import { Theme, registerAllPlugins } from "./";
4
2
  import { load } from "../playground";
3
+ import { onMount, createEventDispatcher } from "svelte";
5
4
  import "xterm/css/xterm.css";
6
5
  const dispatch = createEventDispatcher();
7
- let ref, clientWidth, clientHeight, term, finish = true, input = "", sandbox, first = true;
8
- const wait = () => new Promise((r) => {
9
- const i = setInterval(() => {
10
- if (term) {
11
- clearInterval(i);
12
- r();
13
- }
14
- }, 100);
15
- });
6
+ export let dark = false, path = "", font = "'D2 coding', monospace";
7
+ let ref, clientWidth, clientHeight, term, finish = true, input = "", sandbox, first = true, tc = 0, plugin, ll = null;
8
+ function wait() {
9
+ return new Promise((r) => {
10
+ const i = setInterval(() => {
11
+ if (term) {
12
+ clearInterval(i);
13
+ r();
14
+ }
15
+ }, 100);
16
+ });
17
+ }
18
+ async function initSandbox(language) {
19
+ let _tc = ++tc;
20
+ await wait();
21
+ if (sandbox)
22
+ await sandbox.clear();
23
+ input = "";
24
+ finish = false;
25
+ if (ll !== language) {
26
+ sandbox = await load(language, path);
27
+ await sandbox.clear();
28
+ ll = language;
29
+ }
30
+ sandbox.output = (output) => _tc === tc && term.write(output.replaceAll("\n", "\r\n"));
31
+ }
32
+ function runSandbox(pr) {
33
+ return pr.then(() => term.write(`\r
34
+ Process finished after ${sandbox.elapse}ms\x1B[?25l`)).catch((msg) => term.write(`\r
35
+ \x1B[1;3;31m${msg}\x1B[?25l`)).finally(() => {
36
+ dispatch("finish");
37
+ finish = true;
38
+ term.options.cursorBlink = false;
39
+ });
40
+ }
41
+ async function initTerm(blink = true) {
42
+ await wait();
43
+ term.options.cursorBlink = blink;
44
+ term.focus();
45
+ if (!first)
46
+ term.write(`\r
47
+ \x1B[0m`);
48
+ first = false;
49
+ }
16
50
  export const terminal = {
17
51
  async clear() {
18
52
  await wait();
19
- term.clear();
20
- term.write(`\x1B[?25l`);
21
- term.write("\x1B[0m");
53
+ term.reset();
54
+ term.write(`\x1B[?25l\x1B[0m\x1B[?25h`);
22
55
  term.options.cursorBlink = false;
23
56
  first = true;
57
+ await new Promise((r) => setTimeout(r, 100));
58
+ },
59
+ async prepare(language, code, log = true) {
60
+ await Promise.all([initSandbox(language).then(() => sandbox.load(path, code, log)), initTerm(false)]);
61
+ await runSandbox(sandbox.run(code, true));
24
62
  },
25
63
  async run(language, code, log = true) {
26
- await wait();
27
- if (sandbox)
28
- await sandbox.clear();
29
- input = "";
30
- finish = false;
31
- sandbox = await load(language, path);
32
- await sandbox.clear();
33
- sandbox.output = (output) => {
34
- term.write(output.replaceAll("\n", "\r\n"));
35
- };
36
- term.options.cursorBlink = true;
37
- if (!first)
38
- term.write(`\r
39
- \x1B[0m`);
40
- await sandbox.load(path, code, log);
41
- term.focus();
42
- first = false;
43
- sandbox.run(code).then(() => {
44
- dispatch("finish");
45
- finish = true;
46
- term.write(`\r
47
- Process finished after ${sandbox.elapse}ms\r
48
- \x1B[?25l`);
49
- term.options.cursorBlink = false;
50
- }).catch((msg) => {
51
- dispatch("finish");
52
- finish = true;
53
- term.write(`\r
54
- \x1B[1;3;31m${msg}`);
55
- term.options.cursorBlink = false;
56
- });
64
+ await Promise.all([initSandbox(language).then(() => sandbox.load(path, code, log)), initTerm()]);
65
+ await runSandbox(sandbox.run(code, false));
57
66
  }
58
67
  };
59
- export let dark = false, path = "";
60
68
  $:
61
69
  if (term) {
62
70
  if (dark)
@@ -64,23 +72,17 @@ $:
64
72
  else
65
73
  term.options.theme = Theme.Tango_Light;
66
74
  }
67
- let plugin;
68
- $:
69
- if (plugin) {
70
- void 0, clientHeight;
71
- try {
72
- plugin.fit.fit();
73
- } catch (e) {
74
- }
75
- }
75
+ $: {
76
+ void 0, clientHeight;
77
+ plugin?.fit?.fit?.();
78
+ }
76
79
  onMount(() => {
77
80
  import("xterm").then(async ({ Terminal }) => {
78
81
  term = new Terminal({
79
82
  theme: dark ? Theme.Tango_Dark : Theme.Tango_Light,
80
83
  cursorBlink: false,
81
84
  allowTransparency: true,
82
- fontFamily: "'D2 coding', monospace",
83
- fontWeight: "bold",
85
+ fontFamily: font,
84
86
  allowProposedApi: true
85
87
  });
86
88
  term.open(ref);
@@ -96,9 +98,8 @@ onMount(() => {
96
98
  } else if (ev.key === "Backspace") {
97
99
  if (term._core.buffer.x > 0) {
98
100
  term.write("\b \b");
99
- if (input.length > 0) {
101
+ if (input.length > 0)
100
102
  input = input.substring(0, input.length - 1);
101
- }
102
103
  }
103
104
  } else if (printable) {
104
105
  if (e.key >= String.fromCharCode(32) && e.key <= String.fromCharCode(126) || e.key >= "\xA0") {
@@ -117,8 +118,8 @@ onMount(() => {
117
118
  }
118
119
  });
119
120
  plugin = await registerAllPlugins(term);
121
+ dispatch("load");
120
122
  });
121
- dispatch("load");
122
123
  return async () => {
123
124
  term.dispose();
124
125
  if (sandbox)
@@ -2,12 +2,14 @@ import { SvelteComponentTyped } from "svelte";
2
2
  import 'xterm/css/xterm.css';
3
3
  declare const __propDef: {
4
4
  props: {
5
+ dark?: boolean | undefined;
6
+ path?: string | undefined;
7
+ font?: string | undefined;
5
8
  terminal?: {
6
9
  clear(): Promise<void>;
10
+ prepare(language: any, code: any, log?: boolean): Promise<void>;
7
11
  run(language: any, code: any, log?: boolean): Promise<void>;
8
12
  } | undefined;
9
- dark?: boolean | undefined;
10
- path?: string | undefined;
11
13
  };
12
14
  events: {
13
15
  finish: CustomEvent<any>;
@@ -23,6 +25,7 @@ export type TerminalSlots = typeof __propDef.slots;
23
25
  export default class Terminal extends SvelteComponentTyped<TerminalProps, TerminalEvents, TerminalSlots> {
24
26
  get terminal(): {
25
27
  clear(): Promise<void>;
28
+ prepare(language: any, code: any, log?: boolean): Promise<void>;
26
29
  run(language: any, code: any, log?: boolean): Promise<void>;
27
30
  };
28
31
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wasm-idle",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "A simple web app to run C++/Python code in the browser",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -12,7 +12,8 @@
12
12
  "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
13
13
  "lint": "prettier --plugin-search-dir . --check . && eslint .",
14
14
  "format": "prettier --plugin-search-dir . --write .",
15
- "deploy": "svelte-package && npm publish"
15
+ "deploy": "svelte-package && npm publish",
16
+ "page": "pnpm run build && node ./gh-pages.js"
16
17
  },
17
18
  "devDependencies": {
18
19
  "@sveltejs/adapter-auto": "^2.0.0",
@@ -32,7 +33,7 @@
32
33
  "svelte-check": "^3.2.0",
33
34
  "tslib": "^2.5.0",
34
35
  "typescript": "^5.0.4",
35
- "vite": "^4.2.1"
36
+ "vite": "^4.1.4"
36
37
  },
37
38
  "dependencies": {
38
39
  "pyodide": "^0.23.1",