Something went wrong. Try again.
javascript for 🐜's, a tiny runtime with big ambitions antjs.org
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154const assert = require('node:assert');const util = require('node:util');const { spawnSync } = require('node:child_process');const fs = require('node:fs');const os = require('node:os');const path = require('node:path');
const lines = (s) => s.split('\n');
function makeTypeError() { return new TypeError('boom'); }const te = makeTypeError();assert.strictEqual(lines(te.stack)[0], 'TypeError: boom');assert.match(lines(te.stack)[1], /^ {4}at makeTypeError \(.*test_error_stack_format\.cjs:\d+:\d+\)$/);assert.doesNotMatch(te.stack, /\x1b/);
const desc = Object.getOwnPropertyDescriptor(te, 'stack');assert.strictEqual(typeof desc.get, 'function');assert.strictEqual(typeof desc.set, 'function');assert.strictEqual(desc.enumerable, false);assert.deepStrictEqual(Object.getOwnPropertyNames(te).sort(), ['message', 'stack']);assert.strictEqual(Object.hasOwn(te, 'name'), false);assert.deepStrictEqual(Object.keys(te), []);
class MyErr extends Error {}const mine = new MyErr('x');assert.strictEqual(mine.name, 'Error');assert.strictEqual(Object.hasOwn(mine, 'name'), false);assert.strictEqual(lines(mine.stack)[0], 'Error: x');assert.strictEqual(lines(util.inspect(mine))[0], 'MyErr [Error]: x');
class MyError extends Error {}assert.strictEqual(lines(util.inspect(new MyError('y')))[0], 'MyError: y');
class Named extends Error { constructor(m) { super(m); this.name = 'Named'; } }const named = new Named('n');assert.strictEqual(lines(named.stack)[0], 'Named: n');assert.doesNotMatch(util.inspect(named), /name:/);
const early = new Error('early');const firstRead = early.stack;early.message = 'changed';assert.strictEqual(early.stack, firstRead);
const late = new Error('late');late.message = 'changed';assert.strictEqual(lines(late.stack)[0], 'Error: changed');
assert.strictEqual(lines(new Error().stack)[0], 'Error');assert.strictEqual(lines(Object.create(new Error('base')).stack)[0], 'Error: base');
const assigned = new Error('a');assigned.stack = 'custom';assert.strictEqual(assigned.stack, 'custom');assert.strictEqual(util.inspect(assigned), '[custom]');
for (const ctor of [AggregateError, SuppressedError]) { const err = ctor === AggregateError ? new AggregateError([], 'm') : new SuppressedError(1, 2, 'm'); assert.strictEqual(Object.hasOwn(err, 'name'), false, ctor.name); assert.strictEqual(lines(err.stack)[0], `${ctor.name}: m`);}
try { null.x; } catch (err) { assert.strictEqual(Object.hasOwn(err, 'name'), false); assert.match(lines(err.stack)[0], /^TypeError: /);}
const target = {};Error.captureStackTrace(target);assert.strictEqual(lines(target.stack)[0], 'Error');assert.deepStrictEqual(Object.keys(target), []);
const inspected = util.inspect(te);assert.strictEqual(lines(inspected)[0], 'TypeError: boom');assert.match(lines(inspected)[1], /^ {4}at makeTypeError /);
const withProps = new Error('outer', { cause: new Error('inner') });withProps.code = 'E1';const out = lines(util.inspect(withProps));assert.match(out.find((l) => l.startsWith(' at')), / \{$/);assert.ok(out.includes(" code: 'E1',"), out.join('\n'));assert.ok(out.some((l) => l === ' [cause]: Error: inner'), out.join('\n'));assert.strictEqual(out[out.length - 1], '}');
const nested = lines(util.inspect({ e: new RangeError('r') }));assert.strictEqual(nested[1], ' e: RangeError: r');assert.match(nested[2], /^ {6}at /);
const agg = util.inspect(new AggregateError([new Error('a')], 'agg'));assert.match(agg, /\n {2}\[errors\]: \[\n {4}Error: a\n {8}at /);
function depthError(n) { const e = n ? depthError(n - 1) : new Error('d'); return e; }const savedLimit = Error.stackTraceLimit;assert.strictEqual(savedLimit, 10);assert.strictEqual(lines(depthError(30).stack).length, 11);Error.stackTraceLimit = 2;assert.strictEqual(lines(depthError(30).stack).length, 3);Error.stackTraceLimit = 1.9;assert.strictEqual(lines(depthError(30).stack).length, 2);Error.stackTraceLimit = 0;assert.strictEqual(depthError(5).stack, 'Error: d');Error.stackTraceLimit = 'x';const unlimited = depthError(5);assert.strictEqual(unlimited.stack, undefined);assert.ok(Object.hasOwn(unlimited, 'stack'));Error.stackTraceLimit = Infinity;assert.ok(lines(depthError(40).stack).length > 41);Error.stackTraceLimit = savedLimit;
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'ant-error-stack-'));try { const file = path.join(root, 'uncaught.cjs'); fs.writeFileSync(file, "class E2 extends Error {}\nconst e = new E2('sub');\nconsole.log(JSON.stringify(e.stack.split('\\n')[0]));\nthrow e;\n"); const result = spawnSync(process.execPath, [file], { encoding: 'utf8', env: { ...process.env, NO_COLOR: '1' } }); const stderr = result.stderr.replace(/\x1b\[[0-9;]*m/g, ''); assert.strictEqual(result.status, 1); assert.strictEqual(result.stdout.trim(), '"Error: sub"'); assert.match(stderr, /uncaught\.cjs:2:\d+\n/); assert.match(stderr, /\n2 \| const e = new E2\('sub'\);\n/); assert.match(stderr, /\nE2 \[Error\]: sub\n {2}at /);
const staleFile = path.join(root, 'stale.cjs'); fs.writeFileSync(staleFile, [ 'function read(o) { try { return o.x; } catch { return 0; } }', 'function warm() { for (let i = 0; i < 5000; i++) read({ x: i }); }', 'warm();', 'read(null);', 'const g = { get v() { try { null.y; } catch {} return 1; } };', 'g.v;', "throw new Error('later');", '', ].join('\n')); const stale = spawnSync(process.execPath, [staleFile], { encoding: 'utf8', env: { ...process.env, NO_COLOR: '1' } }); const staleErr = stale.stderr.replace(/\x1b\[[0-9;]*m/g, ''); assert.strictEqual(stale.status, 1); assert.match(staleErr, /^.*stale\.cjs:7:\d+\n/, staleErr); assert.doesNotMatch(staleErr, /stale\.cjs:[1-6]:/, staleErr);
const handlerFile = path.join(root, 'handler.cjs'); fs.writeFileSync(handlerFile, [ "const e = new Error('real');", 'let reads = 0;', "Object.defineProperty(e, 'name', { get() { if (reads++ === 0) throw new Error('name getter'); return 'Error'; } });", "process.on('uncaughtException', (err) => console.log(err === e, err.message));", 'throw e;', '', ].join('\n')); const handler = spawnSync(process.execPath, [handlerFile], { encoding: 'utf8', env: { ...process.env, NO_COLOR: '1' } }); assert.strictEqual(handler.stdout.trim(), 'true real', handler.stdout + handler.stderr);} finally { fs.rmSync(root, { recursive: true, force: true });}
console.log('error stack format ok');