quickwin 1.0.0

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 (175) hide show
  1. package/README.en.md +197 -0
  2. package/README.md +196 -0
  3. package/examples/PdfCanvas.js +67 -0
  4. package/examples/PdfCanvas.tsx +83 -0
  5. package/examples/pdf_preview2.js +431 -0
  6. package/examples/pdf_preview2.ts +375 -0
  7. package/examples/pdf_viewer.js +17623 -0
  8. package/examples/pdf_viewer.tsx +279 -0
  9. package/examples/test_gallery.js +17452 -0
  10. package/examples/test_gallery.tsx +285 -0
  11. package/examples/test_react_lazy.js +17336 -0
  12. package/examples/test_react_lazy.tsx +63 -0
  13. package/examples/test_react_listbox.js +17339 -0
  14. package/examples/test_react_listbox.tsx +71 -0
  15. package/examples/test_root_window.js +17313 -0
  16. package/examples/test_root_window.tsx +41 -0
  17. package/examples/test_tab.js +17339 -0
  18. package/examples/test_tab.tsx +75 -0
  19. package/examples/tray_demo.js +79 -0
  20. package/examples/tray_demo.tsx +81 -0
  21. package/lib/assert.js +8 -0
  22. package/lib/assert.ts +7 -0
  23. package/lib/cache-utils.js +43 -0
  24. package/lib/cache-utils.ts +40 -0
  25. package/lib/dumpRects.js +25 -0
  26. package/lib/dumpRects.ts +25 -0
  27. package/lib/fetch.js +490 -0
  28. package/lib/fetch.ts +502 -0
  29. package/lib/http-common.js +342 -0
  30. package/lib/http-common.ts +399 -0
  31. package/lib/http-server.js +416 -0
  32. package/lib/http-server.ts +424 -0
  33. package/lib/polyfill.js +156 -0
  34. package/lib/polyfill.ts +171 -0
  35. package/lib/react-qw/components/Button.js +8 -0
  36. package/lib/react-qw/components/CheckBox.js +31 -0
  37. package/lib/react-qw/components/ComboBox.js +42 -0
  38. package/lib/react-qw/components/DateTimePicker.js +96 -0
  39. package/lib/react-qw/components/Input.js +50 -0
  40. package/lib/react-qw/components/Link.js +43 -0
  41. package/lib/react-qw/components/ListBox.js +48 -0
  42. package/lib/react-qw/components/ListView.js +328 -0
  43. package/lib/react-qw/components/PathPicker.js +136 -0
  44. package/lib/react-qw/components/ProgressBar.js +22 -0
  45. package/lib/react-qw/components/RadioButton.js +31 -0
  46. package/lib/react-qw/components/ScrollView.js +139 -0
  47. package/lib/react-qw/components/Slider.js +45 -0
  48. package/lib/react-qw/components/Tab.js +61 -0
  49. package/lib/react-qw/components/Tooltip.js +55 -0
  50. package/lib/react-qw/components/TreeView.js +130 -0
  51. package/lib/react-qw/components/index.js +16 -0
  52. package/lib/react-qw/components/index.ts +17 -0
  53. package/lib/react-qw/index.js +73 -0
  54. package/lib/react-qw/index.ts +90 -0
  55. package/lib/react-qw/jsx.d.ts +34 -0
  56. package/lib/react-qw/layout.js +82 -0
  57. package/lib/react-qw/layout.ts +111 -0
  58. package/lib/react-qw/props.js +27 -0
  59. package/lib/react-qw/props.ts +36 -0
  60. package/lib/react-qw/reconciler.js +333 -0
  61. package/lib/react-qw/reconciler.ts +373 -0
  62. package/lib/stream.js +2 -0
  63. package/lib/stream.ts +22 -0
  64. package/lib/text-codec.js +197 -0
  65. package/lib/text-codec.ts +171 -0
  66. package/lib/text-measure.js +52 -0
  67. package/lib/text-measure.ts +54 -0
  68. package/lib/url.js +278 -0
  69. package/lib/url.ts +201 -0
  70. package/lib/vendor/web-streams/ponyfill.d.mts +829 -0
  71. package/lib/vendor/web-streams/ponyfill.mjs +8 -0
  72. package/lib/websocket.js +541 -0
  73. package/lib/websocket.ts +555 -0
  74. package/package.json +44 -0
  75. package/quickwin.d.ts +594 -0
  76. package/quickwin_const.d.ts +900 -0
  77. package/qwin-nowasm.exe +0 -0
  78. package/qwin.exe +0 -0
  79. package/test/add.wasm +0 -0
  80. package/test/complex.wasm +0 -0
  81. package/test/complex_imports.wasm +0 -0
  82. package/test/debug/http_server_e2e.js +31 -0
  83. package/test/debug/minwasm.js +52 -0
  84. package/test/debug/mupdf_debug.js +104 -0
  85. package/test/debug/wasm.js +122 -0
  86. package/test/debug/wasm_export_debug.js +64 -0
  87. package/test/debug/wasm_names.js +46 -0
  88. package/test/global_imports.wasm +0 -0
  89. package/test/import_func.wasm +0 -0
  90. package/test/imports.wasm +0 -0
  91. package/test/run.js +91 -0
  92. package/test/run.ts +96 -0
  93. package/test/sjlj.wasm +0 -0
  94. package/test/test_basic.js +7 -0
  95. package/test/test_basic.ts +9 -0
  96. package/test/test_basic_fetch.js +34 -0
  97. package/test/test_basic_fetch.ts +33 -0
  98. package/test/test_brotli.js +48 -0
  99. package/test/test_brotli.ts +52 -0
  100. package/test/test_fetch_cache.js +169 -0
  101. package/test/test_fetch_cache.ts +187 -0
  102. package/test/test_ffi.js +157 -0
  103. package/test/test_ffi.ts +174 -0
  104. package/test/test_frame_encoding.js +128 -0
  105. package/test/test_frame_encoding.ts +132 -0
  106. package/test/test_helper.js +84 -0
  107. package/test/test_helper.ts +80 -0
  108. package/test/test_http_import.js +78 -0
  109. package/test/test_http_import.ts +74 -0
  110. package/test/test_http_server.js +142 -0
  111. package/test/test_http_server.ts +136 -0
  112. package/test/test_import_dir.js +4 -0
  113. package/test/test_import_dir.ts +5 -0
  114. package/test/test_ipv6.js +134 -0
  115. package/test/test_ipv6.ts +129 -0
  116. package/test/test_jsx.js +1314 -0
  117. package/test/test_meta_url.js +3 -0
  118. package/test/test_meta_url.ts +4 -0
  119. package/test/test_mupdf_render.js +69 -0
  120. package/test/test_mupdf_render.ts +74 -0
  121. package/test/test_mupdf_twice.js +77 -0
  122. package/test/test_mupdf_twice.ts +81 -0
  123. package/test/test_mupdf_wasm.js +33 -0
  124. package/test/test_mupdf_wasm.ts +30 -0
  125. package/test/test_net_event.js +57 -0
  126. package/test/test_net_event.ts +55 -0
  127. package/test/test_net_fetch.js +259 -0
  128. package/test/test_net_fetch.ts +238 -0
  129. package/test/test_net_websocket.js +180 -0
  130. package/test/test_net_websocket.ts +164 -0
  131. package/test/test_polyfill.js +144 -0
  132. package/test/test_polyfill.ts +159 -0
  133. package/test/test_react_complex.js +17440 -0
  134. package/test/test_react_counter.js +17331 -0
  135. package/test/test_react_flex.js +17643 -0
  136. package/test/test_react_hidden.js +17336 -0
  137. package/test/test_react_listview_link.js +17371 -0
  138. package/test/test_react_render.js +17326 -0
  139. package/test/test_url.js +173 -0
  140. package/test/test_url.ts +183 -0
  141. package/test/test_wasm_basic.js +85 -0
  142. package/test/test_wasm_basic.ts +73 -0
  143. package/test/test_wasm_import_global.js +41 -0
  144. package/test/test_wasm_import_global.ts +45 -0
  145. package/test/test_wasm_sjlj.js +145 -0
  146. package/test/test_wasm_sjlj.ts +125 -0
  147. package/test/test_wasm_types.js +97 -0
  148. package/test/test_wasm_types.ts +124 -0
  149. package/test/test_worker.js +21 -0
  150. package/test/test_worker.ts +24 -0
  151. package/test/test_worker_fetch.js +26 -0
  152. package/test/test_worker_fetch.ts +27 -0
  153. package/test/test_worker_net.js +51 -0
  154. package/test/test_worker_net.ts +54 -0
  155. package/test/test_worker_wasm_concurrent.js +44 -0
  156. package/test/test_worker_wasm_concurrent.ts +45 -0
  157. package/test/types.wasm +0 -0
  158. package/test/worker_fetch.js +13 -0
  159. package/test/worker_fetch.ts +13 -0
  160. package/test/worker_helper.js +1 -0
  161. package/test/worker_helper.ts +1 -0
  162. package/test/worker_http.js +18 -0
  163. package/test/worker_http.ts +20 -0
  164. package/test/worker_import_lib.js +12 -0
  165. package/test/worker_import_lib.ts +13 -0
  166. package/test/worker_module.js +16 -0
  167. package/test/worker_module.ts +17 -0
  168. package/test/worker_wasm_concurrent.js +22 -0
  169. package/test/worker_wasm_concurrent.ts +22 -0
  170. package/tsconfig.json +27 -0
  171. package/vendor/mupdf-wasm/mupdf-wasm.d.ts +571 -0
  172. package/vendor/mupdf-wasm/mupdf-wasm.js +2749 -0
  173. package/vendor/mupdf-wasm/mupdf-wasm.wasm +0 -0
  174. package/vendor/mupdf-wasm/mupdf.d.ts +939 -0
  175. package/vendor/mupdf-wasm/mupdf.js +3317 -0
Binary file
package/qwin.exe ADDED
Binary file
package/test/add.wasm ADDED
Binary file
Binary file
Binary file
@@ -0,0 +1,31 @@
1
+ import '../../lib/fetch.js';
2
+ import { createServer } from '../../lib/http-server.js';
3
+ import * as std from 'std';
4
+ const server = createServer(async (req) => {
5
+ const url = new URL(req.url);
6
+ if (url.pathname === '/echo') {
7
+ return new Response(JSON.stringify({ method: req.method, path: url.pathname, body: await req.text(), q: Object.fromEntries(url.searchParams) }), { headers: { 'Content-Type': 'application/json' } });
8
+ }
9
+ return new Response('hello from quickwin http-server', { headers: { 'Content-Type': 'text/plain' } });
10
+ });
11
+ const rc = server.listen(0, '127.0.0.1');
12
+ if (rc !== 0) {
13
+ console.log('listen failed');
14
+ std.exit(1);
15
+ }
16
+ const addr = server.address();
17
+ const port = addr.port;
18
+ console.log('server on port', port);
19
+ async function main() {
20
+ const r1 = await fetch(`http://127.0.0.1:${port}/`);
21
+ console.log('GET / status', r1.status, 'body:', await r1.text());
22
+ const r2 = await fetch(`http://127.0.0.1:${port}/echo?x=1`, {
23
+ method: 'POST',
24
+ headers: { 'Content-Type': 'text/plain' },
25
+ body: 'hello-body',
26
+ });
27
+ console.log('POST /echo status', r2.status, 'body:', await r2.text());
28
+ server.close();
29
+ std.exit(0);
30
+ }
31
+ main();
@@ -0,0 +1,52 @@
1
+ import * as std from 'std';
2
+ std.printf("Hello\n");
3
+ function readWasmFile(path) {
4
+ const fp = std.open(path, 'rb');
5
+ if (!fp) {
6
+ return null;
7
+ }
8
+ fp.seek(0, 2); // SEEK_END
9
+ const size = fp.tell();
10
+ fp.seek(0, 0); // SEEK_SET
11
+ const buffer = new ArrayBuffer(size);
12
+ fp.read(buffer, 0, size);
13
+ fp.close();
14
+ return buffer;
15
+ }
16
+ const wasmBuf = readWasmFile('./complex_imports.wasm');
17
+ try {
18
+ if (!wasmBuf)
19
+ throw new Error('failed to load wasm');
20
+ const m = new WebAssembly.Module(wasmBuf);
21
+ console.log('imports:', WebAssembly.Module.imports(m));
22
+ console.log('exports:', WebAssembly.Module.exports(m));
23
+ const inst = new WebAssembly.Instance(m, {
24
+ env: {
25
+ log_i32: (x) => { console.log(' log_i32:', x); },
26
+ log_i64: (x) => { console.log(' log_i64:', x); },
27
+ log_f32: (x) => { console.log(' log_f32:', x); },
28
+ log_f64: (x) => { console.log(' log_f64:', x); },
29
+ op_i32: (a, b, c) => a * b + c,
30
+ }
31
+ });
32
+ const exp = inst.exports;
33
+ console.log('--- i32 ---');
34
+ let r = exp.run_i32(7);
35
+ console.log(' run_i32(7) =>', r, '(expected 75)');
36
+ console.log('--- i64 ---');
37
+ r = exp.run_i64(100000, 200000);
38
+ console.log(' run_i64(100000, 200000) =>', r, '(expected 300000)');
39
+ r = exp.run_i64(10000000000, 20000000000);
40
+ console.log(' run_i64(10000000000, 20000000000) =>', r, '(expected 30000000000)');
41
+ console.log('--- f32 ---');
42
+ r = exp.run_f32(3.5);
43
+ console.log(' run_f32(3.5) =>', r, '(expected 7.0)');
44
+ console.log('--- f64 ---');
45
+ r = exp.run_f64(2.5, 4.0);
46
+ console.log(' run_f64(2.5, 4.0) =>', r, '(expected 10.0)');
47
+ console.log('--- all done ---');
48
+ }
49
+ catch (e) {
50
+ console.log('ERROR:', e);
51
+ }
52
+ ;
@@ -0,0 +1,104 @@
1
+ import * as std from 'std';
2
+ function loadWasmBytes(path) {
3
+ const fp = std.open(path, 'rb');
4
+ if (!fp)
5
+ throw new Error('Cannot open: ' + path);
6
+ fp.seek(0, 2);
7
+ const size = fp.tell();
8
+ fp.seek(0, 0);
9
+ const buffer = new ArrayBuffer(size);
10
+ fp.read(buffer, 0, size);
11
+ fp.close();
12
+ return buffer;
13
+ }
14
+ function setupMupdfModule(wasmPath) {
15
+ const wasmBinary = loadWasmBytes(wasmPath);
16
+ globalThis["$libmupdf_wasm_Module"] = {
17
+ wasmBinary,
18
+ locateFile: (p) => p
19
+ };
20
+ }
21
+ setupMupdfModule('./vendor/mupdf-wasm/mupdf-wasm.wasm');
22
+ await import('../../vendor/mupdf-wasm/mupdf.js');
23
+ // Debug the instance exports
24
+ const inst = globalThis["$wasm_inst"];
25
+ const mod = globalThis["$wasm_mod"];
26
+ console.log('=== WASM Module exports (first 30) ===');
27
+ const modExports = WebAssembly.Module.exports(mod);
28
+ for (let i = 0; i < 30 && i < modExports.length; i++)
29
+ console.log(` ${i}: ${modExports[i].name} (${modExports[i].kind})`);
30
+ // Find Sf and Tf indices
31
+ let sf_idx = -1, tf_idx = -1;
32
+ for (let i = 0; i < modExports.length; i++) {
33
+ if (modExports[i].name === 'Sf')
34
+ sf_idx = i;
35
+ if (modExports[i].name === 'Tf')
36
+ tf_idx = i;
37
+ }
38
+ console.log('Sf index:', sf_idx, 'Tf index:', tf_idx);
39
+ console.log('instance exports Sf:', typeof inst.exports['Sf']);
40
+ console.log('instance exports Tf:', typeof inst.exports['Tf']);
41
+ // Load a simple WASM to verify bridge works
42
+ const fp = std.open('./example.pdf', 'rb');
43
+ if (!fp) {
44
+ console.log('cannot open example.pdf');
45
+ std.exit(1);
46
+ }
47
+ fp.seek(0, 2);
48
+ const size = fp.tell();
49
+ fp.seek(0, 0);
50
+ const buf = new ArrayBuffer(size);
51
+ fp.read(buf, 0, size);
52
+ fp.close();
53
+ console.log('\npdf size:', size);
54
+ // Try calling lower-level functions directly
55
+ const lib = globalThis["$libmupdf_wasm_Module"];
56
+ // First open the document
57
+ const wasmMemory = inst.exports['cb'];
58
+ console.log('WASM memory:', typeof wasmMemory, wasmMemory?.buffer?.byteLength);
59
+ // Create a buffer and try
60
+ const bufPtr = lib._wasm_malloc(size);
61
+ console.log('malloc buffer pointer:', bufPtr);
62
+ // Write PDF data into WASM memory at bufPtr...
63
+ const mem8 = new Uint8Array(wasmMemory.buffer);
64
+ for (let i = 0; i < size; i++)
65
+ mem8[bufPtr + i] = (new Uint8Array(buf))[i];
66
+ console.log('wrote pdf data to WASM memory at', bufPtr);
67
+ // Try opening document directly with _wasm_open_document_with_buffer
68
+ // Need a string for "application/pdf"
69
+ const magicStr = "application/pdf\x00";
70
+ const magicPtr = lib._wasm_malloc(magicStr.length);
71
+ for (let i = 0; i < magicStr.length; i++)
72
+ mem8[magicPtr + i] = magicStr.charCodeAt(i);
73
+ console.log('magic string at', magicPtr);
74
+ // Create a Buffer wrapper object - need to call Buffer constructor
75
+ // Actually let's just call the low-level function directly
76
+ const fz_ptr = inst.exports['Mf'](magicPtr, bufPtr); // _wasm_open_document_with_buffer
77
+ console.log('_wasm_open_document_with_buffer returned:', fz_ptr, typeof fz_ptr);
78
+ if (fz_ptr && typeof fz_ptr === 'number') {
79
+ // Try countPages
80
+ const count = inst.exports['Sf'](fz_ptr);
81
+ console.log('_wasm_count_pages returned:', count, typeof count);
82
+ // Try loadPage
83
+ if (typeof fz_ptr !== 'number') {
84
+ console.log('fz_ptr is not a number!');
85
+ }
86
+ const pagePtr = inst.exports['Tf'](fz_ptr, 0);
87
+ console.log('_wasm_load_page returned:', pagePtr, typeof pagePtr);
88
+ // Get bounds
89
+ // _wasm_bound_page(Sf?) - need to find this export
90
+ for (let i = 0; i < modExports.length; i++) {
91
+ if (modExports[i].name.startsWith('Uf')) {
92
+ console.log('Uf at index', i, '- likely _wasm_pdf_page_from_fz_page');
93
+ }
94
+ if (modExports[i].name.startsWith('Vf')) {
95
+ console.log('Vf at index', i);
96
+ }
97
+ }
98
+ // Try calling _wasm_pdf_page_from_fz_page (Uf)
99
+ const pdfPtr = inst.exports['Uf'](pagePtr);
100
+ console.log('_wasm_pdf_page_from_fz_page returned:', pdfPtr, typeof pdfPtr);
101
+ }
102
+ lib._wasm_free(magicPtr);
103
+ lib._wasm_free(bufPtr);
104
+ console.log('\ndone');
@@ -0,0 +1,122 @@
1
+ import * as std from 'std';
2
+ function readWasmFile(path) {
3
+ const fp = std.open(path, 'rb');
4
+ if (!fp)
5
+ return null;
6
+ fp.seek(0, 2);
7
+ const size = fp.tell();
8
+ fp.seek(0, 0);
9
+ const buffer = new ArrayBuffer(size);
10
+ fp.read(buffer, 0, size);
11
+ fp.close();
12
+ return buffer;
13
+ }
14
+ var ok = 0, fail = 0;
15
+ function check(name, expected, actual) {
16
+ if (typeof expected === 'number' && typeof actual === 'number') {
17
+ if (Math.abs(expected - actual) < 0.0001) {
18
+ ok++;
19
+ std.printf(' PASS: %s = %s\n', name, String(actual));
20
+ }
21
+ else {
22
+ fail++;
23
+ std.printf(' FAIL: %s = %s (expected %s)\n', name, String(actual), String(expected));
24
+ }
25
+ }
26
+ else if (expected === actual) {
27
+ ok++;
28
+ std.printf(' PASS: %s = %s\n', name, String(actual));
29
+ }
30
+ else {
31
+ fail++;
32
+ std.printf(' FAIL: %s = %s (expected %s)\n', name, String(actual), String(expected));
33
+ }
34
+ }
35
+ std.printf('=== validate ===\n');
36
+ check('empty buffer', false, WebAssembly.validate(new Uint8Array([]).buffer));
37
+ check('invalid bytes', false, WebAssembly.validate(new Uint8Array([1, 2, 3]).buffer));
38
+ const wasmBuffer = readWasmFile('./add.wasm');
39
+ if (!wasmBuffer) {
40
+ std.printf('FAIL: cannot load add.wasm\n');
41
+ std.exit(1);
42
+ }
43
+ check('valid module', true, WebAssembly.validate(wasmBuffer));
44
+ std.printf('=== Module ===\n');
45
+ var module = null;
46
+ try {
47
+ module = new WebAssembly.Module(wasmBuffer);
48
+ check('Module constructor', true, module instanceof WebAssembly.Module);
49
+ }
50
+ catch (e) {
51
+ std.printf(' FAIL: Module constructor: %s\n', String(e));
52
+ fail++;
53
+ }
54
+ std.printf('=== Module.exports ===\n');
55
+ if (module) {
56
+ try {
57
+ const exps = WebAssembly.Module.exports(module);
58
+ check('exports count', 1, exps.length);
59
+ check('export name', 'add', exps[0].name);
60
+ check('export kind', 'function', exps[0].kind);
61
+ }
62
+ catch (e) {
63
+ std.printf(' FAIL: Module.exports: %s\n', String(e));
64
+ fail++;
65
+ }
66
+ }
67
+ std.printf('=== Instance (add.wasm) ===\n');
68
+ if (module) {
69
+ try {
70
+ const instance = new WebAssembly.Instance(module);
71
+ const iExp = instance.exports;
72
+ check('Instance created', true, instance instanceof WebAssembly.Instance);
73
+ check('add(1, 2)', 3, iExp.add(1, 2));
74
+ check('add(10, 20)', 30, iExp.add(10, 20));
75
+ check('add(-5, 3)', -2, iExp.add(-5, 3));
76
+ }
77
+ catch (e) {
78
+ std.printf(' FAIL: Instance: %s\n', String(e));
79
+ fail++;
80
+ }
81
+ }
82
+ std.printf('=== complex.wasm (multi exports) ===\n');
83
+ const complexBuffer = readWasmFile('./complex.wasm');
84
+ if (complexBuffer) {
85
+ try {
86
+ const cmod = new WebAssembly.Module(complexBuffer);
87
+ const cinst = new WebAssembly.Instance(cmod);
88
+ const cExp = cinst.exports;
89
+ check('add(3, 4)', 7, cExp.add(3, 4));
90
+ check('sub(10, 3)', 7, cExp.sub(10, 3));
91
+ check('mul(6, 7)', 42, cExp.mul(6, 7));
92
+ check('factorial(0)', 1, cExp.factorial(0));
93
+ check('factorial(5)', 120, cExp.factorial(5));
94
+ check('factorial(10)', 3628800, cExp.factorial(10));
95
+ }
96
+ catch (e) {
97
+ std.printf(' FAIL: complex.wasm: %s\n', String(e));
98
+ fail++;
99
+ }
100
+ }
101
+ std.printf('=== import function support ===\n');
102
+ const importFuncBuffer = readWasmFile('./import_func.wasm');
103
+ if (importFuncBuffer) {
104
+ try {
105
+ const ifmod = new WebAssembly.Module(importFuncBuffer);
106
+ const importObject = {
107
+ env: { imported_add: (a, b) => a + b }
108
+ };
109
+ const ifinst = new WebAssembly.Instance(ifmod, importObject);
110
+ const ifExp = ifinst.exports;
111
+ check('add_via_import(3, 4)', 7, ifExp.add_via_import(3, 4));
112
+ check('add_via_import(10, 20)', 30, ifExp.add_via_import(10, 20));
113
+ check('add_via_import(-5, 3)', -2, ifExp.add_via_import(-5, 3));
114
+ }
115
+ catch (e) {
116
+ std.printf(' FAIL: import_func.wasm: %s\n', String(e));
117
+ fail++;
118
+ }
119
+ }
120
+ std.printf('\n%d/%d tests passed\n', ok, ok + fail);
121
+ if (fail > 0)
122
+ std.exit(1);
@@ -0,0 +1,64 @@
1
+ import * as std from 'std';
2
+ const fp = std.open('./vendor/mupdf-wasm/mupdf-wasm.wasm', 'rb');
3
+ if (!fp) {
4
+ console.log('cannot open vendor/mupdf-wasm/mupdf-wasm.wasm');
5
+ std.exit(1);
6
+ }
7
+ fp.seek(0, 2);
8
+ const size = fp.tell();
9
+ fp.seek(0, 0);
10
+ const buf = new ArrayBuffer(size);
11
+ fp.read(buf, 0, size);
12
+ fp.close();
13
+ const module = new WebAssembly.Module(buf);
14
+ const exports = WebAssembly.Module.exports(module);
15
+ const imports = WebAssembly.Module.imports(module);
16
+ // List ALL export names
17
+ console.log(`=== All exports (${exports.length}) ===`);
18
+ for (let i = 0; i < exports.length; i++) {
19
+ if (exports[i].name === 'ul' || exports[i].name === 'tl')
20
+ console.log(` ${i}: ${exports[i].name} (${exports[i].kind}) *** FOUND ***`);
21
+ }
22
+ // Check last 20 exports
23
+ console.log(`\n=== Last 20 exports ===`);
24
+ for (let i = Math.max(0, exports.length - 20); i < exports.length; i++)
25
+ console.log(` ${i}: ${exports[i].name} (${exports[i].kind})`);
26
+ // Check if ul/tl are import functions
27
+ console.log(`\n=== Imports (${imports.length}) ===`);
28
+ for (let i = 0; i < imports.length; i++) {
29
+ if (imports[i].name === 'ul' || imports[i].name === 'tl')
30
+ console.log(` ${i}: ${imports[i].module}.${imports[i].name}`);
31
+ }
32
+ // Now try to call simple exports and see if exec_env is the issue
33
+ console.log(`\n=== Direct instance call test ===`);
34
+ const importObj = { a: {} };
35
+ for (const imp of imports) {
36
+ if (!importObj[imp.module])
37
+ importObj[imp.module] = {};
38
+ if (imp.kind === 'function') {
39
+ importObj[imp.module][imp.name] = () => 0;
40
+ }
41
+ }
42
+ // Test calling db, eb sequentially
43
+ const inst = new WebAssembly.Instance(module, importObj);
44
+ const exp = inst.exports;
45
+ console.log('1. calling db()...');
46
+ exp['db']();
47
+ console.log('2. calling db() again...');
48
+ exp['db']();
49
+ console.log('3. calling eb()...');
50
+ try {
51
+ exp['eb']();
52
+ console.log(' eb() succeeded');
53
+ }
54
+ catch (e) {
55
+ console.log(' eb() failed:', e);
56
+ }
57
+ console.log('4. calling fb(100)...');
58
+ try {
59
+ const r = exp['fb'](100);
60
+ console.log(' fb(100) =', r);
61
+ }
62
+ catch (e) {
63
+ console.log(' fb(100) failed:', e);
64
+ }
@@ -0,0 +1,46 @@
1
+ import * as std from 'std';
2
+ // Load the vendor/mupdf-wasm binary using our pre-load mechanism
3
+ const fp = std.open('./vendor/mupdf-wasm/mupdf-wasm.wasm', 'rb');
4
+ if (!fp) {
5
+ console.log('cannot open vendor/mupdf-wasm/mupdf-wasm.wasm');
6
+ std.exit(1);
7
+ }
8
+ fp.seek(0, 2);
9
+ const size = fp.tell();
10
+ fp.seek(0, 0);
11
+ const buf = new ArrayBuffer(size);
12
+ fp.read(buf, 0, size);
13
+ fp.close();
14
+ // Check exports for Tf
15
+ const module = new WebAssembly.Module(buf);
16
+ const exports = WebAssembly.Module.exports(module);
17
+ const imports = WebAssembly.Module.imports(module);
18
+ // Look for Tf specifically
19
+ let foundTf = false;
20
+ for (const e of exports) {
21
+ if (e.name === 'Tf') {
22
+ console.log('FOUND Tf in exports');
23
+ foundTf = true;
24
+ break;
25
+ }
26
+ }
27
+ if (!foundTf)
28
+ console.log('Tf NOT in exports');
29
+ // Check a few nearby names used in assignWasmExports
30
+ const wanted = ['Tf', 'Uf', 'Vf', 'Wf', 'Xf', 'Yf', 'Sf', 'Rf', 'Qf', 'Pf', 'Of', 'Nf'];
31
+ const found = [];
32
+ const missing = [];
33
+ for (const w of wanted) {
34
+ if (exports.some(e => e.name === w))
35
+ found.push(w);
36
+ else
37
+ missing.push(w);
38
+ }
39
+ console.log('found:', found.join(', '));
40
+ console.log('missing:', missing.join(', '));
41
+ // Count exports
42
+ console.log('total exports:', exports.length);
43
+ console.log('total imports:', imports.length);
44
+ // List first 30 export names
45
+ for (let i = 0; i < 30 && i < exports.length; i++)
46
+ console.log(' export', i, '=', exports[i].name);
Binary file
Binary file
Binary file
package/test/run.js ADDED
@@ -0,0 +1,91 @@
1
+ import * as std from 'std';
2
+ import { Tester } from './test_helper.js';
3
+ function formatDuration(ms) {
4
+ if (ms >= 1000)
5
+ return (ms / 1000).toFixed(2) + 's';
6
+ return ms + 'ms';
7
+ }
8
+ const BOLD = '\x1b[1m';
9
+ const GREEN = '\x1b[32m';
10
+ const RED = '\x1b[31m';
11
+ const RESET = '\x1b[0m';
12
+ const suiteDefs = [
13
+ { name: 'basic', file: './test_basic.js', tags: [] },
14
+ { name: 'basic-fetch', file: './test_basic_fetch.js', tags: [] },
15
+ { name: 'ipv6', file: './test_ipv6.js', tags: ['net'] },
16
+ { name: 'url', file: './test_url.js', tags: [] },
17
+ { name: 'wasm-basic', file: './test_wasm_basic.js', tags: ['wasm'] },
18
+ { name: 'wasm-types', file: './test_wasm_types.js', tags: ['wasm'] },
19
+ { name: 'wasm-import-global', file: './test_wasm_import_global.js', tags: ['wasm'] },
20
+ { name: 'wasm-sjlj', file: './test_wasm_sjlj.js', tags: ['wasm'] },
21
+ { name: 'wasm-frame-encoding', file: './test_frame_encoding.js', tags: ['wasm'] },
22
+ { name: 'mupdf-wasm', file: './test_mupdf_wasm.js', tags: ['wasm', 'mupdf'] },
23
+ { name: 'mupdf-twice', file: './test_mupdf_twice.js', tags: ['wasm', 'mupdf'] },
24
+ { name: 'mupdf-render', file: './test_mupdf_render.js', tags: ['wasm', 'mupdf'] },
25
+ { name: 'ffi', file: './test_ffi.js', tags: [] },
26
+ { name: 'net-fetch', file: './test_net_fetch.js', tags: ['net'] },
27
+ { name: 'net-websocket', file: './test_net_websocket.js', tags: ['net'] },
28
+ { name: 'net-event', file: './test_net_event.js', tags: ['net'] },
29
+ { name: 'http-server', file: './test_http_server.js', tags: ['net'] },
30
+ { name: 'http-import', file: './test_http_import.js', tags: ['net'] },
31
+ { name: 'fetch-cache', file: './test_fetch_cache.js', tags: ['net'] },
32
+ { name: 'polyfill', file: './test_polyfill.js', tags: [] },
33
+ { name: 'brotli', file: './test_brotli.js', tags: [] },
34
+ { name: 'worker', file: './test_worker.js', tags: [] },
35
+ { name: 'worker-wasm', file: './test_worker_wasm_concurrent.js', tags: ['wasm'] },
36
+ { name: 'worker-http', file: './test_worker_net.js', tags: ['net'] },
37
+ { name: 'worker-fetch', file: './test_worker_fetch.js', tags: ['net'] }
38
+ ];
39
+ async function main() {
40
+ const filter = scriptArgs.length > 1 ? scriptArgs[1] : '';
41
+ std.printf('%s====== QuickWin Test Runner ======%s\n', BOLD, RESET);
42
+ if (filter)
43
+ std.printf('Filter: %s\n', filter);
44
+ const results = [];
45
+ let totalOk = 0, totalFail = 0;
46
+ for (const def of suiteDefs) {
47
+ if (filter) {
48
+ if (filter.startsWith('-')) {
49
+ const excludeTag = filter.slice(1);
50
+ if (def.tags.indexOf(excludeTag) >= 0)
51
+ continue;
52
+ }
53
+ else {
54
+ if (def.name.indexOf(filter) < 0)
55
+ continue;
56
+ }
57
+ }
58
+ let mod;
59
+ try {
60
+ mod = await import(def.file);
61
+ }
62
+ catch (e) {
63
+ continue;
64
+ }
65
+ if (!mod.suite)
66
+ continue;
67
+ const t = new Tester();
68
+ std.printf('\n%s--- %s ---%s\n', BOLD, def.name, RESET);
69
+ const suiteStart = Date.now();
70
+ try {
71
+ await mod.suite.run(t);
72
+ }
73
+ catch (e) {
74
+ std.printf(' %sSUITE FAILED:%s %s\n', RED, RESET, String(e));
75
+ t.fail++;
76
+ }
77
+ const suiteElapsed = Date.now() - suiteStart;
78
+ t.summary();
79
+ results.push({ name: def.name, ok: t.ok, fail: t.fail, elapsed: suiteElapsed });
80
+ totalOk += t.ok;
81
+ totalFail += t.fail;
82
+ }
83
+ const color = totalFail > 0 ? RED : GREEN;
84
+ std.printf('\n%s====== Test Results ======%s\n', BOLD, RESET);
85
+ for (const r of results) {
86
+ const c = r.fail > 0 ? RED : GREEN;
87
+ std.printf(' %s%-18s %s%d/%d passed %s(%s)%s\n', c, r.name, RESET, r.ok, r.ok + r.fail, c, formatDuration(r.elapsed), RESET);
88
+ }
89
+ std.printf('%s====== Summary: %d/%d passed ======%s\n', color, totalOk, totalOk + totalFail, RESET);
90
+ }
91
+ main();
package/test/run.ts ADDED
@@ -0,0 +1,96 @@
1
+ import * as std from 'std'
2
+ import { Tester } from './test_helper.js'
3
+
4
+ declare var scriptArgs: string[]
5
+
6
+ function formatDuration(ms: number): string {
7
+ if (ms >= 1000) return (ms / 1000).toFixed(2) + 's'
8
+ return ms + 'ms'
9
+ }
10
+
11
+ const BOLD = '\x1b[1m'
12
+ const GREEN = '\x1b[32m'
13
+ const RED = '\x1b[31m'
14
+ const RESET = '\x1b[0m'
15
+
16
+ const suiteDefs = [
17
+ { name: 'basic', file: './test_basic.js', tags: [] },
18
+ { name: 'basic-fetch', file: './test_basic_fetch.js', tags: [] },
19
+ { name: 'ipv6', file: './test_ipv6.js', tags: ['net'] },
20
+ { name: 'url', file: './test_url.js', tags: [] },
21
+ { name: 'wasm-basic', file: './test_wasm_basic.js', tags: ['wasm'] },
22
+ { name: 'wasm-types', file: './test_wasm_types.js', tags: ['wasm'] },
23
+ { name: 'wasm-import-global', file: './test_wasm_import_global.js', tags: ['wasm'] },
24
+ { name: 'wasm-sjlj', file: './test_wasm_sjlj.js', tags: ['wasm'] },
25
+ { name: 'wasm-frame-encoding', file: './test_frame_encoding.js', tags: ['wasm'] },
26
+ { name: 'mupdf-wasm', file: './test_mupdf_wasm.js', tags: ['wasm', 'mupdf'] },
27
+ { name: 'mupdf-twice', file: './test_mupdf_twice.js', tags: ['wasm', 'mupdf'] },
28
+ { name: 'mupdf-render', file: './test_mupdf_render.js', tags: ['wasm', 'mupdf'] },
29
+ { name: 'ffi', file: './test_ffi.js', tags: [] },
30
+ { name: 'net-fetch', file: './test_net_fetch.js', tags: ['net'] },
31
+ { name: 'net-websocket', file: './test_net_websocket.js', tags: ['net'] },
32
+ { name: 'net-event', file: './test_net_event.js', tags: ['net'] },
33
+ { name: 'http-server', file: './test_http_server.js', tags: ['net'] },
34
+ { name: 'http-import', file: './test_http_import.js', tags: ['net'] },
35
+ { name: 'fetch-cache', file: './test_fetch_cache.js', tags: ['net'] },
36
+ { name: 'polyfill', file: './test_polyfill.js', tags: [] },
37
+ { name: 'brotli', file: './test_brotli.js', tags: [] },
38
+ { name: 'worker', file: './test_worker.js', tags: [] },
39
+ { name: 'worker-wasm', file: './test_worker_wasm_concurrent.js', tags: ['wasm'] },
40
+ { name: 'worker-http', file: './test_worker_net.js', tags: ['net'] },
41
+ { name: 'worker-fetch', file: './test_worker_fetch.js', tags: ['net'] }
42
+ ]
43
+
44
+ async function main(): Promise<void> {
45
+ const filter = scriptArgs.length > 1 ? scriptArgs[1] : ''
46
+
47
+ std.printf('%s====== QuickWin Test Runner ======%s\n', BOLD, RESET)
48
+ if (filter) std.printf('Filter: %s\n', filter)
49
+
50
+ const results: { name: string, ok: number, fail: number, elapsed: number }[] = []
51
+ let totalOk = 0, totalFail = 0
52
+
53
+ for (const def of suiteDefs) {
54
+ if (filter) {
55
+ if (filter.startsWith('-')) {
56
+ const excludeTag = filter.slice(1)
57
+ if (def.tags.indexOf(excludeTag) >= 0) continue
58
+ } else {
59
+ if (def.name.indexOf(filter) < 0) continue
60
+ }
61
+ }
62
+
63
+ let mod: any
64
+ try {
65
+ mod = await import(def.file)
66
+ } catch (e) {
67
+ continue
68
+ }
69
+ if (!mod.suite) continue
70
+
71
+ const t = new Tester()
72
+ std.printf('\n%s--- %s ---%s\n', BOLD, def.name, RESET)
73
+ const suiteStart = Date.now()
74
+ try {
75
+ await mod.suite.run(t)
76
+ } catch (e) {
77
+ std.printf(' %sSUITE FAILED:%s %s\n', RED, RESET, String(e))
78
+ t.fail++
79
+ }
80
+ const suiteElapsed = Date.now() - suiteStart
81
+ t.summary()
82
+ results.push({ name: def.name, ok: t.ok, fail: t.fail, elapsed: suiteElapsed })
83
+ totalOk += t.ok
84
+ totalFail += t.fail
85
+ }
86
+
87
+ const color = totalFail > 0 ? RED : GREEN
88
+ std.printf('\n%s====== Test Results ======%s\n', BOLD, RESET)
89
+ for (const r of results) {
90
+ const c = r.fail > 0 ? RED : GREEN
91
+ std.printf(' %s%-18s %s%d/%d passed %s(%s)%s\n', c, r.name, RESET, r.ok, r.ok + r.fail, c, formatDuration(r.elapsed), RESET)
92
+ }
93
+ std.printf('%s====== Summary: %d/%d passed ======%s\n', color, totalOk, totalOk + totalFail, RESET)
94
+ }
95
+
96
+ main()
package/test/sjlj.wasm ADDED
Binary file
@@ -0,0 +1,7 @@
1
+ export const suite = {
2
+ name: 'basic',
3
+ run: (t) => {
4
+ t.section('smoke');
5
+ t.check('hello', true, true);
6
+ }
7
+ };
@@ -0,0 +1,9 @@
1
+ import { Tester } from './test_helper.js'
2
+
3
+ export const suite = {
4
+ name: 'basic',
5
+ run: (t: Tester) => {
6
+ t.section('smoke')
7
+ t.check('hello', true, true)
8
+ }
9
+ }