MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

handle improved oxc TLA

+252 -68
+161 -61
examples/test262/index.js
··· 1 1 import fs from 'fs'; 2 2 import { join } from 'path'; 3 + import { spawnSync } from 'child_process'; 3 4 4 5 const basePath = import.meta.dirname; 5 6 const indexPath = join(basePath, 'ant.json'); ··· 53 54 index: 0, 54 55 filter: '', 55 56 filtered: entries, 57 + memoryOffset: 0, 58 + memoryStatus: '', 59 + memoryStatusAt: 0, 56 60 searchMode: false, 57 61 searchQuery: '' 58 62 }; ··· 96 100 return str.slice(0, len - 1) + 'โ€ฆ'; 97 101 } 98 102 103 + const byteStatSuffixes = new Set([ 104 + 'used', 105 + 'capacity', 106 + 'totalUsed', 107 + 'totalCapacity', 108 + 'objects', 109 + 'overflow', 110 + 'extraSlots', 111 + 'promises', 112 + 'proxies', 113 + 'exotic', 114 + 'arrays', 115 + 'shapes', 116 + 'closures', 117 + 'upvalues', 118 + 'propRefs', 119 + 'total', 120 + 'buffers', 121 + 'code', 122 + 'bytes', 123 + 'cstack', 124 + 'rss', 125 + 'virtualSize' 126 + ]); 127 + 128 + function formatStatValue(path, value, styled = true) { 129 + if (typeof value === 'number') { 130 + const key = path.split('.').pop(); 131 + if (byteStatSuffixes.has(key)) { 132 + return styled ? `${fmt(value)} ${c.dim}(${value})${c.reset}` : `${fmt(value)} (${value})`; 133 + } 134 + } 135 + return String(value); 136 + } 137 + 138 + function flattenStats(value, prefix = '', out = [], styled = true) { 139 + if (value && typeof value === 'object') { 140 + for (const [key, child] of Object.entries(value)) { 141 + flattenStats(child, prefix ? `${prefix}.${key}` : key, out, styled); 142 + } 143 + return out; 144 + } 145 + 146 + if (styled) { 147 + out.push(`${c.gray}${prefix}${c.reset}: ${c.bold}${formatStatValue(prefix, value, true)}${c.reset}`); 148 + } else { 149 + out.push(`${prefix}: ${formatStatValue(prefix, value, false)}`); 150 + } 151 + return out; 152 + } 153 + 154 + function buildMemoryLines(styled = true) { 155 + const mem = Ant.stats(); 156 + const lines = styled 157 + ? [`${c.cyan}Ant.stats()${c.reset}`, `${c.dim}Raw runtime stats dump${c.reset}`, ''] 158 + : ['Ant.stats()', 'Raw runtime stats dump', '']; 159 + lines.push(...flattenStats(mem, '', [], styled)); 160 + 161 + if (Ant.raw && typeof Ant.raw.gcMarkProfile === 'function') { 162 + lines.push(''); 163 + lines.push(styled ? `${c.cyan}Ant.raw.gcMarkProfile()${c.reset}` : 'Ant.raw.gcMarkProfile()'); 164 + lines.push(styled ? `${c.dim}Extra GC mark profiler stats${c.reset}` : 'Extra GC mark profiler stats'); 165 + lines.push(''); 166 + lines.push(...flattenStats(Ant.raw.gcMarkProfile(), 'gcMarkProfile', [], styled)); 167 + } 168 + 169 + return lines; 170 + } 171 + 172 + function memoryStatusText() { 173 + if (!state.memoryStatus) return ''; 174 + if (Date.now() - state.memoryStatusAt > 4000) { 175 + state.memoryStatus = ''; 176 + return ''; 177 + } 178 + return state.memoryStatus; 179 + } 180 + 181 + function setMemoryStatus(message) { 182 + state.memoryStatus = message; 183 + state.memoryStatusAt = Date.now(); 184 + } 185 + 186 + function copyMemoryStats() { 187 + const text = buildMemoryLines(false).join('\n') + '\n'; 188 + const commands = process.platform === 'win32' 189 + ? [{ command: 'clip', args: [] }] 190 + : [ 191 + { command: 'pbcopy', args: [] }, 192 + { command: 'wl-copy', args: [] }, 193 + { command: 'xclip', args: ['-selection', 'clipboard'] }, 194 + { command: 'xsel', args: ['--clipboard', '--input'] } 195 + ]; 196 + 197 + for (const { command, args } of commands) { 198 + try { 199 + const result = spawnSync(command, args, { input: text }); 200 + if (result.status === 0 || result.exitCode === 0) { 201 + setMemoryStatus(`${c.green}Copied stats to clipboard with ${command}${c.reset}`); 202 + return true; 203 + } 204 + } catch {} 205 + } 206 + 207 + setMemoryStatus(`${c.red}Clipboard copy failed${c.reset}`); 208 + return false; 209 + } 210 + 99 211 function buildScreen() { 100 212 const rows = getRows(); 101 213 const cols = getCols(); ··· 187 299 lines.push(''); 188 300 lines.push(`${c.dim}s browse ยท q quit${c.reset}`); 189 301 } else if (state.mode === 'memory') { 190 - const mem = Ant.stats(); 191 - 192 - lines.push(`${c.cyan}Pools${c.reset}`); 193 - lines.push(` Rope: ${c.bold}${fmt(mem.pools.rope.used)}${c.reset} / ${fmt(mem.pools.rope.capacity)} (${mem.pools.rope.blocks} blocks)`); 194 - lines.push( 195 - ` String: ${c.bold}${fmt(mem.pools.string.used)}${c.reset} / ${fmt(mem.pools.string.capacity)} (${mem.pools.string.blocks} blocks)` 196 - ); 197 - lines.push( 198 - ` Symbol: ${c.bold}${fmt(mem.pools.symbol.used)}${c.reset} / ${fmt(mem.pools.symbol.capacity)} (${mem.pools.symbol.blocks} blocks)` 199 - ); 200 - lines.push( 201 - ` Bigint: ${c.bold}${fmt(mem.pools.bigint.used)}${c.reset} / ${fmt(mem.pools.bigint.capacity)} (${mem.pools.bigint.blocks} blocks)` 202 - ); 203 - lines.push(` Total: ${c.bold}${fmt(mem.pools.totalUsed)} / ${fmt(mem.pools.totalCapacity)}${c.reset}`); 204 - lines.push(''); 302 + const footerLines = 2; 303 + const memoryLines = buildMemoryLines(); 304 + const viewHeight = Math.max(1, rows - footerLines); 305 + const maxOffset = Math.max(0, memoryLines.length - viewHeight); 205 306 206 - lines.push(`${c.cyan}Alloc${c.reset}`); 207 - lines.push(` Objects: ${c.bold}${fmt(mem.alloc.objects)}${c.reset} (${mem.alloc.objectCount} objects)`); 208 - lines.push(` Overflow: ${c.bold}${fmt(mem.alloc.overflow)}${c.reset}`); 209 - lines.push(` ExtraSlots: ${c.bold}${fmt(mem.alloc.extraSlots)}${c.reset}`); 210 - lines.push(` Promises: ${c.bold}${fmt(mem.alloc.promises)}${c.reset}`); 211 - lines.push(` Proxies: ${c.bold}${fmt(mem.alloc.proxies)}${c.reset}`); 212 - lines.push(` Exotic: ${c.bold}${fmt(mem.alloc.exotic)}${c.reset}`); 213 - lines.push(` Arrays: ${c.bold}${fmt(mem.alloc.arrays)}${c.reset}`); 214 - lines.push(` Shapes: ${c.bold}${fmt(mem.alloc.shapes)}${c.reset}`); 215 - lines.push(` Closures: ${c.bold}${fmt(mem.alloc.closures)}${c.reset}`); 216 - lines.push(` Upvalues: ${c.bold}${fmt(mem.alloc.upvalues)}${c.reset}`); 217 - lines.push(` PropRefs: ${c.bold}${fmt(mem.alloc.propRefs)}${c.reset}`); 218 - lines.push(` Total: ${c.bold}${fmt(mem.alloc.total)}${c.reset}`); 219 - lines.push(''); 220 - 221 - lines.push(`${c.cyan}External${c.reset}`); 222 - lines.push(` Buffers: ${c.bold}${fmt(mem.external.buffers)}${c.reset}`); 223 - lines.push(` Code: ${c.bold}${fmt(mem.external.code)}${c.reset}`); 224 - lines.push(` Total: ${c.bold}${fmt(mem.external.total)}${c.reset}`); 225 - lines.push(''); 226 - 227 - lines.push(`${c.cyan}Intern Table${c.reset}`); 228 - lines.push(` Strings: ${c.bold}${mem.intern.count}${c.reset}`); 229 - lines.push(` Bytes: ${c.bold}${fmt(mem.intern.bytes)}${c.reset}`); 230 - lines.push(''); 231 - 232 - if (mem.vm) { 233 - lines.push(`${c.cyan}VM${c.reset}`); 234 - lines.push(` Stack: ${c.bold}${mem.vm.stackUsed} / ${mem.vm.stackSize}${c.reset}`); 235 - lines.push(` Frames: ${c.bold}${mem.vm.framesUsed} / ${mem.vm.maxFrames}${c.reset}`); 236 - lines.push(''); 307 + if (state.memoryOffset > maxOffset) { 308 + state.memoryOffset = maxOffset; 237 309 } 238 310 239 - lines.push(`${c.cyan}Process${c.reset}`); 240 - lines.push(` RSS: ${c.bold}${fmt(mem.rss)}${c.reset}`); 241 - if (mem.virtualSize) { 242 - lines.push(` Virtual: ${c.bold}${fmt(mem.virtualSize)}${c.reset}`); 243 - } 244 - lines.push(` C Stack: ${c.bold}${fmt(mem.cstack)}${c.reset}`); 245 - lines.push(''); 311 + const end = Math.min(memoryLines.length, state.memoryOffset + viewHeight); 312 + lines.push(...memoryLines.slice(state.memoryOffset, end)); 246 313 247 - while (lines.length < rows - 2) { 314 + while (lines.length < rows - footerLines) { 248 315 lines.push(''); 249 316 } 250 317 251 318 lines.push(''); 252 - lines.push(`${c.dim}m browse ยท q quit${c.reset} ${c.cyan}${fps.current} fps${c.reset}`); 319 + const status = memoryStatusText(); 320 + lines.push( 321 + `${c.dim}โ†‘โ†“ scroll ยท PgUp/PgDn ยท g/G top/bottom ยท c copy ยท m browse ยท q quit${c.reset} ${c.dim}[${state.memoryOffset + 1}-${end}/${memoryLines.length}]${c.reset} ${status}${status ? ' ' : ''}${c.cyan}${fps.current} fps${c.reset}` 322 + ); 253 323 } 254 324 255 325 return lines.map(l => pad(l, cols)).join('\n'); ··· 313 383 break; 314 384 case '\x1b[A': 315 385 case 'k': 316 - state.index = Math.max(0, state.index - 1); 386 + if (state.mode === 'memory') { 387 + state.memoryOffset = Math.max(0, state.memoryOffset - 1); 388 + } else { 389 + state.index = Math.max(0, state.index - 1); 390 + } 317 391 needsRender = true; 318 392 break; 319 393 case '\x1b[B': 320 394 case 'j': 321 - state.index = Math.min(state.filtered.length - 1, state.index + 1); 395 + if (state.mode === 'memory') { 396 + state.memoryOffset++; 397 + } else { 398 + state.index = Math.min(state.filtered.length - 1, state.index + 1); 399 + } 322 400 needsRender = true; 323 401 break; 324 402 case '\x1b[5~': 325 - state.index = Math.max(0, state.index - 10); 403 + if (state.mode === 'memory') { 404 + state.memoryOffset = Math.max(0, state.memoryOffset - Math.max(1, getRows() - 4)); 405 + } else { 406 + state.index = Math.max(0, state.index - 10); 407 + } 326 408 needsRender = true; 327 409 break; 328 410 case '\x1b[6~': 329 - state.index = Math.min(state.filtered.length - 1, state.index + 10); 411 + if (state.mode === 'memory') { 412 + state.memoryOffset += Math.max(1, getRows() - 4); 413 + } else { 414 + state.index = Math.min(state.filtered.length - 1, state.index + 10); 415 + } 330 416 needsRender = true; 331 417 break; 332 418 case 'g': 333 - state.index = 0; 419 + if (state.mode === 'memory') { 420 + state.memoryOffset = 0; 421 + } else { 422 + state.index = 0; 423 + } 334 424 needsRender = true; 335 425 break; 336 426 case 'G': 337 - state.index = state.filtered.length - 1; 427 + if (state.mode === 'memory') { 428 + state.memoryOffset = Number.MAX_SAFE_INTEGER; 429 + } else { 430 + state.index = state.filtered.length - 1; 431 + } 338 432 needsRender = true; 339 433 break; 340 434 case 'p': ··· 362 456 case 'm': 363 457 state.mode = state.mode === 'memory' ? 'browse' : 'memory'; 364 458 needsRender = true; 459 + break; 460 + case 'c': 461 + if (state.mode === 'memory') { 462 + copyMemoryStats(); 463 + needsRender = true; 464 + } 365 465 break; 366 466 case '/': 367 467 if (state.mode === 'browse') {
+1
include/oxc.h
··· 12 12 char *OXC_strip_types_owned( 13 13 const char *input, 14 14 const char *filename, 15 + int is_module, 15 16 size_t *out_len, 16 17 int *out_error, 17 18 char *error_output,
+1
include/utils.h
··· 28 28 char **buffer, 29 29 size_t len, 30 30 const char *filename, 31 + int is_module, 31 32 size_t *out_len, 32 33 const char **error_detail 33 34 );
+3 -1
src/esm/loader.c
··· 1147 1147 1148 1148 if (!mod->embedded_code) { 1149 1149 int strip_result = strip_typescript_inplace( 1150 - &content, size, mod->resolved_path, &js_len, &strip_detail 1150 + &content, size, mod->resolved_path, 1151 + mod->format != MODULE_EVAL_FORMAT_CJS, 1152 + &js_len, &strip_detail 1151 1153 ); 1152 1154 1153 1155 if (strip_result < 0) {
+2 -2
src/strip/src/ffi.rs
··· 36 36 37 37 #[unsafe(no_mangle)] 38 38 pub unsafe extern "C" fn OXC_strip_types_owned( 39 - input: *const c_char, filename: *const c_char, out_len: *mut usize, out_error: *mut c_int, error_output: *mut c_char, error_output_len: usize, 39 + input: *const c_char, filename: *const c_char, is_module: c_int, out_len: *mut usize, out_error: *mut c_int, error_output: *mut c_char, error_output_len: usize, 40 40 ) -> *mut c_char { 41 41 if !out_error.is_null() { 42 42 unsafe { *out_error = OXC_ERR_NULL_INPUT }; ··· 73 73 } 74 74 }; 75 75 76 - match strip_types_internal(input_str, filename_str) { 76 + match strip_types_internal(input_str, filename_str, is_module != 0) { 77 77 Ok(result) => { 78 78 let bytes = result.as_bytes(); 79 79 let alloc_len = bytes.len() + 1;
+2 -2
src/strip/src/strip.rs
··· 7 7 use oxc_span::SourceType; 8 8 use oxc_transformer::{TransformOptions, Transformer, TypeScriptOptions}; 9 9 10 - pub fn strip_types_internal(source: &str, filename: &str) -> Result<String, String> { 10 + pub fn strip_types_internal(source: &str, filename: &str, is_module: bool) -> Result<String, String> { 11 11 let allocator = Allocator::default(); 12 - let source_type = SourceType::from_path(filename).unwrap_or_else(|_| SourceType::ts()); 12 + let source_type = SourceType::from_path(filename).unwrap_or_else(|_| SourceType::ts()).with_module(is_module); 13 13 let parser_ret = Parser::new(&allocator, source, source_type).parse(); 14 14 15 15 if !parser_ret.errors.is_empty() {
+18 -1
src/types/ant.d.ts
··· 43 43 blocks: number; 44 44 } 45 45 46 + interface AntStringPoolInfo extends AntPoolInfo { 47 + pooled: AntPoolInfo; 48 + largeLive: AntPoolInfo; 49 + largeReusable: AntPoolInfo; 50 + largeQuarantine: AntPoolInfo; 51 + } 52 + 46 53 interface AntPoolStats { 47 54 rope: AntPoolInfo; 48 55 symbol: AntPoolInfo; 49 56 bigint: AntPoolInfo; 50 - string: AntPoolInfo; 57 + string: AntStringPoolInfo; 51 58 totalUsed: number; 52 59 totalCapacity: number; 53 60 } ··· 78 85 pools: AntPoolStats; 79 86 alloc: AntAllocStats; 80 87 external: AntExternalMemory; 88 + intern: { 89 + count: number; 90 + bytes: number; 91 + }; 92 + vm?: { 93 + stackSize: number; 94 + stackUsed: number; 95 + maxFrames: number; 96 + framesUsed: number; 97 + }; 81 98 cstack: number; 82 99 rss?: number; 83 100 virtualSize?: number;
+2 -1
src/utils.c
··· 129 129 char **buffer, 130 130 size_t len, 131 131 const char *filename, 132 + int is_module, 132 133 size_t *out_len, 133 134 const char **error_detail 134 135 ) { ··· 147 148 148 149 int strip_error = OXC_ERR_TRANSFORM_FAILED; 149 150 char *stripped = OXC_strip_types_owned( 150 - input, filename, 151 + input, filename, is_module, 151 152 &stripped_len, &strip_error, 152 153 error_buf, sizeof(error_buf) 153 154 );
+21
tests/test_promise_chained_catch_unhandled.cjs
··· 1 + const assert = require("node:assert"); 2 + const { spawnSync } = require("child_process"); 3 + 4 + const source = [ 5 + "async function explode(){ throw new Error('boom') }", 6 + "explode().then(() => {}).catch(() => console.log('chained-caught'))", 7 + ].join(" "); 8 + 9 + const result = spawnSync(process.execPath, ["-e", source], { 10 + encoding: "utf8", 11 + }); 12 + 13 + if (result.error) { 14 + throw result.error; 15 + } 16 + 17 + assert.strictEqual(result.status, 0, result.stderr || result.stdout); 18 + assert.match(result.stdout, /chained-caught/); 19 + assert.doesNotMatch(result.stderr, /Uncaught \\(in promise\\)/); 20 + 21 + console.log("promise chains with downstream catch are not reported as unhandled");
+41
tests/test_typescript_entry_tla.cjs
··· 1 + const { spawnSync } = require('child_process'); 2 + const fs = require('fs'); 3 + const os = require('os'); 4 + const path = require('path'); 5 + 6 + function assert(condition, message) { 7 + if (!condition) throw new Error(message); 8 + } 9 + 10 + const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'ant-ts-entry-tla-')); 11 + const scriptPath = path.join(tmpRoot, 'entry.ts'); 12 + 13 + fs.writeFileSync( 14 + scriptPath, 15 + [ 16 + 'const message: string = await Promise.resolve("ts tla ok");', 17 + 'console.log(message);', 18 + '', 19 + ].join('\n') 20 + ); 21 + 22 + const result = spawnSync(process.execPath, [scriptPath], { 23 + encoding: 'utf8', 24 + }); 25 + 26 + if (result.error) throw result.error; 27 + 28 + assert( 29 + result.status === 0, 30 + `expected direct .ts entry with top-level await to exit 0, got ${result.status}\nstdout:\n${result.stdout}\nstderr:\n${result.stderr}` 31 + ); 32 + assert( 33 + result.stdout === 'ts tla ok\n', 34 + `expected stdout to be ts tla ok, got ${JSON.stringify(result.stdout)}` 35 + ); 36 + assert( 37 + !/strip failed|await is only allowed within async functions/i.test(result.stderr), 38 + `expected no TypeScript strip/TLA parse error, got stderr:\n${result.stderr}` 39 + ); 40 + 41 + console.log('direct TypeScript entrypoint top-level await works');