wasm-idle 0.3.2 → 0.4.1

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.
Files changed (46) hide show
  1. package/README.md +22 -2
  2. package/dist/clang/app.d.ts +2 -1
  3. package/dist/clang/app.js +166 -137
  4. package/dist/clang/index.d.ts +6 -0
  5. package/dist/clang/index.js +137 -21
  6. package/dist/debug/expression.js +135 -19
  7. package/dist/debug/index.d.ts +1 -1
  8. package/dist/debug/index.js +1 -1
  9. package/dist/debug/language/index.d.ts +1 -0
  10. package/dist/debug/language/index.js +1 -0
  11. package/dist/debug/language/python.d.ts +2 -0
  12. package/dist/debug/language/python.js +14 -0
  13. package/dist/index.d.ts +3 -1
  14. package/dist/index.js +1 -1
  15. package/dist/playground/assetBridge.d.ts +20 -0
  16. package/dist/playground/assetBridge.js +192 -0
  17. package/dist/playground/assets.d.ts +32 -0
  18. package/dist/playground/assets.js +97 -0
  19. package/dist/playground/clang.d.ts +11 -3
  20. package/dist/playground/clang.js +57 -20
  21. package/dist/playground/index.d.ts +2 -1
  22. package/dist/playground/index.js +10 -2
  23. package/dist/playground/java.d.ts +33 -0
  24. package/dist/playground/java.js +161 -0
  25. package/dist/playground/javaStdin.d.ts +8 -0
  26. package/dist/playground/javaStdin.js +323 -0
  27. package/dist/playground/options.d.ts +19 -0
  28. package/dist/playground/options.js +15 -1
  29. package/dist/playground/python.d.ts +21 -6
  30. package/dist/playground/python.js +135 -25
  31. package/dist/playground/sandbox.d.ts +5 -2
  32. package/dist/playground/stdinBuffer.d.ts +7 -0
  33. package/dist/playground/stdinBuffer.js +100 -0
  34. package/dist/playground/teavmConfig.d.ts +3 -0
  35. package/dist/playground/teavmConfig.js +14 -0
  36. package/dist/playground/worker/assets.d.ts +12 -0
  37. package/dist/playground/worker/assets.js +257 -0
  38. package/dist/playground/worker/clang.js +13 -23
  39. package/dist/playground/worker/java.d.ts +1 -0
  40. package/dist/playground/worker/java.js +228 -0
  41. package/dist/playground/worker/python.js +264 -58
  42. package/dist/terminal/Terminal.svelte +98 -18
  43. package/dist/terminal/Terminal.svelte.d.ts +4 -1
  44. package/dist/terminal/theme.js +2 -2
  45. package/dist/terminal/types.d.ts +4 -2
  46. package/package.json +11 -11
@@ -8,6 +8,38 @@ export function evaluateDebugExpression(expression, variables) {
8
8
  values.set(variable.name, variable.value);
9
9
  const parsedValues = new Map();
10
10
  const tokens = [];
11
+ const parseQuotedValue = (text, start) => {
12
+ const quote = text[start];
13
+ if (quote !== "'" && quote !== '"')
14
+ throw new Error('expected quoted string');
15
+ let index = start + 1;
16
+ let value = '';
17
+ while (index < text.length) {
18
+ const character = text[index];
19
+ if (!character)
20
+ break;
21
+ if (character === '\\') {
22
+ const escaped = text[index + 1];
23
+ if (!escaped)
24
+ throw new Error('unterminated string literal');
25
+ if (escaped === 'n')
26
+ value += '\n';
27
+ else if (escaped === 'r')
28
+ value += '\r';
29
+ else if (escaped === 't')
30
+ value += '\t';
31
+ else
32
+ value += escaped;
33
+ index += 2;
34
+ continue;
35
+ }
36
+ if (character === quote)
37
+ return { value, next: index + 1 };
38
+ value += character;
39
+ index += 1;
40
+ }
41
+ throw new Error('unterminated string literal');
42
+ };
11
43
  for (let index = 0; index < source.length;) {
12
44
  const character = source[index];
13
45
  if (!character)
@@ -32,6 +64,12 @@ export function evaluateDebugExpression(expression, variables) {
32
64
  index += operator.length;
33
65
  continue;
34
66
  }
67
+ if (character === "'" || character === '"') {
68
+ const parsed = parseQuotedValue(source, index);
69
+ tokens.push({ type: 'string', value: parsed.value });
70
+ index = parsed.next;
71
+ continue;
72
+ }
35
73
  const number = source.slice(index).match(/^\d+(?:\.\d+)?/);
36
74
  if (number?.[0]) {
37
75
  tokens.push({ type: 'number', value: number[0] });
@@ -40,8 +78,26 @@ export function evaluateDebugExpression(expression, variables) {
40
78
  }
41
79
  const identifier = source.slice(index).match(/^[A-Za-z_]\w*/);
42
80
  if (identifier?.[0]) {
43
- if (identifier[0] === 'true' || identifier[0] === 'false') {
44
- tokens.push({ type: 'boolean', value: identifier[0] === 'true' });
81
+ if (identifier[0] === 'true' ||
82
+ identifier[0] === 'false' ||
83
+ identifier[0] === 'True' ||
84
+ identifier[0] === 'False') {
85
+ tokens.push({
86
+ type: 'boolean',
87
+ value: identifier[0] === 'true' || identifier[0] === 'True'
88
+ });
89
+ }
90
+ else if (identifier[0] === 'null' || identifier[0] === 'None') {
91
+ tokens.push({ type: 'null' });
92
+ }
93
+ else if (identifier[0] === 'and') {
94
+ tokens.push({ type: 'operator', value: '&&' });
95
+ }
96
+ else if (identifier[0] === 'or') {
97
+ tokens.push({ type: 'operator', value: '||' });
98
+ }
99
+ else if (identifier[0] === 'not') {
100
+ tokens.push({ type: 'operator', value: '!' });
45
101
  }
46
102
  else {
47
103
  tokens.push({ type: 'identifier', value: identifier[0] });
@@ -81,16 +137,44 @@ export function evaluateDebugExpression(expression, variables) {
81
137
  throw new Error('unsupported array preview');
82
138
  }
83
139
  }
84
- if (character === "'") {
85
- const end = text.indexOf("'", index + 1);
86
- if (end === -1)
87
- throw new Error('unsupported char preview');
88
- return { value: text.slice(index + 1, end), next: end + 1 };
140
+ if (character === '(') {
141
+ index += 1;
142
+ const items = [];
143
+ while (true) {
144
+ while (/\s/.test(text[index] || ''))
145
+ index += 1;
146
+ if (text[index] === ')')
147
+ return { value: items, next: index + 1 };
148
+ if (text.startsWith('...', index))
149
+ throw new Error('unavailable');
150
+ const item = parsePreviewValue(text, index);
151
+ items.push(item.value);
152
+ index = item.next;
153
+ while (/\s/.test(text[index] || ''))
154
+ index += 1;
155
+ if (text[index] === ',') {
156
+ index += 1;
157
+ continue;
158
+ }
159
+ if (text[index] === ')')
160
+ return { value: items, next: index + 1 };
161
+ throw new Error('unsupported tuple preview');
162
+ }
89
163
  }
164
+ if (character === "'" || character === '"')
165
+ return parseQuotedValue(text, index);
90
166
  if (text.startsWith('true', index))
91
167
  return { value: true, next: index + 4 };
92
168
  if (text.startsWith('false', index))
93
169
  return { value: false, next: index + 5 };
170
+ if (text.startsWith('True', index))
171
+ return { value: true, next: index + 4 };
172
+ if (text.startsWith('False', index))
173
+ return { value: false, next: index + 5 };
174
+ if (text.startsWith('null', index))
175
+ return { value: null, next: index + 4 };
176
+ if (text.startsWith('None', index))
177
+ return { value: null, next: index + 4 };
94
178
  const number = text.slice(index).match(/^-?\d+(?:\.\d+)?/);
95
179
  if (number?.[0])
96
180
  return { value: Number(number[0]), next: index + number[0].length };
@@ -102,17 +186,24 @@ export function evaluateDebugExpression(expression, variables) {
102
186
  const value = values.get(name);
103
187
  if (value == null || value === '?')
104
188
  throw new Error('unavailable');
105
- if (value === 'true' || value === 'false') {
106
- const parsed = value === 'true';
189
+ if (value === 'true' || value === 'false' || value === 'True' || value === 'False') {
190
+ const parsed = value === 'true' || value === 'True';
107
191
  parsedValues.set(name, parsed);
108
192
  return parsed;
109
193
  }
194
+ if (value === 'null' || value === 'None') {
195
+ parsedValues.set(name, null);
196
+ return null;
197
+ }
110
198
  const numeric = Number(value);
111
199
  if (!Number.isNaN(numeric)) {
112
200
  parsedValues.set(name, numeric);
113
201
  return numeric;
114
202
  }
115
- if (value.startsWith('[')) {
203
+ if (value.startsWith('[') ||
204
+ value.startsWith('(') ||
205
+ value.startsWith("'") ||
206
+ value.startsWith('"')) {
116
207
  const parsed = parsePreviewValue(value).value;
117
208
  parsedValues.set(name, parsed);
118
209
  return parsed;
@@ -131,10 +222,21 @@ export function evaluateDebugExpression(expression, variables) {
131
222
  cursor += 1;
132
223
  return token.value;
133
224
  }
225
+ if (token.type === 'null') {
226
+ cursor += 1;
227
+ return null;
228
+ }
229
+ if (token.type === 'string') {
230
+ cursor += 1;
231
+ return token.value;
232
+ }
134
233
  if (token.type === 'identifier') {
135
234
  cursor += 1;
136
235
  let resolved = resolveIdentifierValue(token.value);
137
- while (tokens[cursor]?.type === 'bracket' && tokens[cursor]?.value === '[') {
236
+ while (true) {
237
+ const bracket = tokens[cursor];
238
+ if (!bracket || bracket.type !== 'bracket' || bracket.value !== '[')
239
+ break;
138
240
  cursor += 1;
139
241
  const index = Number(parseOr());
140
242
  const closing = tokens[cursor];
@@ -201,8 +303,14 @@ export function evaluateDebugExpression(expression, variables) {
201
303
  return left;
202
304
  cursor += 1;
203
305
  const right = parseMul();
204
- if (operator.value === '+')
205
- left = Number(left) + Number(right);
306
+ if (operator.value === '+') {
307
+ if (typeof left === 'string' || typeof right === 'string') {
308
+ left = `${left ?? 'null'}${right ?? 'null'}`;
309
+ }
310
+ else {
311
+ left = Number(left) + Number(right);
312
+ }
313
+ }
206
314
  if (operator.value === '-')
207
315
  left = Number(left) - Number(right);
208
316
  }
@@ -215,14 +323,16 @@ export function evaluateDebugExpression(expression, variables) {
215
323
  return left;
216
324
  cursor += 1;
217
325
  const right = parseAdd();
326
+ const leftValue = typeof left === 'string' && typeof right === 'string' ? left : Number(left);
327
+ const rightValue = typeof left === 'string' && typeof right === 'string' ? right : Number(right);
218
328
  if (operator.value === '<')
219
- left = Number(left) < Number(right);
329
+ left = leftValue < rightValue;
220
330
  if (operator.value === '<=')
221
- left = Number(left) <= Number(right);
331
+ left = leftValue <= rightValue;
222
332
  if (operator.value === '>')
223
- left = Number(left) > Number(right);
333
+ left = leftValue > rightValue;
224
334
  if (operator.value === '>=')
225
- left = Number(left) >= Number(right);
335
+ left = leftValue >= rightValue;
226
336
  }
227
337
  };
228
338
  const parseEquality = () => {
@@ -241,7 +351,10 @@ export function evaluateDebugExpression(expression, variables) {
241
351
  };
242
352
  const parseAnd = () => {
243
353
  let left = parseEquality();
244
- while (tokens[cursor]?.type === 'operator' && tokens[cursor]?.value === '&&') {
354
+ while (true) {
355
+ const operator = tokens[cursor];
356
+ if (!operator || operator.type !== 'operator' || operator.value !== '&&')
357
+ break;
245
358
  cursor += 1;
246
359
  left = Boolean(left) && Boolean(parseEquality());
247
360
  }
@@ -249,7 +362,10 @@ export function evaluateDebugExpression(expression, variables) {
249
362
  };
250
363
  const parseOr = () => {
251
364
  let left = parseAnd();
252
- while (tokens[cursor]?.type === 'operator' && tokens[cursor]?.value === '||') {
365
+ while (true) {
366
+ const operator = tokens[cursor];
367
+ if (!operator || operator.type !== 'operator' || operator.value !== '||')
368
+ break;
253
369
  cursor += 1;
254
370
  left = Boolean(left) || Boolean(parseAnd());
255
371
  }
@@ -1,5 +1,5 @@
1
1
  export { evaluateDebugExpression } from './expression';
2
2
  export { selectInlineDebugLocals } from './locals';
3
- export { cppDebugLanguageAdapter } from './language';
3
+ export { cppDebugLanguageAdapter, pythonDebugLanguageAdapter } from './language';
4
4
  export { MonacoDebugView } from './editor';
5
5
  export type { DebugLanguageAdapter } from './language';
@@ -1,4 +1,4 @@
1
1
  export { evaluateDebugExpression } from './expression';
2
2
  export { selectInlineDebugLocals } from './locals';
3
- export { cppDebugLanguageAdapter } from './language';
3
+ export { cppDebugLanguageAdapter, pythonDebugLanguageAdapter } from './language';
4
4
  export { MonacoDebugView } from './editor';
@@ -1,2 +1,3 @@
1
1
  export { cppDebugLanguageAdapter } from './cpp';
2
+ export { pythonDebugLanguageAdapter } from './python';
2
3
  export type { DebugLanguageAdapter } from './types';
@@ -1 +1,2 @@
1
1
  export { cppDebugLanguageAdapter } from './cpp';
2
+ export { pythonDebugLanguageAdapter } from './python';
@@ -0,0 +1,2 @@
1
+ import type { DebugLanguageAdapter } from './types';
2
+ export declare const pythonDebugLanguageAdapter: DebugLanguageAdapter;
@@ -0,0 +1,14 @@
1
+ import { evaluateDebugExpression } from '../expression';
2
+ const selectInlinePythonLocals = (lineText, locals) => {
3
+ const sanitized = lineText
4
+ .replace(/#.*$/g, ' ')
5
+ .replace(/"(?:\\.|[^"\\])*"/g, ' ')
6
+ .replace(/'(?:\\.|[^'\\])*'/g, ' ');
7
+ const identifiers = new Set(sanitized.match(/[A-Za-z_]\w*/g) || []);
8
+ return locals.filter((variable) => identifiers.has(variable.name));
9
+ };
10
+ export const pythonDebugLanguageAdapter = {
11
+ id: 'python',
12
+ evaluateExpression: evaluateDebugExpression,
13
+ selectInlineLocals: selectInlinePythonLocals
14
+ };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  import Terminal from './terminal';
2
- export { cppDebugLanguageAdapter, evaluateDebugExpression, MonacoDebugView, selectInlineDebugLocals } from './debug';
2
+ export { cppDebugLanguageAdapter, pythonDebugLanguageAdapter, evaluateDebugExpression, MonacoDebugView, selectInlineDebugLocals } from './debug';
3
3
  import playground from './playground';
4
4
  export default Terminal;
5
5
  export { playground };
6
6
  export type { DebugCommand, DebugFrame, DebugSessionEvent, DebugVariable, SandboxExecutionOptions, TerminalControl } from './terminal';
7
+ export type { CompilerDiagnostic } from './playground/options';
8
+ export type { PlaygroundRuntimeAssets, RuntimeAssetConfig, RuntimeAssetLoadRequest, RuntimeAssetLoader, RuntimeAssetLoaderResult } from './playground/assets';
7
9
  export type { DebugLanguageAdapter } from './debug';
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import Terminal from './terminal';
2
- export { cppDebugLanguageAdapter, evaluateDebugExpression, MonacoDebugView, selectInlineDebugLocals } from './debug';
2
+ export { cppDebugLanguageAdapter, pythonDebugLanguageAdapter, evaluateDebugExpression, MonacoDebugView, selectInlineDebugLocals } from './debug';
3
3
  import playground from './playground';
4
4
  export default Terminal;
5
5
  export { playground };
@@ -0,0 +1,20 @@
1
+ import { type ResolvedRuntimeAssetConfig, type RuntimeAssetRuntime } from './assets';
2
+ type ProgressLike = {
3
+ set?: (value: number) => void;
4
+ };
5
+ export declare class WorkerAssetBridge {
6
+ private worker;
7
+ private readonly runtime;
8
+ private config;
9
+ private readonly progress;
10
+ constructor(worker: Worker, runtime: RuntimeAssetRuntime, config: ResolvedRuntimeAssetConfig, progress?: ProgressLike);
11
+ matches(config: ResolvedRuntimeAssetConfig): boolean;
12
+ rebind(worker: Worker, config: ResolvedRuntimeAssetConfig, progress?: ProgressLike): void;
13
+ resetProgress(progress?: ProgressLike): void;
14
+ handleMessage(event: MessageEvent<any>): boolean;
15
+ private respond;
16
+ private loadAsset;
17
+ private normalizeLoaderResult;
18
+ private fetchAsset;
19
+ }
20
+ export {};
@@ -0,0 +1,192 @@
1
+ import { JAVA_RUNTIME_LOAD_ASSETS, PYTHON_RUNTIME_LOAD_ASSETS } from './assets';
2
+ const encoder = new TextEncoder();
3
+ const transferBuffer = (bytes) => bytes.byteOffset === 0 && bytes.byteLength === bytes.buffer.byteLength
4
+ ? bytes.buffer
5
+ : bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
6
+ const expectedAssetsForRuntime = (runtime) => new Set(runtime === 'python' ? [...PYTHON_RUNTIME_LOAD_ASSETS] : [...JAVA_RUNTIME_LOAD_ASSETS]);
7
+ class RuntimeLoadProgress {
8
+ fractions = new Map();
9
+ expectedAssets;
10
+ progress;
11
+ constructor(runtime) {
12
+ this.expectedAssets = expectedAssetsForRuntime(runtime);
13
+ this.reset();
14
+ }
15
+ reset(progress) {
16
+ this.progress = progress;
17
+ this.fractions.clear();
18
+ for (const asset of this.expectedAssets)
19
+ this.fractions.set(asset, 0);
20
+ this.emit();
21
+ }
22
+ update(asset, loaded, total) {
23
+ if (!this.expectedAssets.has(asset))
24
+ return;
25
+ const fraction = total && total > 0 ? Math.min(loaded / total, 1) : loaded > 0 ? 1 : 0;
26
+ this.fractions.set(asset, fraction);
27
+ this.emit();
28
+ }
29
+ emit() {
30
+ if (!this.progress)
31
+ return;
32
+ if (!this.fractions.size)
33
+ return this.progress.set?.(0);
34
+ let total = 0;
35
+ for (const fraction of this.fractions.values())
36
+ total += fraction;
37
+ this.progress.set?.(total / this.fractions.size);
38
+ }
39
+ }
40
+ export class WorkerAssetBridge {
41
+ worker;
42
+ runtime;
43
+ config;
44
+ progress;
45
+ constructor(worker, runtime, config, progress) {
46
+ this.worker = worker;
47
+ this.runtime = runtime;
48
+ this.config = config;
49
+ this.progress = new RuntimeLoadProgress(runtime);
50
+ this.progress.reset(progress);
51
+ }
52
+ matches(config) {
53
+ return (this.config.baseUrl === config.baseUrl &&
54
+ this.config.loader === config.loader &&
55
+ this.config.useAssetBridge === config.useAssetBridge);
56
+ }
57
+ rebind(worker, config, progress) {
58
+ this.worker = worker;
59
+ this.config = config;
60
+ this.progress.reset(progress);
61
+ }
62
+ resetProgress(progress) {
63
+ this.progress.reset(progress);
64
+ }
65
+ handleMessage(event) {
66
+ const assetRequest = event.data?.assetRequest;
67
+ if (assetRequest) {
68
+ void this.respond(assetRequest);
69
+ return true;
70
+ }
71
+ const assetProgress = event.data?.assetProgress;
72
+ if (assetProgress) {
73
+ this.progress.update(assetProgress.asset, assetProgress.loaded, assetProgress.total);
74
+ return true;
75
+ }
76
+ return false;
77
+ }
78
+ async respond(request) {
79
+ try {
80
+ const loaded = await this.loadAsset(request.asset);
81
+ const buffer = transferBuffer(loaded.bytes);
82
+ this.worker.postMessage({
83
+ assetResponse: {
84
+ id: request.id,
85
+ ok: true,
86
+ bytes: buffer,
87
+ mimeType: loaded.mimeType
88
+ }
89
+ }, [buffer]);
90
+ }
91
+ catch (error) {
92
+ this.worker.postMessage({
93
+ assetResponse: {
94
+ id: request.id,
95
+ ok: false,
96
+ error: error instanceof Error ? error.message : String(error)
97
+ }
98
+ });
99
+ }
100
+ }
101
+ async loadAsset(asset) {
102
+ const reportProgress = (loaded, total) => this.progress.update(asset, loaded, total);
103
+ if (this.config.loader) {
104
+ const loaded = await this.normalizeLoaderResult(await this.config.loader({
105
+ runtime: this.runtime,
106
+ asset,
107
+ reportProgress
108
+ }), asset);
109
+ if (loaded)
110
+ return loaded;
111
+ }
112
+ return await this.fetchAsset(new URL(asset, this.config.baseUrl).href, asset);
113
+ }
114
+ async normalizeLoaderResult(result, asset) {
115
+ if (!result)
116
+ return null;
117
+ if (typeof result === 'string' || result instanceof URL) {
118
+ return await this.fetchAsset(String(result), asset);
119
+ }
120
+ if (result instanceof ArrayBuffer) {
121
+ const bytes = new Uint8Array(result);
122
+ this.progress.update(asset, bytes.byteLength, bytes.byteLength);
123
+ return { bytes };
124
+ }
125
+ if (result instanceof Uint8Array) {
126
+ this.progress.update(asset, result.byteLength, result.byteLength);
127
+ return { bytes: result };
128
+ }
129
+ if (result instanceof Blob) {
130
+ const bytes = new Uint8Array(await result.arrayBuffer());
131
+ this.progress.update(asset, bytes.byteLength, bytes.byteLength);
132
+ return { bytes, mimeType: result.type || undefined };
133
+ }
134
+ if ('url' in result && result.url) {
135
+ return await this.fetchAsset(String(result.url), asset);
136
+ }
137
+ if ('data' in result) {
138
+ if (typeof result.data === 'string') {
139
+ const bytes = encoder.encode(result.data);
140
+ this.progress.update(asset, bytes.byteLength, bytes.byteLength);
141
+ return { bytes, mimeType: result.mimeType };
142
+ }
143
+ if (result.data instanceof ArrayBuffer) {
144
+ const bytes = new Uint8Array(result.data);
145
+ this.progress.update(asset, bytes.byteLength, bytes.byteLength);
146
+ return { bytes, mimeType: result.mimeType };
147
+ }
148
+ if (result.data instanceof Uint8Array) {
149
+ this.progress.update(asset, result.data.byteLength, result.data.byteLength);
150
+ return { bytes: result.data, mimeType: result.mimeType };
151
+ }
152
+ const bytes = new Uint8Array(await result.data.arrayBuffer());
153
+ this.progress.update(asset, bytes.byteLength, bytes.byteLength);
154
+ return { bytes, mimeType: result.mimeType || result.data.type || undefined };
155
+ }
156
+ return null;
157
+ }
158
+ async fetchAsset(url, asset) {
159
+ const response = await fetch(url);
160
+ if (!response.ok)
161
+ throw new Error(`Failed to load ${asset}: ${response.status}`);
162
+ const contentLength = Number(response.headers.get('content-length') || 0) || undefined;
163
+ const mimeType = response.headers.get('content-type') || undefined;
164
+ if (!response.body) {
165
+ const bytes = new Uint8Array(await response.arrayBuffer());
166
+ this.progress.update(asset, bytes.byteLength, contentLength ?? bytes.byteLength);
167
+ return { bytes, mimeType };
168
+ }
169
+ const reader = response.body.getReader();
170
+ let receivedLength = 0;
171
+ const chunks = [];
172
+ while (true) {
173
+ const { done, value } = await reader.read();
174
+ if (done)
175
+ break;
176
+ if (!value)
177
+ continue;
178
+ const chunk = Uint8Array.from(value);
179
+ chunks.push(chunk);
180
+ receivedLength += chunk.byteLength;
181
+ this.progress.update(asset, receivedLength, contentLength);
182
+ }
183
+ const bytes = new Uint8Array(receivedLength);
184
+ let position = 0;
185
+ for (const chunk of chunks) {
186
+ bytes.set(chunk, position);
187
+ position += chunk.byteLength;
188
+ }
189
+ this.progress.update(asset, receivedLength, contentLength ?? receivedLength);
190
+ return { bytes, mimeType };
191
+ }
192
+ }
@@ -0,0 +1,32 @@
1
+ export type RuntimeAssetRuntime = 'python' | 'java';
2
+ export interface RuntimeAssetLoadRequest {
3
+ runtime: RuntimeAssetRuntime;
4
+ asset: string;
5
+ reportProgress: (loaded: number, total?: number) => void;
6
+ }
7
+ export interface RuntimeAssetDataResult {
8
+ data: string | ArrayBuffer | Uint8Array | Blob;
9
+ mimeType?: string;
10
+ }
11
+ export interface RuntimeAssetUrlResult {
12
+ url: string | URL;
13
+ }
14
+ export type RuntimeAssetLoaderResult = RuntimeAssetDataResult | RuntimeAssetUrlResult | string | URL | ArrayBuffer | Uint8Array | Blob | null | undefined;
15
+ export type RuntimeAssetLoader = (request: RuntimeAssetLoadRequest) => RuntimeAssetLoaderResult | Promise<RuntimeAssetLoaderResult>;
16
+ export interface RuntimeAssetConfig {
17
+ baseUrl?: string;
18
+ loader?: RuntimeAssetLoader;
19
+ }
20
+ export interface PlaygroundRuntimeAssets {
21
+ rootUrl?: string;
22
+ python?: RuntimeAssetConfig;
23
+ java?: RuntimeAssetConfig;
24
+ }
25
+ export interface ResolvedRuntimeAssetConfig {
26
+ baseUrl: string;
27
+ loader?: RuntimeAssetLoader;
28
+ useAssetBridge: boolean;
29
+ }
30
+ export declare const PYTHON_RUNTIME_LOAD_ASSETS: readonly ["pyodide.asm.js", "pyodide-lock.json", "pyodide.asm.wasm", "python_stdlib.zip"];
31
+ export declare const JAVA_RUNTIME_LOAD_ASSETS: readonly ["compiler.wasm-runtime.js", "compiler.wasm", "compile-classlib-teavm.bin", "runtime-classlib-teavm.bin"];
32
+ export declare function resolveRuntimeAssetConfig(runtime: RuntimeAssetRuntime, options: string | PlaygroundRuntimeAssets | undefined, currentUrl?: string): ResolvedRuntimeAssetConfig;
@@ -0,0 +1,97 @@
1
+ import { normalizeTeaVmBaseUrl, resolveTeaVmBaseUrl } from './teavmConfig';
2
+ export const PYTHON_RUNTIME_LOAD_ASSETS = [
3
+ 'pyodide.asm.js',
4
+ 'pyodide-lock.json',
5
+ 'pyodide.asm.wasm',
6
+ 'python_stdlib.zip'
7
+ ];
8
+ export const JAVA_RUNTIME_LOAD_ASSETS = [
9
+ 'compiler.wasm-runtime.js',
10
+ 'compiler.wasm',
11
+ 'compile-classlib-teavm.bin',
12
+ 'runtime-classlib-teavm.bin'
13
+ ];
14
+ const PYTHON_VIRTUAL_BASE_URL = 'https://wasm-idle.invalid/python/';
15
+ const JAVA_VIRTUAL_BASE_URL = 'https://wasm-idle.invalid/java/';
16
+ const normalizeBaseUrl = (baseUrl, currentUrl = '') => {
17
+ const normalized = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
18
+ return currentUrl ? new URL(normalized, currentUrl).href : normalized;
19
+ };
20
+ const normalizeRootUrl = (rootUrl) => rootUrl.endsWith('/') ? rootUrl.slice(0, -1) : rootUrl;
21
+ const resolvePythonBaseUrl = (rootUrl = '', currentUrl = '') => normalizeBaseUrl(`${normalizeRootUrl(rootUrl) || ''}/pyodide/`, currentUrl);
22
+ const resolvePythonRuntimeAssetConfig = (options, currentUrl = '') => {
23
+ if (typeof options === 'string') {
24
+ return {
25
+ baseUrl: resolvePythonBaseUrl(options, currentUrl),
26
+ useAssetBridge: false
27
+ };
28
+ }
29
+ const runtimeConfig = options?.python;
30
+ if (runtimeConfig?.baseUrl) {
31
+ return {
32
+ baseUrl: normalizeBaseUrl(runtimeConfig.baseUrl, currentUrl),
33
+ loader: runtimeConfig.loader,
34
+ useAssetBridge: !!runtimeConfig.loader
35
+ };
36
+ }
37
+ if (options?.rootUrl) {
38
+ return {
39
+ baseUrl: resolvePythonBaseUrl(options.rootUrl, currentUrl),
40
+ loader: runtimeConfig?.loader,
41
+ useAssetBridge: !!runtimeConfig?.loader
42
+ };
43
+ }
44
+ if (runtimeConfig?.loader) {
45
+ return {
46
+ baseUrl: PYTHON_VIRTUAL_BASE_URL,
47
+ loader: runtimeConfig.loader,
48
+ useAssetBridge: true
49
+ };
50
+ }
51
+ return {
52
+ baseUrl: resolvePythonBaseUrl('', currentUrl),
53
+ useAssetBridge: false
54
+ };
55
+ };
56
+ const resolveJavaBaseUrl = (rootUrl = '', currentUrl = '') => resolveTeaVmBaseUrl(rootUrl, currentUrl);
57
+ const resolveJavaRuntimeAssetConfig = (options, currentUrl = '') => {
58
+ if (typeof options === 'string') {
59
+ return {
60
+ baseUrl: resolveJavaBaseUrl(options, currentUrl),
61
+ useAssetBridge: false
62
+ };
63
+ }
64
+ const runtimeConfig = options?.java;
65
+ if (runtimeConfig?.baseUrl) {
66
+ return {
67
+ baseUrl: currentUrl
68
+ ? new URL(normalizeTeaVmBaseUrl(runtimeConfig.baseUrl), currentUrl).href
69
+ : normalizeTeaVmBaseUrl(runtimeConfig.baseUrl),
70
+ loader: runtimeConfig.loader,
71
+ useAssetBridge: !!runtimeConfig.loader
72
+ };
73
+ }
74
+ if (options?.rootUrl) {
75
+ return {
76
+ baseUrl: resolveJavaBaseUrl(options.rootUrl, currentUrl),
77
+ loader: runtimeConfig?.loader,
78
+ useAssetBridge: !!runtimeConfig?.loader
79
+ };
80
+ }
81
+ if (runtimeConfig?.loader) {
82
+ return {
83
+ baseUrl: JAVA_VIRTUAL_BASE_URL,
84
+ loader: runtimeConfig.loader,
85
+ useAssetBridge: true
86
+ };
87
+ }
88
+ return {
89
+ baseUrl: resolveJavaBaseUrl('', currentUrl),
90
+ useAssetBridge: false
91
+ };
92
+ };
93
+ export function resolveRuntimeAssetConfig(runtime, options, currentUrl = '') {
94
+ return runtime === 'python'
95
+ ? resolvePythonRuntimeAssetConfig(options, currentUrl)
96
+ : resolveJavaRuntimeAssetConfig(options, currentUrl);
97
+ }