feat: budgeted console formatter (inspect builtin) - #416
Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (15)
📝 WalkthroughWalkthroughThe runtime replaces ChangesInspect formatter integration
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Console
participant BuiltinLoader
participant Inspect
participant NativeWrapper
Console->>BuiltinLoader: initialize inspect builtin
BuiltinLoader->>Inspect: execute inspect.js
Inspect-->>Console: cache formatter function
Console->>Inspect: format object or function
Inspect->>NativeWrapper: request wrapper hint when applicable
NativeWrapper-->>Inspect: return native hint
Inspect-->>Console: return bounded output
Possibly related PRs
Suggested reviewers: Poem
✨ Finishing Touches📝 Generate docstrings
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
5b5c4e2 to
c1cdf0e
Compare
…ed logging console.log without DevTools serialized entire object graphs through JSON.stringify with an O(n^2) seen-array, no depth or size limits, a hand-rolled array printer that only caught direct self-cycles, and a third bespoke dump in console.dir. A large object could hang the app for seconds and shared acyclic references printed as [Circular]. internal/inspect.js is a util.inspect-lite built on primordials: depth, per-collection and total-output budgets make unbounded work impossible; an ancestor set reports only true cycles; getters are never invoked (except the guarded error.stack read every error path already does); brands come from Object.prototype.toString so tampered prototypes cannot break or hijack logging. Native wrappers render as a short class-name hint via the binding bag instead of being walked. Console log/dir/assert all route through it, smart-stringify is retired, and the formatter doubles as the internal __inspect global.
a5b101e to
9720d56
Compare
What
Replaces the console's no-DevTools formatting pipeline — which could hang the app on a single
console.log— withinternal/inspect.js, a budgeted util.inspect-lite built on primordials. Stacked on #415 (primordials), which is stacked on #411 (builtins).The problem
console.log(obj)without a DevTools frontend serialized the whole object graph:JSON.stringify(obj, replacer, 2)with no depth or size limit — logging a store/component tree serialized everything reachable, then shipped megabytes through a stack-frame regex and NSLog.seenarray made cycle tracking O(n²) — quadratic interpreter work under jitless — and never popped on subtree exit, so shared acyclic references falsely printed[Circular].JSON.stringifyinvokes getters andtoJSON— a log line could execute arbitrary user code.console.dirhad a third bespoke dump with the same issues.The fix
inspect.js(function-body builtin, primordials-clean — it must work precisely when the app is broken):Set(enter/exit) — true cycles say[Circular], diamonds print normally, O(1) membership.[Getter]/[Setter]tags). Two deliberate exceptions: a guardederror.stackread (V8 materializes stacks via a lazy accessor and every error path in the runtime already reads it), and customtoStringoverrides — NativeScript core'sViewBase/Observableconvention (Button(42)-style short forms) is honored, matching the previous console: an own-or-inheritedtoStringother thanObject.prototype's is detected via descriptors (no invocation to detect), then invoked guarded and capped; broken overrides degrade to structural rendering.Object.prototype.toString, Map/Set walked through captured iteratornext(early-exit capable, unlikeforEach), sizes via captured accessor getters. Verified by device tests that breakArray.prototype.*,Object.keys,JSON.stringifyetc. and log anyway.[UILabel],[class UIView],[Pointer]) via abinding.getNativeWrapperHintnative callback instead of walking native-backed graphs.[Function: name]/[class Name], TypedArrays/ArrayBuffers with lengths, null-prototype and constructor-name prefixes, sparse arrays, BigInt, symbols.__inspectglobal (testability + app-level escape hatch).C++ side shrinks:
console.log/dir/assertall route through one cached formatter; the array printer, the dir dump, andsmart-stringify.js(+ itsHelpers/Cachesplumbing) are deleted. Top-level strings still print raw. If the formatter ever fails to initialize, logging degrades toToDetailStringinstead of breaking.Also extends
primordials.js(Set methods, iteratornextcaptures, accessor getters, brand/regexp helpers) and the ESLint captured-statics list.Output changes to be aware of
Logs now look like Node's inspect output —
{ a: 1, b: [Circular] },Map(3) { ... },... 150 more items, truncation markers — instead of pretty-printed JSON.console.dirkeeps its dump markers but uses depth 4.Testing
stackgetters and tampered prototypes.InspectTests.js): cycles vs diamonds, caps, getter non-invocation, native-wrapper hints, tampered-prototype formatting, and a regression test thatconsole.logof a 5000-node cyclic graph completes in bounded time.Also fixes a latent js2c bug this PR flushed out: builtin sources containing non-ASCII bytes (UTF-8 >= 0x80) failed to compile as
const chararray initializers; the generator now emitsunsigned char.Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Tests