Skip to content

Add JSONL runtime parsing and module imports#182

Merged
frostney merged 4 commits into
mainfrom
feature/jsonl-support
Apr 4, 2026
Merged

Add JSONL runtime parsing and module imports#182
frostney merged 4 commits into
mainfrom
feature/jsonl-support

Conversation

@frostney
Copy link
Copy Markdown
Owner

@frostney frostney commented Apr 4, 2026

Summary

  • Adds a new JSONL built-in with JSONL.parse(...) and JSONL.parseChunk(...) for newline-delimited JSON runtime use.
  • Supports .jsonl imports in the module loader, exposing each non-empty line as a zero-based string export.
  • Wires JSONL into the default runtime globals and updates file-extension handling and built-in registration.
  • Adds end-to-end tests for parsing, chunked parsing, and .jsonl module imports/re-exports.
  • Updates docs and README examples to describe the new JSONL surface.

Fixes #176

Testing

  • Added JavaScript coverage in tests/built-ins/JSONL/parse.js.
  • Added JavaScript coverage in tests/built-ins/JSONL/parseChunk.js.
  • Added module import coverage in tests/language/modules/jsonl-import.js.
  • Updated documentation examples and built-in listings to reflect the new behavior.

Summary by CodeRabbit

  • New Features

    • Import .jsonl files as modules (each non-empty line exported by zero-based string index)
    • Runtime APIs: JSONL.parse(...) and JSONL.parseChunk(...) for full and chunked parsing (Bun-compatible)
  • Documentation

    • Docs updated with JSONL import semantics, runtime examples, error/line-number behavior, and YAML parsing/multi-document guidance
  • Tests

    • Added test suites and fixtures validating JSONL parse, parseChunk, module imports and re-exports

- Add `JSONL.parse` and `JSONL.parseChunk` built-ins
- Support `.jsonl` module exports and loader integration
- Document JSONL behavior and add end-to-end tests
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 4, 2026

Warning

Rate limit exceeded

@frostney has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 0 minutes and 3 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 0 minutes and 3 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 19979e7c-8f82-4557-bede-cdd8d0c05f4f

📥 Commits

Reviewing files that changed from the base of the PR and between 5ff7590 and 324e39a.

📒 Files selected for processing (5)
  • tests/built-ins/JSONL/parseChunk.js
  • tests/language/modules/helpers/event-stream-with-blank-lines.jsonl
  • tests/language/modules/jsonl-import.js
  • units/Goccia.Builtins.JSONL.pas
  • units/Goccia.Modules.ContentProvider.Test.pas
📝 Walkthrough

Walkthrough

Adds JSONL (newline-delimited JSON) support: a line-aware parser with chunked parsing, a runtime JSONL builtin (parse/parseChunk), .jsonl module import handling exporting records as zero-based string-indexed named exports, and engine/bootstrap/infrastructure and tests to integrate the feature.

Changes

Cohort / File(s) Summary
Documentation
README.md, docs/built-ins.md, docs/design-decisions.md, docs/language-restrictions.md
Documented JSONL module import semantics (zero-based string keys), JSONL.parse and JSONL.parseChunk APIs, chunk semantics, and examples.
Core Parser
units/Goccia.JSONL.pas
New TGocciaJSONLParser: full and chunked parsing, UTF‑8 BOM handling, blank-line skipping, per-line JSON parsing with line-numbered errors, and chunk resume semantics (Values/Read/Done/ErrorMessage).
Builtin API
units/Goccia.Builtins.JSONL.pas
New TGocciaJSONLBuiltin exposing JSONL.parse and JSONL.parseChunk with string/Uint8Array input support, offset clamping, and Bun-compatible return shape (values, read, done, error).
Engine & Bootstrap
units/Goccia.Engine.pas, units/Goccia.Runtime.Bootstrap.pas
Added ggJSONL global, included in DefaultGlobals, engine/bootstrap fields and lifecycle to register the JSONL builtin and expose it via BuiltinJSONL.
Module loader & Extensions
units/Goccia.Modules.Loader.pas, units/Goccia.FileExtensions.pas, units/Goccia.ScriptLoader.Globals.pas
Recognize .jsonl as structured-data; load .jsonl via TGocciaJSONLParser and populate module exports with stringified numeric indices ("0", "1", …); added EXT_JSONL and predicates for structured-globals detection.
Constants
units/Goccia.Constants.PropertyNames.pas
Added PROP_VALUES, PROP_READ, and PROP_ERROR constants used by chunked parse result objects.
Tests & Fixtures
tests/built-ins/JSONL/parse.js, tests/built-ins/JSONL/parseChunk.js, tests/language/modules/jsonl-import.js, tests/language/modules/helpers/event-stream.jsonl, tests/language/modules/helpers/jsonl-re-exporter.js
Added unit tests covering parse/parseChunk behaviors (mixed types, BOM, incomplete records, error line numbers), and module import/re-export of .jsonl with string-indexed bindings.

Sequence Diagram(s)

sequenceDiagram
    participant Script as Script (caller / test)
    participant Builtin as JSONL Builtin
    participant Parser as TGocciaJSONLParser
    participant JSON as TGocciaJSONParser

    Script->>Builtin: JSONL.parse(text or Uint8Array)
    Builtin->>Parser: Parse(input)
    Parser->>JSON: Parse each non-empty line
    JSON-->>Parser: parsed value / parse error
    Parser-->>Builtin: TGocciaArrayValue or raise EGocciaJSONLParseError
    Builtin-->>Script: return array (or throw SyntaxError with "JSONL line N")
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Poem

🐰
Line by line I nibble through the stream,
Each JSON hop a tiny data dream,
Blank leaves skipped, errors flagged by name,
Chunks resume — the parser plays the game,
Hooray! JSONL hops into the frame.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR partially implements issue #176: JSONL.parse and parseChunk are provided [#176], .jsonl imports are integrated [#176], and tests/docs are added [#176]. However, the recommended v1 contract of a synthetic { records } export is not implemented; instead, per-line numeric string exports ("0", "1", …) are used, contrary to the issue's preference [#176]. Consider reverting .jsonl module imports to use a stable synthetic { records } export shape as recommended in issue #176, or document the deviation and confirm stakeholder acceptance of numeric-string exports.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding JSONL runtime parsing and module import support with clear, concise phrasing.
Out of Scope Changes check ✅ Passed All changes are within scope: JSONL parsing utilities, runtime builtin, module-loader integration, file-extension handling, and related tests/documentation additions directly address issue #176 objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/jsonl-support

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 4, 2026

Suite Timing

Suite Metric Interpreted Bytecode
Tests Total 3645 3645
Tests Passed 3604 ✅ 3645 ✅
Tests Skipped 41 0
Tests Execution 192.0ms 178.6ms
Tests Engine 357.2ms 640.4ms
Benchmarks Total 274 274
Benchmarks Duration 7.45min 6.24min

Measured on ubuntu-latest x64.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 4, 2026

Benchmark Results

274 benchmarks

Interpreted: 🟢 78 improved · 🔴 44 regressed · 152 unchanged · avg +0.2%
Bytecode: 🟢 47 improved · 🔴 79 regressed · 148 unchanged · avg -0.5%

arraybuffer.js — Interp: 🟢 9, 5 unch. · avg +1.3% · Bytecode: 🟢 6, 🔴 2, 6 unch. · avg +1.7%
Benchmark Interpreted Δ Bytecode Δ
create ArrayBuffer(0) 456,015 ops/sec [452,710..457,384] → 461,175 ops/sec [458,139..464,539] 🟢 +1.1% 478,619 ops/sec [472,000..488,725] → 504,371 ops/sec [498,239..506,390] 🟢 +5.4%
create ArrayBuffer(64) 438,406 ops/sec [436,377..440,088] → 442,251 ops/sec [441,512..444,961] 🟢 +0.9% 455,988 ops/sec [453,996..458,297] → 478,179 ops/sec [476,773..480,339] 🟢 +4.9%
create ArrayBuffer(1024) 341,837 ops/sec [341,109..344,624] → 346,602 ops/sec [302,690..350,363] ~ overlap (+1.4%) 357,713 ops/sec [354,628..362,489] → 373,371 ops/sec [369,640..376,649] 🟢 +4.4%
create ArrayBuffer(8192) 153,053 ops/sec [152,389..153,223] → 154,559 ops/sec [152,083..155,640] ~ overlap (+1.0%) 158,029 ops/sec [156,489..158,725] → 162,326 ops/sec [156,478..165,381] ~ overlap (+2.7%)
slice full buffer (64 bytes) 508,442 ops/sec [500,633..511,188] → 525,582 ops/sec [520,436..527,791] 🟢 +3.4% 605,475 ops/sec [604,488..612,031] → 610,000 ops/sec [597,816..615,965] ~ overlap (+0.7%)
slice half buffer (512 of 1024 bytes) 435,288 ops/sec [432,648..437,712] → 443,369 ops/sec [440,519..446,097] 🟢 +1.9% 508,298 ops/sec [487,406..523,150] → 521,285 ops/sec [517,092..525,922] ~ overlap (+2.6%)
slice with negative indices 428,735 ops/sec [427,265..429,648] → 436,988 ops/sec [435,959..438,910] 🟢 +1.9% 551,434 ops/sec [549,054..554,238] → 559,088 ops/sec [557,776..561,050] 🟢 +1.4%
slice empty range 488,022 ops/sec [485,156..489,240] → 499,408 ops/sec [498,406..499,759] 🟢 +2.3% 583,060 ops/sec [581,747..585,482] → 595,217 ops/sec [591,310..599,909] 🟢 +2.1%
byteLength access 1,317,459 ops/sec [1,312,359..1,322,289] → 1,330,651 ops/sec [1,326,129..1,336,592] 🟢 +1.0% 1,517,850 ops/sec [1,511,492..1,523,121] → 1,474,063 ops/sec [1,471,815..1,475,021] 🔴 -2.9%
Symbol.toStringTag access 1,012,854 ops/sec [1,010,797..1,017,427] → 1,031,019 ops/sec [1,029,218..1,032,500] 🟢 +1.8% 1,041,802 ops/sec [1,034,785..1,045,130] → 1,021,421 ops/sec [1,020,496..1,022,583] 🔴 -2.0%
ArrayBuffer.isView 730,456 ops/sec [726,497..731,404] → 746,494 ops/sec [743,401..748,607] 🟢 +2.2% 830,172 ops/sec [824,169..831,342] → 842,275 ops/sec [836,000..846,402] 🟢 +1.5%
clone ArrayBuffer(64) 421,200 ops/sec [419,738..423,035] → 418,785 ops/sec [417,221..420,932] ~ overlap (-0.6%) 470,976 ops/sec [467,679..480,986] → 481,243 ops/sec [480,005..481,455] ~ overlap (+2.2%)
clone ArrayBuffer(1024) 331,473 ops/sec [329,757..332,229] → 329,642 ops/sec [328,464..329,902] ~ overlap (-0.6%) 362,359 ops/sec [358,834..364,602] → 360,498 ops/sec [358,478..362,094] ~ overlap (-0.5%)
clone ArrayBuffer inside object 272,096 ops/sec [269,396..273,726] → 273,125 ops/sec [272,732..275,452] ~ overlap (+0.4%) 287,047 ops/sec [285,801..289,003] → 289,630 ops/sec [288,687..289,841] ~ overlap (+0.9%)
arrays.js — Interp: 🟢 7, 🔴 3, 9 unch. · avg +0.3% · Bytecode: 🟢 3, 🔴 6, 10 unch. · avg -0.0%
Benchmark Interpreted Δ Bytecode Δ
Array.from length 100 13,359 ops/sec [13,327..13,438] → 13,235 ops/sec [13,226..13,339] ~ overlap (-0.9%) 13,741 ops/sec [13,486..13,942] → 13,433 ops/sec [13,393..13,468] 🔴 -2.2%
Array.from 10 elements 220,768 ops/sec [220,661..222,282] → 218,407 ops/sec [218,087..218,944] 🔴 -1.1% 236,252 ops/sec [233,545..241,683] → 233,085 ops/sec [232,075..233,700] ~ overlap (-1.3%)
Array.of 10 elements 280,635 ops/sec [279,923..281,196] → 277,918 ops/sec [276,393..278,320] 🔴 -1.0% 303,899 ops/sec [302,799..304,269] → 306,218 ops/sec [301,085..306,990] ~ overlap (+0.8%)
spread into new array 329,143 ops/sec [322,226..331,369] → 325,453 ops/sec [324,531..326,627] ~ overlap (-1.1%) 195,757 ops/sec [194,133..200,505] → 196,028 ops/sec [194,941..199,471] ~ overlap (+0.1%)
map over 50 elements 24,831 ops/sec [24,784..24,921] → 24,937 ops/sec [24,843..25,090] ~ overlap (+0.4%) 26,036 ops/sec [25,800..26,720] → 25,858 ops/sec [25,831..25,987] ~ overlap (-0.7%)
filter over 50 elements 22,471 ops/sec [22,413..22,545] → 22,671 ops/sec [22,615..22,858] 🟢 +0.9% 20,326 ops/sec [20,265..20,349] → 22,510 ops/sec [22,470..22,758] 🟢 +10.7%
reduce sum 50 elements 26,128 ops/sec [25,993..26,174] → 26,635 ops/sec [26,591..26,642] 🟢 +1.9% 19,287 ops/sec [19,229..19,398] → 18,790 ops/sec [18,709..18,821] 🔴 -2.6%
forEach over 50 elements 23,027 ops/sec [22,975..23,125] → 23,188 ops/sec [23,166..23,227] 🟢 +0.7% 26,609 ops/sec [26,473..27,856] → 26,630 ops/sec [26,596..26,636] ~ overlap (+0.1%)
find in 50 elements 32,476 ops/sec [32,411..32,607] → 33,109 ops/sec [33,027..33,188] 🟢 +1.9% 29,983 ops/sec [29,843..31,074] → 29,345 ops/sec [29,226..29,474] 🔴 -2.1%
sort 20 elements 12,398 ops/sec [12,363..12,433] → 12,547 ops/sec [12,485..12,612] 🟢 +1.2% 13,448 ops/sec [13,165..13,832] → 12,749 ops/sec [12,732..12,784] 🔴 -5.2%
flat nested array 113,313 ops/sec [112,937..114,318] → 112,466 ops/sec [110,850..112,665] 🔴 -0.7% 132,758 ops/sec [131,156..137,707] → 131,162 ops/sec [130,808..131,667] ~ overlap (-1.2%)
flatMap 71,829 ops/sec [71,661..72,239] → 71,434 ops/sec [71,173..71,772] ~ overlap (-0.5%) 81,421 ops/sec [80,603..83,234] → 81,041 ops/sec [80,262..81,604] ~ overlap (-0.5%)
map inside map (5x5) 20,347 ops/sec [20,247..20,526] → 20,215 ops/sec [20,118..20,365] ~ overlap (-0.6%) 22,057 ops/sec [21,878..22,885] → 22,001 ops/sec [21,901..22,256] ~ overlap (-0.3%)
filter inside map (5x10) 15,403 ops/sec [15,385..15,425] → 15,452 ops/sec [15,389..15,475] ~ overlap (+0.3%) 15,232 ops/sec [14,872..15,507] → 15,804 ops/sec [15,669..15,941] 🟢 +3.8%
reduce inside map (5x10) 19,103 ops/sec [18,976..19,220] → 19,293 ops/sec [19,181..19,357] ~ overlap (+1.0%) 16,268 ops/sec [15,998..16,762] → 15,639 ops/sec [15,583..15,694] 🔴 -3.9%
forEach inside forEach (5x10) 16,456 ops/sec [16,334..16,464] → 16,918 ops/sec [16,893..16,966] 🟢 +2.8% 16,611 ops/sec [16,369..17,080] → 16,532 ops/sec [16,479..16,605] ~ overlap (-0.5%)
find inside some (10x10) 13,263 ops/sec [13,174..13,364] → 13,552 ops/sec [13,510..13,608] 🟢 +2.2% 12,714 ops/sec [12,620..13,408] → 12,488 ops/sec [12,445..12,498] 🔴 -1.8%
map+filter chain nested (5x20) 5,139 ops/sec [5,086..5,162] → 5,160 ops/sec [5,140..5,164] ~ overlap (+0.4%) 4,991 ops/sec [4,990..5,002] → 5,281 ops/sec [5,239..5,297] 🟢 +5.8%
reduce flatten (10x5) 38,507 ops/sec [38,024..38,862] → 37,706 ops/sec [37,220..38,097] ~ overlap (-2.1%) 17,775 ops/sec [17,328..18,145] → 17,812 ops/sec [17,730..17,999] ~ overlap (+0.2%)
async-await.js — Interp: 🟢 1, 🔴 1, 4 unch. · avg -0.3% · Bytecode: 🟢 5, 1 unch. · avg +4.0%
Benchmark Interpreted Δ Bytecode Δ
single await 373,131 ops/sec [371,158..374,071] → 371,868 ops/sec [370,966..372,787] ~ overlap (-0.3%) 382,719 ops/sec [380,790..386,032] → 410,257 ops/sec [408,907..411,493] 🟢 +7.2%
multiple awaits 167,545 ops/sec [166,550..168,177] → 166,456 ops/sec [165,456..167,083] ~ overlap (-0.7%) 170,184 ops/sec [167,781..173,887] → 178,920 ops/sec [178,238..179,335] 🟢 +5.1%
await non-Promise value 843,117 ops/sec [833,499..847,186] → 836,286 ops/sec [832,974..839,357] ~ overlap (-0.8%) 1,091,041 ops/sec [1,076,397..1,111,025] → 1,074,148 ops/sec [1,067,444..1,076,493] ~ overlap (-1.5%)
await with try/catch 363,372 ops/sec [361,675..365,377] → 361,103 ops/sec [360,738..361,922] ~ overlap (-0.6%) 377,576 ops/sec [375,044..381,291] → 403,374 ops/sec [400,708..405,548] 🟢 +6.8%
await Promise.all 52,187 ops/sec [51,991..52,332] → 50,812 ops/sec [50,689..51,159] 🔴 -2.6% 50,533 ops/sec [50,337..50,736] → 51,942 ops/sec [51,552..52,337] 🟢 +2.8%
nested async function call 186,352 ops/sec [185,666..187,393] → 192,502 ops/sec [191,534..193,698] 🟢 +3.3% 223,022 ops/sec [220,837..229,398] → 231,284 ops/sec [230,886..232,307] 🟢 +3.7%
classes.js — Interp: 🟢 10, 🔴 2, 19 unch. · avg +0.6% · Bytecode: 🟢 2, 🔴 4, 25 unch. · avg -0.7%
Benchmark Interpreted Δ Bytecode Δ
simple class new 139,681 ops/sec [138,530..140,351] → 139,593 ops/sec [139,052..139,904] ~ overlap (-0.1%) 201,821 ops/sec [201,378..203,539] → 204,701 ops/sec [203,036..206,361] ~ overlap (+1.4%)
class with defaults 109,925 ops/sec [109,343..110,309] → 110,781 ops/sec [110,407..111,259] 🟢 +0.8% 143,658 ops/sec [140,609..145,498] → 143,308 ops/sec [141,737..143,810] ~ overlap (-0.2%)
50 instances via Array.from 5,753 ops/sec [5,727..5,770] → 5,840 ops/sec [5,813..5,859] 🟢 +1.5% 7,678 ops/sec [7,645..7,868] → 7,872 ops/sec [7,796..7,902] ~ overlap (+2.5%)
instance method call 70,439 ops/sec [69,669..70,558] → 71,673 ops/sec [71,373..71,830] 🟢 +1.8% 90,992 ops/sec [90,785..91,367] → 91,307 ops/sec [91,053..91,570] ~ overlap (+0.3%)
static method call 112,116 ops/sec [111,431..112,842] → 112,861 ops/sec [112,393..113,156] ~ overlap (+0.7%) 183,604 ops/sec [179,326..189,860] → 181,927 ops/sec [181,642..182,414] ~ overlap (-0.9%)
single-level inheritance 55,085 ops/sec [55,012..55,097] → 55,750 ops/sec [55,673..55,770] 🟢 +1.2% 74,277 ops/sec [73,232..74,936] → 74,684 ops/sec [73,969..75,359] ~ overlap (+0.5%)
two-level inheritance 47,246 ops/sec [47,087..47,351] → 47,922 ops/sec [47,834..48,021] 🟢 +1.4% 60,808 ops/sec [59,155..61,788] → 60,915 ops/sec [60,119..61,866] ~ overlap (+0.2%)
private field access 70,032 ops/sec [69,755..70,171] → 70,716 ops/sec [70,283..71,023] 🟢 +1.0% 89,867 ops/sec [88,696..92,220] → 90,746 ops/sec [90,034..91,486] ~ overlap (+1.0%)
private methods 77,680 ops/sec [77,465..78,083] → 77,894 ops/sec [76,832..78,354] ~ overlap (+0.3%) 96,874 ops/sec [96,088..99,068] → 98,125 ops/sec [97,596..98,963] ~ overlap (+1.3%)
getter/setter access 75,663 ops/sec [75,334..76,176] → 75,599 ops/sec [75,204..75,749] ~ overlap (-0.1%) 105,593 ops/sec [104,187..107,949] → 103,729 ops/sec [103,238..104,047] 🔴 -1.8%
class decorator (identity) 92,426 ops/sec [91,884..93,347] → 94,036 ops/sec [93,253..94,251] ~ overlap (+1.7%) 101,400 ops/sec [100,562..103,729] → 103,514 ops/sec [102,594..106,943] ~ overlap (+2.1%)
class decorator (wrapping) 54,287 ops/sec [53,910..54,683] → 54,953 ops/sec [54,858..55,429] 🟢 +1.2% 60,822 ops/sec [57,086..62,544] → 61,434 ops/sec [59,004..62,852] ~ overlap (+1.0%)
identity method decorator 64,513 ops/sec [63,954..65,124] → 65,307 ops/sec [65,045..65,757] ~ overlap (+1.2%) 88,586 ops/sec [83,651..93,555] → 87,234 ops/sec [82,049..92,520] ~ overlap (-1.5%)
wrapping method decorator 51,802 ops/sec [51,727..51,944] → 54,497 ops/sec [53,896..54,706] 🟢 +5.2% 62,299 ops/sec [59,428..65,771] → 62,913 ops/sec [59,845..67,601] ~ overlap (+1.0%)
stacked method decorators (x3) 35,586 ops/sec [35,253..35,877] → 35,973 ops/sec [35,773..36,060] ~ overlap (+1.1%) 46,156 ops/sec [42,654..49,456] → 43,017 ops/sec [41,350..46,409] ~ overlap (-6.8%)
identity field decorator 72,374 ops/sec [71,400..72,988] → 71,901 ops/sec [71,637..72,440] ~ overlap (-0.7%) 73,839 ops/sec [73,021..74,528] → 76,686 ops/sec [74,707..79,307] 🟢 +3.9%
field initializer decorator 60,057 ops/sec [59,154..60,419] → 60,317 ops/sec [60,085..60,584] ~ overlap (+0.4%) 68,018 ops/sec [62,987..69,619] → 70,878 ops/sec [64,551..78,498] ~ overlap (+4.2%)
getter decorator (identity) 65,827 ops/sec [65,375..66,321] → 64,768 ops/sec [64,591..65,051] 🔴 -1.6% 75,932 ops/sec [74,322..77,182] → 70,164 ops/sec [69,667..72,043] 🔴 -7.6%
setter decorator (identity) 54,954 ops/sec [54,643..55,474] → 55,008 ops/sec [54,753..55,175] ~ overlap (+0.1%) 60,170 ops/sec [58,960..60,629] → 62,810 ops/sec [61,657..64,206] 🟢 +4.4%
static method decorator 70,838 ops/sec [70,101..71,551] → 70,564 ops/sec [70,309..70,930] ~ overlap (-0.4%) 81,496 ops/sec [80,054..86,121] → 78,232 ops/sec [77,536..79,446] 🔴 -4.0%
static field decorator 82,561 ops/sec [81,876..83,165] → 81,719 ops/sec [81,183..82,469] ~ overlap (-1.0%) 89,678 ops/sec [86,231..93,629] → 88,311 ops/sec [85,296..94,954] ~ overlap (-1.5%)
private method decorator 53,595 ops/sec [53,413..53,741] → 54,352 ops/sec [54,007..54,398] 🟢 +1.4% 72,494 ops/sec [69,810..77,179] → 71,131 ops/sec [68,527..74,316] ~ overlap (-1.9%)
private field decorator 59,054 ops/sec [58,876..59,378] → 58,443 ops/sec [58,267..58,678] 🔴 -1.0% 67,902 ops/sec [64,156..71,785] → 61,864 ops/sec [61,807..62,201] 🔴 -8.9%
plain auto-accessor (no decorator) 102,671 ops/sec [101,060..104,709] → 103,449 ops/sec [101,535..105,713] ~ overlap (+0.8%) 98,021 ops/sec [96,581..101,756] → 99,250 ops/sec [97,223..102,007] ~ overlap (+1.3%)
auto-accessor with decorator 56,005 ops/sec [54,371..57,294] → 55,382 ops/sec [54,331..56,055] ~ overlap (-1.1%) 60,228 ops/sec [57,382..63,647] → 57,662 ops/sec [56,361..63,297] ~ overlap (-4.3%)
decorator writing metadata 44,464 ops/sec [44,411..44,570] → 44,693 ops/sec [44,203..45,322] ~ overlap (+0.5%) 51,402 ops/sec [50,482..55,911] → 50,323 ops/sec [49,950..54,663] ~ overlap (-2.1%)
static getter read 124,994 ops/sec [124,278..125,805] → 126,905 ops/sec [125,932..128,151] 🟢 +1.5% 172,210 ops/sec [170,646..173,366] → 172,608 ops/sec [171,599..173,577] ~ overlap (+0.2%)
static getter/setter pair 98,042 ops/sec [97,693..98,704] → 98,406 ops/sec [97,901..99,355] ~ overlap (+0.4%) 121,009 ops/sec [120,587..124,949] → 118,855 ops/sec [117,353..121,342] ~ overlap (-1.8%)
inherited static getter 75,863 ops/sec [75,131..76,230] → 75,897 ops/sec [75,460..76,453] ~ overlap (+0.0%) 99,596 ops/sec [98,440..101,358] → 98,061 ops/sec [97,085..99,063] ~ overlap (-1.5%)
inherited static setter 81,824 ops/sec [81,551..82,036] → 81,443 ops/sec [80,769..81,911] ~ overlap (-0.5%) 106,101 ops/sec [104,361..108,195] → 104,974 ops/sec [101,216..107,467] ~ overlap (-1.1%)
inherited static getter with this binding 69,744 ops/sec [68,968..70,234] → 70,512 ops/sec [69,917..70,787] ~ overlap (+1.1%) 90,402 ops/sec [89,868..93,212] → 89,730 ops/sec [89,231..90,589] ~ overlap (-0.7%)
closures.js — Interp: 🟢 5, 6 unch. · avg +1.2% · Bytecode: 🔴 7, 4 unch. · avg -3.7%
Benchmark Interpreted Δ Bytecode Δ
closure over single variable 132,921 ops/sec [132,219..133,210] → 137,785 ops/sec [136,700..139,476] 🟢 +3.7% 276,880 ops/sec [272,554..282,645] → 269,502 ops/sec [268,361..270,393] 🔴 -2.7%
closure over multiple variables 118,662 ops/sec [117,979..118,959] → 122,066 ops/sec [121,193..123,323] 🟢 +2.9% 197,602 ops/sec [195,356..205,069] → 192,073 ops/sec [190,902..197,284] ~ overlap (-2.8%)
nested closures 126,225 ops/sec [125,937..127,307] → 127,895 ops/sec [126,350..128,631] ~ overlap (+1.3%) 235,423 ops/sec [223,620..247,622] → 228,481 ops/sec [220,918..235,892] ~ overlap (-2.9%)
function as argument 94,473 ops/sec [94,057..94,975] → 95,437 ops/sec [94,948..96,515] ~ overlap (+1.0%) 249,455 ops/sec [245,129..259,502] → 241,799 ops/sec [240,752..243,980] 🔴 -3.1%
function returning function 118,020 ops/sec [117,627..118,865] → 119,431 ops/sec [118,799..120,857] ~ overlap (+1.2%) 273,716 ops/sec [269,458..282,758] → 278,618 ops/sec [277,006..282,059] ~ overlap (+1.8%)
compose two functions 71,661 ops/sec [71,085..71,731] → 72,130 ops/sec [71,951..72,994] 🟢 +0.7% 157,101 ops/sec [152,390..158,710] → 137,401 ops/sec [136,524..142,722] 🔴 -12.5%
fn.call 153,169 ops/sec [152,847..154,079] → 154,578 ops/sec [154,176..154,897] 🟢 +0.9% 235,851 ops/sec [229,155..239,128] → 225,324 ops/sec [224,425..226,145] 🔴 -4.5%
fn.apply 112,007 ops/sec [111,822..113,058] → 111,602 ops/sec [111,245..112,045] ~ overlap (-0.4%) 155,947 ops/sec [155,413..158,040] → 147,602 ops/sec [146,810..148,756] 🔴 -5.4%
fn.bind 144,104 ops/sec [143,729..144,772] → 144,995 ops/sec [144,531..147,014] ~ overlap (+0.6%) 279,117 ops/sec [277,155..280,663] → 277,200 ops/sec [275,280..277,771] ~ overlap (-0.7%)
recursive sum to 50 11,969 ops/sec [11,939..12,039] → 12,162 ops/sec [12,058..12,357] 🟢 +1.6% 23,549 ops/sec [23,384..24,214] → 22,913 ops/sec [22,857..22,970] 🔴 -2.7%
recursive tree traversal 20,572 ops/sec [20,378..20,659] → 20,556 ops/sec [20,304..20,880] ~ overlap (-0.1%) 36,734 ops/sec [36,057..37,367] → 34,647 ops/sec [34,216..34,868] 🔴 -5.7%
collections.js — Interp: 🟢 4, 8 unch. · avg +0.7% · Bytecode: 🔴 2, 10 unch. · avg -0.6%
Benchmark Interpreted Δ Bytecode Δ
add 50 elements 6,826 ops/sec [6,817..6,842] → 7,057 ops/sec [7,007..7,072] 🟢 +3.4% 7,157 ops/sec [7,123..7,247] → 7,183 ops/sec [7,128..7,228] ~ overlap (+0.4%)
has lookup (50 elements) 87,465 ops/sec [87,381..87,533] → 89,025 ops/sec [88,446..89,728] 🟢 +1.8% 98,586 ops/sec [96,712..99,641] → 97,500 ops/sec [97,198..97,611] ~ overlap (-1.1%)
delete elements 46,650 ops/sec [46,496..46,852] → 46,676 ops/sec [46,308..46,891] ~ overlap (+0.1%) 49,613 ops/sec [49,427..50,584] → 49,011 ops/sec [48,475..49,265] 🔴 -1.2%
forEach iteration 15,733 ops/sec [15,631..15,759] → 15,699 ops/sec [15,638..15,803] ~ overlap (-0.2%) 15,013 ops/sec [14,875..15,149] → 15,075 ops/sec [15,021..15,078] ~ overlap (+0.4%)
spread to array 28,929 ops/sec [28,461..29,439] → 28,484 ops/sec [28,269..28,901] ~ overlap (-1.5%) 223,504 ops/sec [220,073..226,899] → 215,936 ops/sec [215,014..220,714] ~ overlap (-3.4%)
deduplicate array 38,508 ops/sec [38,239..39,027] → 38,279 ops/sec [37,880..38,919] ~ overlap (-0.6%) 70,989 ops/sec [70,399..72,677] → 72,628 ops/sec [72,388..72,858] ~ overlap (+2.3%)
set 50 entries 5,145 ops/sec [5,102..5,228] → 5,245 ops/sec [5,191..5,303] ~ overlap (+1.9%) 5,689 ops/sec [5,592..5,816] → 5,538 ops/sec [5,509..5,569] 🔴 -2.7%
get lookup (50 entries) 84,666 ops/sec [84,306..85,019] → 86,323 ops/sec [86,038..87,081] 🟢 +2.0% 93,878 ops/sec [92,225..95,461] → 92,668 ops/sec [92,618..92,703] ~ overlap (-1.3%)
has check 126,828 ops/sec [126,270..127,226] → 128,885 ops/sec [128,856..128,985] 🟢 +1.6% 144,361 ops/sec [142,429..149,819] → 143,664 ops/sec [143,498..143,724] ~ overlap (-0.5%)
delete entries 45,590 ops/sec [45,399..45,942] → 45,703 ops/sec [45,337..45,939] ~ overlap (+0.2%) 47,852 ops/sec [47,353..49,430] → 47,940 ops/sec [47,613..48,042] ~ overlap (+0.2%)
forEach iteration 15,833 ops/sec [15,694..16,008] → 15,831 ops/sec [15,663..15,956] ~ overlap (-0.0%) 15,455 ops/sec [15,336..15,715] → 15,300 ops/sec [15,225..15,403] ~ overlap (-1.0%)
keys/values/entries 7,845 ops/sec [7,798..7,930] → 7,834 ops/sec [7,797..8,002] ~ overlap (-0.1%) 27,063 ops/sec [26,797..27,461] → 27,381 ops/sec [27,063..27,772] ~ overlap (+1.2%)
destructuring.js — Interp: 🟢 4, 🔴 3, 15 unch. · avg +0.1% · Bytecode: 🔴 15, 7 unch. · avg -2.5%
Benchmark Interpreted Δ Bytecode Δ
simple array destructuring 376,516 ops/sec [369,240..380,396] → 386,121 ops/sec [382,683..388,391] 🟢 +2.6% 265,142 ops/sec [263,565..267,710] → 269,111 ops/sec [267,449..269,983] ~ overlap (+1.5%)
with rest element 246,726 ops/sec [242,679..249,143] → 244,591 ops/sec [242,973..245,697] ~ overlap (-0.9%) 212,371 ops/sec [212,103..212,700] → 209,385 ops/sec [208,430..210,329] 🔴 -1.4%
with defaults 389,624 ops/sec [386,938..392,154] → 380,181 ops/sec [376,454..382,680] 🔴 -2.4% 313,840 ops/sec [312,599..323,841] → 308,755 ops/sec [305,450..311,606] 🔴 -1.6%
skip elements 400,237 ops/sec [398,369..403,073] → 405,669 ops/sec [402,691..409,697] ~ overlap (+1.4%) 289,504 ops/sec [287,332..296,589] → 287,927 ops/sec [286,697..289,174] ~ overlap (-0.5%)
nested array destructuring 166,800 ops/sec [163,941..169,455] → 167,662 ops/sec [166,429..169,353] ~ overlap (+0.5%) 92,663 ops/sec [89,273..93,208] → 91,612 ops/sec [91,305..91,801] ~ overlap (-1.1%)
swap variables 499,055 ops/sec [494,857..503,141] → 500,608 ops/sec [497,670..503,521] ~ overlap (+0.3%) 340,994 ops/sec [326,739..349,063] → 335,205 ops/sec [330,200..337,465] ~ overlap (-1.7%)
simple object destructuring 304,299 ops/sec [301,518..304,807] → 308,164 ops/sec [305,733..309,648] 🟢 +1.3% 414,440 ops/sec [409,965..420,576] → 402,139 ops/sec [394,554..408,225] 🔴 -3.0%
with defaults 343,697 ops/sec [339,836..347,024] → 343,594 ops/sec [340,663..347,920] ~ overlap (-0.0%) 559,140 ops/sec [554,398..567,783] → 556,490 ops/sec [552,735..558,358] ~ overlap (-0.5%)
with renaming 330,336 ops/sec [328,021..331,550] → 323,717 ops/sec [322,814..325,556] 🔴 -2.0% 444,806 ops/sec [437,307..448,314] → 439,604 ops/sec [433,450..441,997] ~ overlap (-1.2%)
nested object destructuring 151,183 ops/sec [146,995..152,755] → 152,936 ops/sec [151,792..153,833] ~ overlap (+1.2%) 204,052 ops/sec [202,903..206,296] → 199,890 ops/sec [199,192..200,972] 🔴 -2.0%
rest properties 184,468 ops/sec [183,385..186,200] → 187,467 ops/sec [186,653..188,470] 🟢 +1.6% 190,487 ops/sec [189,429..190,873] → 188,610 ops/sec [185,995..189,416] 🔴 -1.0%
object parameter 94,784 ops/sec [93,937..95,663] → 94,640 ops/sec [93,930..95,457] ~ overlap (-0.2%) 155,480 ops/sec [153,792..158,194] → 152,038 ops/sec [150,177..153,744] 🔴 -2.2%
array parameter 121,533 ops/sec [120,990..122,038] → 121,255 ops/sec [121,005..121,615] ~ overlap (-0.2%) 113,631 ops/sec [112,935..117,327] → 110,917 ops/sec [109,916..111,861] 🔴 -2.4%
mixed destructuring in map 33,281 ops/sec [33,121..33,378] → 32,960 ops/sec [32,811..33,223] ~ overlap (-1.0%) 36,041 ops/sec [35,453..36,888] → 34,231 ops/sec [33,830..34,606] 🔴 -5.0%
forEach with array destructuring 63,792 ops/sec [62,985..64,330] → 63,874 ops/sec [63,248..64,180] ~ overlap (+0.1%) 43,574 ops/sec [43,289..44,482] → 41,655 ops/sec [41,579..42,227] 🔴 -4.4%
map with array destructuring 63,303 ops/sec [62,671..64,644] → 63,589 ops/sec [63,225..63,776] ~ overlap (+0.5%) 42,869 ops/sec [42,571..44,256] → 41,868 ops/sec [41,622..42,379] 🔴 -2.3%
filter with array destructuring 66,512 ops/sec [66,171..66,800] → 65,362 ops/sec [65,124..65,800] 🔴 -1.7% 48,695 ops/sec [47,583..49,329] → 47,273 ops/sec [46,904..47,437] 🔴 -2.9%
reduce with array destructuring 73,478 ops/sec [72,415..73,668] → 72,333 ops/sec [71,502..72,841] ~ overlap (-1.6%) 47,465 ops/sec [46,351..47,839] → 46,551 ops/sec [45,999..47,138] ~ overlap (-1.9%)
map with object destructuring 72,646 ops/sec [71,893..73,063] → 72,328 ops/sec [71,043..72,539] ~ overlap (-0.4%) 91,626 ops/sec [89,888..93,461] → 86,529 ops/sec [85,558..87,349] 🔴 -5.6%
map with nested destructuring 60,125 ops/sec [59,641..60,644] → 60,847 ops/sec [60,627..61,314] ~ overlap (+1.2%) 86,029 ops/sec [84,642..86,745] → 81,338 ops/sec [81,122..82,011] 🔴 -5.5%
map with rest in destructuring 40,534 ops/sec [40,095..41,249] → 41,959 ops/sec [41,643..42,007] 🟢 +3.5% 24,731 ops/sec [24,506..25,427] → 23,664 ops/sec [23,284..23,779] 🔴 -4.3%
map with defaults in destructuring 56,490 ops/sec [56,283..56,727] → 56,126 ops/sec [55,879..56,532] ~ overlap (-0.6%) 66,649 ops/sec [66,052..68,975] → 63,434 ops/sec [62,843..63,605] 🔴 -4.8%
fibonacci.js — Interp: 🟢 5, 🔴 1, 2 unch. · avg +1.0% · Bytecode: 🟢 1, 🔴 5, 2 unch. · avg -1.5%
Benchmark Interpreted Δ Bytecode Δ
recursive fib(15) 319 ops/sec [313..321] → 327 ops/sec [325..332] 🟢 +2.3% 814 ops/sec [807..822] → 788 ops/sec [787..790] 🔴 -3.1%
recursive fib(20) 29 ops/sec [29..29] → 30 ops/sec [29..30] 🟢 +1.7% 73 ops/sec [73..76] → 71 ops/sec [71..71] 🔴 -2.9%
recursive fib(15) typed 319 ops/sec [318..323] → 332 ops/sec [329..335] 🟢 +4.1% 849 ops/sec [842..861] → 816 ops/sec [813..819] 🔴 -3.8%
recursive fib(20) typed 29 ops/sec [29..29] → 29 ops/sec [29..29] 🟢 +1.2% 76 ops/sec [75..78] → 74 ops/sec [74..75] 🔴 -2.4%
iterative fib(20) via reduce 12,176 ops/sec [12,139..12,213] → 12,003 ops/sec [11,959..12,023] 🔴 -1.4% 19,097 ops/sec [18,457..19,302] → 18,117 ops/sec [17,965..18,239] 🔴 -5.1%
iterator fib(20) 9,623 ops/sec [9,500..9,674] → 9,538 ops/sec [9,515..9,553] ~ overlap (-0.9%) 18,263 ops/sec [17,999..18,664] → 18,250 ops/sec [17,988..18,295] ~ overlap (-0.1%)
iterator fib(20) via Iterator.from + take 15,738 ops/sec [15,361..15,778] → 15,521 ops/sec [15,474..15,617] ~ overlap (-1.4%) 20,652 ops/sec [20,397..21,250] → 21,217 ops/sec [21,086..21,284] ~ overlap (+2.7%)
iterator fib(20) last value via reduce 11,303 ops/sec [11,243..11,399] → 11,586 ops/sec [11,543..11,602] 🟢 +2.5% 14,076 ops/sec [13,811..14,334] → 14,472 ops/sec [14,400..14,668] 🟢 +2.8%
for-of.js — Interp: 🔴 3, 4 unch. · avg -2.2% · Bytecode: 🟢 2, 🔴 3, 2 unch. · avg +0.1%
Benchmark Interpreted Δ Bytecode Δ
for...of with 10-element array 47,737 ops/sec [47,349..47,902] → 46,198 ops/sec [45,842..46,550] 🔴 -3.2% 168,214 ops/sec [166,600..169,038] → 170,869 ops/sec [168,929..172,248] ~ overlap (+1.6%)
for...of with 100-element array 5,479 ops/sec [5,428..5,504] → 5,351 ops/sec [5,327..5,389] 🔴 -2.3% 18,904 ops/sec [18,587..19,482] → 18,720 ops/sec [18,644..18,812] ~ overlap (-1.0%)
for...of with string (10 chars) 34,136 ops/sec [33,806..34,480] → 33,719 ops/sec [33,415..34,072] ~ overlap (-1.2%) 87,189 ops/sec [87,079..90,597] → 85,533 ops/sec [85,142..86,234] 🔴 -1.9%
for...of with Set (10 elements) 47,695 ops/sec [46,395..48,105] → 46,654 ops/sec [46,547..46,830] ~ overlap (-2.2%) 161,683 ops/sec [160,186..164,173] → 159,268 ops/sec [158,826..159,362] 🔴 -1.5%
for...of with Map entries (10 entries) 30,089 ops/sec [29,855..30,378] → 29,338 ops/sec [29,118..29,391] 🔴 -2.5% 28,649 ops/sec [28,248..29,058] → 29,635 ops/sec [29,549..29,783] 🟢 +3.4%
for...of with destructuring 40,185 ops/sec [38,996..41,047] → 39,216 ops/sec [39,059..39,509] ~ overlap (-2.4%) 38,365 ops/sec [38,238..38,574] → 37,864 ops/sec [37,753..38,022] 🔴 -1.3%
for-await-of with sync array 44,716 ops/sec [44,012..45,165] → 44,006 ops/sec [43,659..44,091] ~ overlap (-1.6%) 127,727 ops/sec [127,568..128,831] → 129,789 ops/sec [129,177..131,873] 🟢 +1.6%
helpers/bench-module.js — Interp: 0 · Bytecode: 0
Benchmark Interpreted Δ Bytecode Δ
iterators.js — Interp: 🔴 7, 13 unch. · avg -1.4% · Bytecode: 🟢 5, 🔴 2, 13 unch. · avg +1.0%
Benchmark Interpreted Δ Bytecode Δ
Iterator.from({next}).toArray() — 20 elements 15,317 ops/sec [15,239..15,536] → 15,167 ops/sec [15,102..15,271] ~ overlap (-1.0%) 20,552 ops/sec [20,101..21,084] → 20,512 ops/sec [20,379..20,679] ~ overlap (-0.2%)
Iterator.from({next}).toArray() — 50 elements 6,633 ops/sec [6,541..6,663] → 6,590 ops/sec [6,545..6,608] ~ overlap (-0.7%) 9,123 ops/sec [8,858..9,155] → 9,012 ops/sec [8,934..9,043] ~ overlap (-1.2%)
spread pre-wrapped iterator — 20 elements 11,413 ops/sec [11,223..11,447] → 11,321 ops/sec [11,251..11,446] ~ overlap (-0.8%) 19,776 ops/sec [19,429..20,193] → 20,368 ops/sec [19,534..20,489] ~ overlap (+3.0%)
Iterator.from({next}).forEach — 50 elements 4,638 ops/sec [4,609..4,658] → 4,530 ops/sec [4,500..4,595] 🔴 -2.3% 5,634 ops/sec [5,485..5,714] → 5,687 ops/sec [5,631..5,785] ~ overlap (+0.9%)
Iterator.from({next}).reduce — 50 elements 4,631 ops/sec [4,587..4,656] → 4,535 ops/sec [4,523..4,563] 🔴 -2.1% 5,294 ops/sec [5,248..5,374] → 5,462 ops/sec [5,403..5,481] 🟢 +3.2%
wrap array iterator 165,887 ops/sec [164,287..168,332] → 157,811 ops/sec [153,771..159,564] 🔴 -4.9% 178,005 ops/sec [173,284..181,064] → 186,734 ops/sec [183,380..188,294] 🟢 +4.9%
wrap plain {next()} object 10,886 ops/sec [10,783..11,039] → 10,548 ops/sec [10,427..10,641] 🔴 -3.1% 14,167 ops/sec [14,039..14,319] → 14,380 ops/sec [14,245..14,568] ~ overlap (+1.5%)
map + toArray (50 elements) 4,731 ops/sec [4,691..4,753] → 4,540 ops/sec [4,529..4,568] 🔴 -4.1% 5,920 ops/sec [5,873..6,069] → 5,608 ops/sec [5,561..5,649] 🔴 -5.3%
filter + toArray (50 elements) 4,572 ops/sec [4,564..4,573] → 4,480 ops/sec [4,431..4,495] 🔴 -2.0% 5,603 ops/sec [5,529..5,738] → 5,656 ops/sec [5,626..5,668] ~ overlap (+1.0%)
take(10) + toArray (50 element source) 28,105 ops/sec [27,879..28,335] → 27,831 ops/sec [27,739..27,918] ~ overlap (-1.0%) 35,285 ops/sec [34,827..35,759] → 35,628 ops/sec [35,509..35,813] ~ overlap (+1.0%)
drop(40) + toArray (50 element source) 6,788 ops/sec [6,758..6,826] → 6,607 ops/sec [6,477..6,690] 🔴 -2.7% 9,035 ops/sec [8,985..9,158] → 9,062 ops/sec [8,990..9,142] ~ overlap (+0.3%)
chained map + filter + take (100 element source) 8,260 ops/sec [8,183..8,293] → 8,181 ops/sec [8,114..8,237] ~ overlap (-1.0%) 9,971 ops/sec [9,887..10,078] → 9,862 ops/sec [9,805..9,904] ~ overlap (-1.1%)
some + every (50 elements) 2,648 ops/sec [2,645..2,655] → 2,661 ops/sec [2,648..2,676] ~ overlap (+0.5%) 3,548 ops/sec [3,508..3,568] → 3,545 ops/sec [3,525..3,549] ~ overlap (-0.1%)
find (50 elements) 5,815 ops/sec [5,760..5,872] → 5,760 ops/sec [5,746..5,783] ~ overlap (-1.0%) 7,073 ops/sec [7,021..7,133] → 7,044 ops/sec [7,002..7,054] ~ overlap (-0.4%)
array.values().map().filter().toArray() 8,157 ops/sec [8,088..8,230] → 8,069 ops/sec [8,015..8,148] ~ overlap (-1.1%) 9,878 ops/sec [9,829..9,902] → 9,573 ops/sec [9,525..9,583] 🔴 -3.1%
array.values().take(5).toArray() 210,266 ops/sec [207,609..214,870] → 211,238 ops/sec [210,725..211,374] ~ overlap (+0.5%) 234,869 ops/sec [233,582..237,806] → 240,232 ops/sec [238,875..241,895] 🟢 +2.3%
array.values().drop(45).toArray() 195,170 ops/sec [194,740..195,201] → 194,846 ops/sec [193,113..197,472] ~ overlap (-0.2%) 213,828 ops/sec [213,097..217,549] → 216,158 ops/sec [215,656..217,536] ~ overlap (+1.1%)
map.entries() chained helpers 10,203 ops/sec [10,083..10,294] → 10,101 ops/sec [10,025..10,173] ~ overlap (-1.0%) 6,008 ops/sec [5,928..6,064] → 6,111 ops/sec [6,064..6,173] ~ overlap (+1.7%)
set.values() chained helpers 17,002 ops/sec [16,846..17,098] → 16,955 ops/sec [16,737..17,158] ~ overlap (-0.3%) 18,089 ops/sec [18,042..18,155] → 19,797 ops/sec [19,642..19,839] 🟢 +9.4%
string iterator map + toArray 13,549 ops/sec [13,410..13,615] → 13,579 ops/sec [13,536..13,681] ~ overlap (+0.2%) 14,535 ops/sec [14,498..14,612] → 14,785 ops/sec [14,752..14,851] 🟢 +1.7%
json.js — Interp: 🔴 8, 12 unch. · avg -1.2% · Bytecode: 🟢 3, 🔴 4, 13 unch. · avg -0.7%
Benchmark Interpreted Δ Bytecode Δ
parse simple object 172,308 ops/sec [171,566..174,061] → 172,232 ops/sec [170,540..172,897] ~ overlap (-0.0%) 181,662 ops/sec [180,509..183,897] → 181,560 ops/sec [180,061..181,659] ~ overlap (-0.1%)
parse nested object 106,995 ops/sec [105,208..108,022] → 104,461 ops/sec [104,290..104,796] 🔴 -2.4% 112,656 ops/sec [111,525..112,938] → 110,333 ops/sec [109,663..110,669] 🔴 -2.1%
parse array of objects 63,230 ops/sec [62,380..63,643] → 61,516 ops/sec [61,307..61,784] 🔴 -2.7% 64,769 ops/sec [64,531..66,048] → 65,068 ops/sec [64,391..65,413] ~ overlap (+0.5%)
parse large flat object 69,277 ops/sec [68,509..70,208] → 68,407 ops/sec [68,162..68,654] ~ overlap (-1.3%) 75,426 ops/sec [73,384..78,206] → 72,549 ops/sec [72,414..72,771] 🔴 -3.8%
parse mixed types 79,760 ops/sec [78,766..80,716] → 77,816 ops/sec [77,376..78,051] 🔴 -2.4% 84,883 ops/sec [81,408..86,816] → 81,668 ops/sec [81,301..82,320] ~ overlap (-3.8%)
stringify simple object 171,951 ops/sec [170,560..173,666] → 168,534 ops/sec [168,157..169,542] 🔴 -2.0% 179,274 ops/sec [177,331..182,729] → 181,651 ops/sec [179,141..182,351] ~ overlap (+1.3%)
stringify nested object 95,250 ops/sec [94,859..95,721] → 95,273 ops/sec [94,499..96,286] ~ overlap (+0.0%) 100,560 ops/sec [100,323..100,939] → 100,290 ops/sec [99,541..100,803] ~ overlap (-0.3%)
stringify array of objects 44,581 ops/sec [44,423..44,638] → 44,897 ops/sec [44,330..45,128] ~ overlap (+0.7%) 43,581 ops/sec [43,407..43,903] → 44,866 ops/sec [44,754..45,102] 🟢 +2.9%
stringify mixed types 71,889 ops/sec [70,696..72,340] → 70,666 ops/sec [70,414..70,967] ~ overlap (-1.7%) 73,696 ops/sec [72,669..76,696] → 73,118 ops/sec [72,414..73,435] ~ overlap (-0.8%)
reviver doubles numbers 49,296 ops/sec [48,597..49,586] → 48,760 ops/sec [47,354..49,446] ~ overlap (-1.1%) 53,136 ops/sec [51,218..54,127] → 54,521 ops/sec [53,336..55,467] ~ overlap (+2.6%)
reviver filters properties 41,398 ops/sec [41,161..41,629] → 41,165 ops/sec [40,851..41,572] ~ overlap (-0.6%) 44,187 ops/sec [42,922..44,482] → 43,707 ops/sec [43,540..43,903] ~ overlap (-1.1%)
reviver on nested object 52,653 ops/sec [52,140..52,787] → 51,685 ops/sec [48,299..52,313] ~ overlap (-1.8%) 56,015 ops/sec [54,102..57,757] → 55,425 ops/sec [54,639..55,923] ~ overlap (-1.1%)
reviver on array 32,392 ops/sec [32,177..32,610] → 32,489 ops/sec [32,442..32,654] ~ overlap (+0.3%) 34,383 ops/sec [32,015..35,623] → 33,247 ops/sec [32,785..33,845] ~ overlap (-3.3%)
replacer function doubles numbers 42,912 ops/sec [42,835..42,949] → 42,178 ops/sec [41,942..42,377] 🔴 -1.7% 47,837 ops/sec [46,629..49,447] → 47,530 ops/sec [47,323..47,671] ~ overlap (-0.6%)
replacer function excludes properties 56,204 ops/sec [55,951..56,831] → 55,532 ops/sec [55,197..55,898] 🔴 -1.2% 58,116 ops/sec [57,706..58,334] → 58,799 ops/sec [58,470..59,320] 🟢 +1.2%
array replacer (allowlist) 99,936 ops/sec [97,418..100,638] → 97,495 ops/sec [97,210..97,618] ~ overlap (-2.4%) 101,887 ops/sec [100,681..103,145] → 105,334 ops/sec [104,018..105,923] 🟢 +3.4%
stringify with 2-space indent 79,802 ops/sec [78,843..80,234] → 79,291 ops/sec [78,990..79,364] ~ overlap (-0.6%) 85,296 ops/sec [83,208..86,897] → 83,849 ops/sec [83,161..84,876] ~ overlap (-1.7%)
stringify with tab indent 80,151 ops/sec [79,816..80,629] → 79,347 ops/sec [78,703..79,679] 🔴 -1.0% 84,665 ops/sec [82,942..87,474] → 83,300 ops/sec [82,869..84,774] ~ overlap (-1.6%)
parse then stringify 49,728 ops/sec [49,451..50,068] → 49,322 ops/sec [48,784..49,721] ~ overlap (-0.8%) 54,632 ops/sec [53,302..55,255] → 53,092 ops/sec [53,021..53,152] 🔴 -2.8%
stringify then parse 31,054 ops/sec [30,758..31,158] → 30,446 ops/sec [30,301..30,702] 🔴 -2.0% 33,552 ops/sec [33,293..34,618] → 32,440 ops/sec [32,331..32,548] 🔴 -3.3%
jsx.jsx — Interp: 🟢 3, 🔴 7, 11 unch. · avg -0.7% · Bytecode: 🟢 9, 🔴 5, 7 unch. · avg +1.3%
Benchmark Interpreted Δ Bytecode Δ
simple element 220,523 ops/sec [214,082..223,851] → 215,477 ops/sec [214,826..216,314] ~ overlap (-2.3%) 317,408 ops/sec [312,710..328,208] → 336,119 ops/sec [328,123..340,033] ~ overlap (+5.9%)
self-closing element 225,066 ops/sec [224,662..225,742] → 229,667 ops/sec [225,972..231,170] 🟢 +2.0% 349,837 ops/sec [342,537..358,655] → 348,920 ops/sec [347,874..349,200] ~ overlap (-0.3%)
element with string attribute 179,145 ops/sec [178,249..179,899] → 180,042 ops/sec [179,724..181,559] ~ overlap (+0.5%) 251,496 ops/sec [250,081..254,867] → 263,159 ops/sec [262,311..264,751] 🟢 +4.6%
element with multiple attributes 161,105 ops/sec [160,562..161,328] → 156,143 ops/sec [154,295..157,474] 🔴 -3.1% 211,167 ops/sec [207,191..214,662] → 204,649 ops/sec [203,941..205,412] 🔴 -3.1%
element with expression attribute 168,508 ops/sec [167,631..169,462] → 168,133 ops/sec [167,338..168,620] ~ overlap (-0.2%) 249,265 ops/sec [247,398..255,497] → 259,295 ops/sec [257,277..260,759] 🟢 +4.0%
text child 216,433 ops/sec [215,536..217,871] → 212,473 ops/sec [209,400..215,344] 🔴 -1.8% 327,951 ops/sec [323,093..335,864] → 320,677 ops/sec [319,523..322,797] 🔴 -2.2%
expression child 218,033 ops/sec [216,052..218,584] → 208,800 ops/sec [207,750..209,921] 🔴 -4.2% 313,441 ops/sec [310,558..322,785] → 335,266 ops/sec [332,264..336,471] 🟢 +7.0%
mixed text and expression 200,273 ops/sec [199,523..201,386] → 201,846 ops/sec [199,731..204,003] ~ overlap (+0.8%) 292,218 ops/sec [290,050..295,723] → 292,192 ops/sec [288,209..301,060] ~ overlap (-0.0%)
nested elements (3 levels) 83,920 ops/sec [83,458..84,432] → 81,414 ops/sec [80,434..81,735] 🔴 -3.0% 121,498 ops/sec [121,120..122,000] → 123,622 ops/sec [122,339..125,180] 🟢 +1.7%
sibling children 61,022 ops/sec [60,498..61,217] → 60,812 ops/sec [60,315..61,145] ~ overlap (-0.3%) 89,021 ops/sec [88,175..90,016] → 87,622 ops/sec [87,098..88,081] 🔴 -1.6%
component element 152,091 ops/sec [150,394..152,866] → 151,983 ops/sec [150,918..153,533] ~ overlap (-0.1%) 221,349 ops/sec [218,372..222,091] → 231,307 ops/sec [230,588..234,315] 🟢 +4.5%
component with children 94,015 ops/sec [93,588..94,113] → 95,679 ops/sec [94,846..96,019] 🟢 +1.8% 142,230 ops/sec [141,072..144,435] → 136,551 ops/sec [135,487..136,774] 🔴 -4.0%
dotted component 128,742 ops/sec [127,762..129,468] → 127,005 ops/sec [126,598..127,261] 🔴 -1.3% 174,887 ops/sec [172,210..175,643] → 180,009 ops/sec [179,638..180,568] 🟢 +2.9%
empty fragment 224,018 ops/sec [221,703..225,491] → 220,908 ops/sec [218,639..222,377] ~ overlap (-1.4%) 368,580 ops/sec [367,240..371,845] → 370,398 ops/sec [368,822..370,923] ~ overlap (+0.5%)
fragment with children 60,732 ops/sec [60,476..61,091] → 60,496 ops/sec [60,076..60,760] ~ overlap (-0.4%) 90,871 ops/sec [89,888..91,698] → 93,220 ops/sec [92,938..93,916] 🟢 +2.6%
spread attributes 113,529 ops/sec [113,384..115,167] → 110,956 ops/sec [110,376..111,950] 🔴 -2.3% 135,669 ops/sec [134,955..136,996] → 135,329 ops/sec [134,758..136,275] ~ overlap (-0.3%)
spread with overrides 99,057 ops/sec [98,667..99,675] → 96,111 ops/sec [93,043..96,845] 🔴 -3.0% 116,549 ops/sec [115,600..119,306] → 120,818 ops/sec [120,218..121,155] 🟢 +3.7%
shorthand props 162,355 ops/sec [160,443..163,840] → 163,653 ops/sec [160,193..164,033] ~ overlap (+0.8%) 248,156 ops/sec [245,439..251,176] → 237,965 ops/sec [237,099..238,697] 🔴 -4.1%
nav bar structure 27,548 ops/sec [27,373..27,701] → 28,207 ops/sec [28,137..28,515] 🟢 +2.4% 39,815 ops/sec [39,708..40,520] → 41,171 ops/sec [40,928..41,526] 🟢 +3.4%
card component tree 32,222 ops/sec [32,014..32,536] → 32,471 ops/sec [32,175..32,974] ~ overlap (+0.8%) 45,868 ops/sec [44,751..46,862] → 45,632 ops/sec [45,369..45,815] ~ overlap (-0.5%)
10 list items via Array.from 14,982 ops/sec [14,877..15,047] → 14,865 ops/sec [14,756..15,005] ~ overlap (-0.8%) 19,373 ops/sec [18,074..20,033] → 19,668 ops/sec [19,563..19,769] ~ overlap (+1.5%)
modules.js — Interp: 🟢 3, 6 unch. · avg +1.0% · Bytecode: 🔴 2, 7 unch. · avg -1.1%
Benchmark Interpreted Δ Bytecode Δ
call imported function 466,490 ops/sec [463,174..472,496] → 479,084 ops/sec [473,559..484,816] 🟢 +2.7% 656,714 ops/sec [636,666..679,928] → 654,676 ops/sec [648,524..656,688] ~ overlap (-0.3%)
call two imported functions 259,348 ops/sec [257,764..261,113] → 269,148 ops/sec [266,943..270,757] 🟢 +3.8% 359,426 ops/sec [358,579..372,994] → 356,966 ops/sec [355,906..361,880] ~ overlap (-0.7%)
read imported constant 1,672,060 ops/sec [1,666,400..1,678,479] → 1,665,156 ops/sec [1,661,038..1,688,597] ~ overlap (-0.4%) 3,392,837 ops/sec [3,329,076..3,469,540] → 3,384,329 ops/sec [3,381,167..3,390,265] ~ overlap (-0.3%)
read imported string 1,667,485 ops/sec [1,654,226..1,678,707] → 1,662,554 ops/sec [1,646,288..1,671,489] ~ overlap (-0.3%) 3,446,070 ops/sec [3,364,494..3,519,818] → 3,380,147 ops/sec [3,376,033..3,386,600] ~ overlap (-1.9%)
read JSON string property 1,684,984 ops/sec [1,671,928..1,691,680] → 1,680,542 ops/sec [1,672,212..1,684,432] ~ overlap (-0.3%) 3,424,162 ops/sec [3,381,091..3,505,221] → 3,353,134 ops/sec [3,349,499..3,361,742] 🔴 -2.1%
read JSON number property 1,672,106 ops/sec [1,657,236..1,682,142] → 1,653,336 ops/sec [1,636,419..1,666,802] ~ overlap (-1.1%) 3,426,043 ops/sec [3,379,374..3,565,107] → 3,377,980 ops/sec [3,362,270..3,380,675] ~ overlap (-1.4%)
read JSON boolean property 1,674,450 ops/sec [1,660,631..1,687,242] → 1,676,751 ops/sec [1,637,097..1,689,148] ~ overlap (+0.1%) 3,413,123 ops/sec [3,378,123..3,532,535] → 3,370,918 ops/sec [3,353,241..3,381,032] ~ overlap (-1.2%)
read JSON array property 1,685,985 ops/sec [1,669,847..1,698,450] → 1,677,055 ops/sec [1,662,646..1,694,861] ~ overlap (-0.5%) 3,409,440 ops/sec [3,382,651..3,447,684] → 3,381,243 ops/sec [3,378,130..3,384,312] ~ overlap (-0.8%)
read multiple JSON properties 935,187 ops/sec [923,452..935,921] → 978,835 ops/sec [967,244..979,511] 🟢 +4.7% 3,083,223 ops/sec [3,075,031..3,226,955] → 3,050,574 ops/sec [3,045,703..3,053,010] 🔴 -1.1%
numbers.js — Interp: 🟢 9, 2 unch. · avg +2.7% · Bytecode: 🟢 2, 🔴 3, 6 unch. · avg -0.7%
Benchmark Interpreted Δ Bytecode Δ
integer arithmetic 505,147 ops/sec [502,576..505,797] → 510,806 ops/sec [503,570..520,594] ~ overlap (+1.1%) 1,452,522 ops/sec [1,438,527..1,492,879] → 1,387,674 ops/sec [1,368,797..1,421,975] 🔴 -4.5%
floating point arithmetic 572,856 ops/sec [569,713..576,345] → 616,723 ops/sec [614,054..624,300] 🟢 +7.7% 966,319 ops/sec [952,175..1,008,488] → 939,270 ops/sec [934,334..940,114] 🔴 -2.8%
number coercion 182,472 ops/sec [179,899..184,059] → 188,535 ops/sec [186,624..189,224] 🟢 +3.3% 221,468 ops/sec [220,361..224,031] → 219,298 ops/sec [218,224..219,545] 🔴 -1.0%
toFixed 102,150 ops/sec [101,615..102,995] → 101,851 ops/sec [101,640..102,632] ~ overlap (-0.3%) 112,572 ops/sec [111,030..114,838] → 113,636 ops/sec [113,030..114,378] ~ overlap (+0.9%)
toString 152,006 ops/sec [149,672..152,757] → 154,336 ops/sec [153,512..154,484] 🟢 +1.5% 187,274 ops/sec [185,754..194,215] → 187,377 ops/sec [186,301..187,992] ~ overlap (+0.1%)
valueOf 224,707 ops/sec [222,483..226,504] → 227,302 ops/sec [226,591..230,618] 🟢 +1.2% 264,227 ops/sec [261,123..266,368] → 268,050 ops/sec [267,093..269,324] 🟢 +1.4%
toPrecision 141,216 ops/sec [138,110..142,224] → 143,724 ops/sec [142,900..144,544] 🟢 +1.8% 164,827 ops/sec [164,631..165,527] → 164,847 ops/sec [164,069..165,137] ~ overlap (+0.0%)
Number.isNaN 299,490 ops/sec [297,766..300,539] → 313,032 ops/sec [309,830..314,831] 🟢 +4.5% 335,751 ops/sec [326,206..345,530] → 326,605 ops/sec [325,480..327,409] ~ overlap (-2.7%)
Number.isFinite 300,203 ops/sec [299,812..300,723] → 306,077 ops/sec [304,382..307,094] 🟢 +2.0% 312,129 ops/sec [308,923..314,205] → 312,409 ops/sec [311,266..313,178] ~ overlap (+0.1%)
Number.isInteger 302,329 ops/sec [301,124..304,208] → 315,036 ops/sec [313,384..317,542] 🟢 +4.2% 328,317 ops/sec [327,834..329,569] → 333,870 ops/sec [332,480..334,861] 🟢 +1.7%
Number.parseInt and parseFloat 247,087 ops/sec [246,568..247,948] → 253,110 ops/sec [250,480..259,006] 🟢 +2.4% 258,712 ops/sec [257,398..261,854] → 257,208 ops/sec [255,558..259,790] ~ overlap (-0.6%)
objects.js — Interp: 🔴 2, 5 unch. · avg -1.1% · Bytecode: 🟢 2, 🔴 2, 3 unch. · avg +0.1%
Benchmark Interpreted Δ Bytecode Δ
create simple object 485,080 ops/sec [482,204..486,951] → 471,285 ops/sec [465,496..473,870] 🔴 -2.8% 582,968 ops/sec [581,020..583,992] → 580,523 ops/sec [577,154..581,739] ~ overlap (-0.4%)
create nested object 235,970 ops/sec [234,382..237,378] → 234,621 ops/sec [234,090..235,486] ~ overlap (-0.6%) 259,859 ops/sec [255,774..262,621] → 266,500 ops/sec [261,806..268,941] ~ overlap (+2.6%)
create 50 objects via Array.from 9,329 ops/sec [9,223..9,388] → 9,336 ops/sec [9,190..9,351] ~ overlap (+0.1%) 9,674 ops/sec [9,564..9,852] → 9,926 ops/sec [9,896..10,004] 🟢 +2.6%
property read 551,558 ops/sec [548,145..561,992] → 548,357 ops/sec [541,841..555,628] ~ overlap (-0.6%) 450,452 ops/sec [447,406..456,618] → 428,194 ops/sec [424,280..434,555] 🔴 -4.9%
Object.keys 285,146 ops/sec [279,995..286,523] → 283,159 ops/sec [282,404..283,975] ~ overlap (-0.7%) 320,833 ops/sec [313,087..327,323] → 309,533 ops/sec [307,293..310,069] 🔴 -3.5%
Object.entries 106,248 ops/sec [103,866..106,827] → 105,538 ops/sec [104,881..106,489] ~ overlap (-0.7%) 111,661 ops/sec [110,872..112,204] → 114,353 ops/sec [113,408..114,952] 🟢 +2.4%
spread operator 181,540 ops/sec [179,710..183,068] → 177,692 ops/sec [177,145..178,071] 🔴 -2.1% 209,747 ops/sec [207,848..212,203] → 213,889 ops/sec [211,361..215,171] ~ overlap (+2.0%)
promises.js — Interp: 🟢 3, 9 unch. · avg +0.6% · Bytecode: 🟢 1, 🔴 1, 10 unch. · avg -0.5%
Benchmark Interpreted Δ Bytecode Δ
Promise.resolve(value) 531,889 ops/sec [526,583..536,724] → 546,715 ops/sec [542,830..549,555] 🟢 +2.8% 561,629 ops/sec [556,182..563,122] → 558,805 ops/sec [554,437..561,236] ~ overlap (-0.5%)
new Promise(resolve => resolve(value)) 187,942 ops/sec [187,524..189,229] → 194,043 ops/sec [192,686..195,079] 🟢 +3.2% 226,094 ops/sec [225,378..228,969] → 229,203 ops/sec [228,294..229,759] ~ overlap (+1.4%)
Promise.reject(reason) 545,290 ops/sec [542,941..548,836] → 559,380 ops/sec [555,670..561,352] 🟢 +2.6% 560,544 ops/sec [541,594..563,094] → 541,061 ops/sec [539,506..543,420] ~ overlap (-3.5%)
resolve + then (1 handler) 175,582 ops/sec [173,408..177,575] → 176,053 ops/sec [174,876..177,969] ~ overlap (+0.3%) 200,904 ops/sec [198,866..205,373] → 198,956 ops/sec [197,674..200,060] ~ overlap (-1.0%)
resolve + then chain (3 deep) 69,123 ops/sec [68,981..69,878] → 69,135 ops/sec [68,835..69,524] ~ overlap (+0.0%) 81,247 ops/sec [79,322..82,749] → 77,819 ops/sec [77,706..78,193] 🔴 -4.2%
resolve + then chain (10 deep) 22,094 ops/sec [21,852..22,491] → 21,586 ops/sec [21,153..22,006] ~ overlap (-2.3%) 25,498 ops/sec [24,892..26,858] → 24,962 ops/sec [24,853..25,098] ~ overlap (-2.1%)
reject + catch + then 97,943 ops/sec [97,309..98,723] → 98,778 ops/sec [98,261..99,096] ~ overlap (+0.9%) 114,063 ops/sec [112,396..119,192] → 112,405 ops/sec [111,843..112,520] ~ overlap (-1.5%)
resolve + finally + then 83,456 ops/sec [82,769..84,032] → 84,461 ops/sec [84,027..84,978] ~ overlap (+1.2%) 93,053 ops/sec [92,458..94,676] → 93,523 ops/sec [92,598..93,990] ~ overlap (+0.5%)
Promise.all (5 resolved) 32,044 ops/sec [31,788..32,320] → 32,012 ops/sec [31,911..32,204] ~ overlap (-0.1%) 33,452 ops/sec [33,167..33,570] → 33,805 ops/sec [33,530..34,174] ~ overlap (+1.1%)
Promise.race (5 resolved) 34,417 ops/sec [34,078..34,579] → 34,370 ops/sec [34,264..34,403] ~ overlap (-0.1%) 35,489 ops/sec [35,068..35,632] → 35,815 ops/sec [35,459..35,861] ~ overlap (+0.9%)
Promise.allSettled (5 mixed) 27,150 ops/sec [27,039..27,267] → 26,859 ops/sec [26,676..27,065] ~ overlap (-1.1%) 28,413 ops/sec [28,168..28,832] → 28,466 ops/sec [28,380..28,700] ~ overlap (+0.2%)
Promise.any (5 mixed) 32,176 ops/sec [31,857..32,403] → 32,156 ops/sec [31,991..32,354] ~ overlap (-0.1%) 32,893 ops/sec [32,703..33,220] → 33,622 ops/sec [33,330..33,755] 🟢 +2.2%
regexp.js — Interp: 🟢 3, 🔴 2, 6 unch. · avg +0.1% · Bytecode: 🔴 5, 6 unch. · avg -1.9%
Benchmark Interpreted Δ Bytecode Δ
regex literal creation 186,162 ops/sec [185,307..186,724] → 182,217 ops/sec [180,745..183,550] 🔴 -2.1% 168,160 ops/sec [165,657..174,405] → 163,359 ops/sec [161,116..165,696] ~ overlap (-2.9%)
new RegExp(pattern, flags) 155,219 ops/sec [154,688..155,681] → 156,469 ops/sec [155,293..157,685] ~ overlap (+0.8%) 164,747 ops/sec [161,071..168,136] → 162,095 ops/sec [159,708..164,855] ~ overlap (-1.6%)
RegExp(existingRegex) returns the same regex 712,830 ops/sec [710,014..715,620] → 737,195 ops/sec [733,906..741,975] 🟢 +3.4% 958,758 ops/sec [956,577..963,662] → 936,426 ops/sec [935,671..937,670] 🔴 -2.3%
test() on a global regex 157,720 ops/sec [156,685..158,064] → 154,975 ops/sec [154,361..156,481] 🔴 -1.7% 181,130 ops/sec [180,194..182,627] → 181,120 ops/sec [179,800..181,453] ~ overlap (-0.0%)
exec() with capture groups 138,447 ops/sec [137,191..139,995] → 137,707 ops/sec [134,783..138,743] ~ overlap (-0.5%) 165,052 ops/sec [162,176..169,782] → 158,358 ops/sec [157,189..158,884] 🔴 -4.1%
toString() 470,786 ops/sec [463,875..474,924] → 475,727 ops/sec [473,560..477,780] ~ overlap (+1.0%) 598,365 ops/sec [588,624..631,958] → 603,531 ops/sec [601,284..607,531] ~ overlap (+0.9%)
match() with global regex 44,657 ops/sec [44,333..44,893] → 45,237 ops/sec [45,040..45,482] 🟢 +1.3% 46,623 ops/sec [46,098..46,670] → 45,130 ops/sec [44,487..45,294] 🔴 -3.2%
matchAll() with capture groups 22,960 ops/sec [22,846..23,034] → 23,137 ops/sec [23,045..23,191] 🟢 +0.8% 29,084 ops/sec [28,735..29,778] → 28,332 ops/sec [28,069..28,612] 🔴 -2.6%
replace() with global regex 43,069 ops/sec [42,736..43,348] → 43,029 ops/sec [42,794..43,106] ~ overlap (-0.1%) 44,536 ops/sec [43,199..45,611] → 43,030 ops/sec [42,534..43,328] ~ overlap (-3.4%)
search() with regex 92,395 ops/sec [91,658..92,939] → 91,679 ops/sec [91,569..91,900] ~ overlap (-0.8%) 89,096 ops/sec [88,772..89,961] → 88,490 ops/sec [87,985..88,541] 🔴 -0.7%
split() with regex separator 45,101 ops/sec [44,903..45,304] → 44,902 ops/sec [44,472..44,955] ~ overlap (-0.4%) 46,046 ops/sec [45,317..46,529] → 45,385 ops/sec [44,946..45,698] ~ overlap (-1.4%)
strings.js — Interp: 🟢 5, 🔴 1, 5 unch. · avg +1.0% · Bytecode: 🔴 3, 8 unch. · avg -1.8%
Benchmark Interpreted Δ Bytecode Δ
string concatenation 398,673 ops/sec [397,739..400,106] → 408,036 ops/sec [406,434..409,157] 🟢 +2.3% 331,004 ops/sec [330,831..332,269] → 316,839 ops/sec [304,364..318,292] 🔴 -4.3%
template literal 667,785 ops/sec [665,718..677,198] → 645,731 ops/sec [632,580..656,837] 🔴 -3.3% 663,433 ops/sec [647,488..675,389] → 643,767 ops/sec [635,665..652,883] ~ overlap (-3.0%)
string repeat 395,370 ops/sec [393,112..403,761] → 406,875 ops/sec [403,748..408,158] ~ overlap (+2.9%) 460,921 ops/sec [458,845..468,541] → 463,271 ops/sec [462,047..464,274] ~ overlap (+0.5%)
split and join 136,913 ops/sec [136,502..137,287] → 136,771 ops/sec [135,764..137,310] ~ overlap (-0.1%) 154,302 ops/sec [153,373..161,316] → 154,674 ops/sec [154,080..156,058] ~ overlap (+0.2%)
indexOf and includes 169,671 ops/sec [168,392..170,996] → 169,014 ops/sec [167,683..170,404] ~ overlap (-0.4%) 196,921 ops/sec [194,790..197,501] → 192,832 ops/sec [191,302..193,740] 🔴 -2.1%
toUpperCase and toLowerCase 254,098 ops/sec [249,038..255,405] → 257,919 ops/sec [257,182..260,047] 🟢 +1.5% 335,697 ops/sec [333,221..341,545] → 333,013 ops/sec [330,377..334,803] ~ overlap (-0.8%)
slice and substring 154,612 ops/sec [152,175..155,914] → 157,270 ops/sec [157,098..158,064] 🟢 +1.7% 203,825 ops/sec [199,037..205,162] → 199,577 ops/sec [196,775..199,963] ~ overlap (-2.1%)
trim operations 187,690 ops/sec [184,293..188,006] → 191,465 ops/sec [190,925..192,130] 🟢 +2.0% 246,484 ops/sec [241,843..248,658] → 246,587 ops/sec [245,451..249,009] ~ overlap (+0.0%)
replace and replaceAll 206,401 ops/sec [204,510..207,641] → 208,325 ops/sec [207,230..209,829] ~ overlap (+0.9%) 230,666 ops/sec [228,275..232,538] → 230,806 ops/sec [230,086..232,507] ~ overlap (+0.1%)
startsWith and endsWith 134,303 ops/sec [133,482..135,124] → 137,762 ops/sec [136,443..138,925] 🟢 +2.6% 163,649 ops/sec [161,328..164,886] → 158,546 ops/sec [158,404..162,569] ~ overlap (-3.1%)
padStart and padEnd 195,758 ops/sec [192,969..197,390] → 198,175 ops/sec [195,082..199,412] ~ overlap (+1.2%) 240,058 ops/sec [235,612..245,126] → 227,540 ops/sec [225,762..230,544] 🔴 -5.2%
typed-arrays.js — Interp: 🟢 7, 🔴 4, 11 unch. · avg +0.7% · Bytecode: 🟢 6, 🔴 8, 8 unch. · avg -0.3%
Benchmark Interpreted Δ Bytecode Δ
new Int32Array(0) 320,726 ops/sec [319,533..322,560] → 333,903 ops/sec [331,819..337,200] 🟢 +4.1% 360,753 ops/sec [358,516..367,460] → 379,609 ops/sec [372,283..381,400] 🟢 +5.2%
new Int32Array(100) 292,671 ops/sec [290,059..294,189] → 303,883 ops/sec [302,444..306,093] 🟢 +3.8% 329,002 ops/sec [322,862..335,960] → 341,864 ops/sec [337,630..343,146] 🟢 +3.9%
new Int32Array(1000) 182,427 ops/sec [179,321..183,169] → 186,490 ops/sec [184,913..187,232] 🟢 +2.2% 190,153 ops/sec [189,806..193,810] → 200,385 ops/sec [198,292..201,689] 🟢 +5.4%
new Float64Array(100) 272,356 ops/sec [271,021..274,270] → 279,471 ops/sec [279,308..280,856] 🟢 +2.6% 294,702 ops/sec [293,168..295,855] → 306,370 ops/sec [303,904..308,103] 🟢 +4.0%
Int32Array.from([...]) 184,003 ops/sec [182,106..184,531] → 177,782 ops/sec [177,201..178,578] 🔴 -3.4% 196,191 ops/sec [192,199..202,107] → 189,464 ops/sec [188,667..190,166] 🔴 -3.4%
Int32Array.of(1, 2, 3, 4, 5) 304,119 ops/sec [302,577..306,819] → 301,793 ops/sec [298,822..304,123] ~ overlap (-0.8%) 362,784 ops/sec [356,302..372,722] → 358,103 ops/sec [356,721..360,365] ~ overlap (-1.3%)
sequential write 100 elements 3,602 ops/sec [3,569..3,612] → 3,616 ops/sec [3,607..3,624] ~ overlap (+0.4%) 16,103 ops/sec [16,030..16,293] → 15,834 ops/sec [15,665..15,945] 🔴 -1.7%
sequential read 100 elements 3,620 ops/sec [3,581..3,652] → 3,686 ops/sec [3,638..3,696] ~ overlap (+1.8%) 11,772 ops/sec [11,040..12,000] → 11,075 ops/sec [10,950..11,340] ~ overlap (-5.9%)
Float64Array write 100 elements 3,345 ops/sec [3,299..3,354] → 3,382 ops/sec [3,368..3,399] 🟢 +1.1% 11,380 ops/sec [9,954..11,819] → 11,219 ops/sec [11,099..11,440] ~ overlap (-1.4%)
fill(42) 44,803 ops/sec [44,685..44,935] → 44,333 ops/sec [44,252..44,416] 🔴 -1.0% 45,374 ops/sec [45,208..47,337] → 44,571 ops/sec [44,492..44,629] 🔴 -1.8%
slice() 201,053 ops/sec [200,162..202,617] → 204,114 ops/sec [202,045..207,791] ~ overlap (+1.5%) 227,559 ops/sec [222,238..232,345] → 221,340 ops/sec [220,149..221,771] 🔴 -2.7%
map(x => x * 2) 7,732 ops/sec [7,568..7,850] → 7,842 ops/sec [7,766..7,949] ~ overlap (+1.4%) 9,125 ops/sec [9,005..9,153] → 8,668 ops/sec [8,617..8,716] 🔴 -5.0%
filter(x => x > 50) 8,144 ops/sec [8,102..8,194] → 8,126 ops/sec [8,051..8,143] ~ overlap (-0.2%) 9,560 ops/sec [9,213..9,643] → 9,608 ops/sec [9,588..9,645] ~ overlap (+0.5%)
reduce (sum) 7,815 ops/sec [7,655..7,844] → 7,942 ops/sec [7,827..8,034] ~ overlap (+1.6%) 7,572 ops/sec [7,397..7,713] → 7,363 ops/sec [7,297..7,393] 🔴 -2.8%
sort() 170,340 ops/sec [169,172..171,392] → 165,915 ops/sec [165,482..166,804] 🔴 -2.6% 171,044 ops/sec [170,675..171,848] → 179,321 ops/sec [178,865..179,546] 🟢 +4.8%
indexOf() 418,319 ops/sec [414,060..420,643] → 430,876 ops/sec [425,174..432,650] 🟢 +3.0% 492,611 ops/sec [491,143..494,494] → 480,289 ops/sec [479,598..483,406] 🔴 -2.5%
reverse() 318,488 ops/sec [317,225..320,092] → 327,071 ops/sec [326,170..328,527] 🟢 +2.7% 348,361 ops/sec [346,671..355,672] → 348,717 ops/sec [347,266..349,036] ~ overlap (+0.1%)
create view over existing buffer 395,428 ops/sec [391,974..397,016] → 396,807 ops/sec [394,809..401,801] ~ overlap (+0.3%) 439,303 ops/sec [437,963..443,216] → 453,318 ops/sec [450,644..456,242] 🟢 +3.2%
subarray() 429,338 ops/sec [426,825..432,468] → 429,952 ops/sec [427,224..432,013] ~ overlap (+0.1%) 518,798 ops/sec [514,692..525,358] → 521,957 ops/sec [514,712..525,523] ~ overlap (+0.6%)
set() from array 551,454 ops/sec [547,175..553,559] → 546,452 ops/sec [544,372..552,933] ~ overlap (-0.9%) 624,307 ops/sec [618,106..630,606] → 618,123 ops/sec [616,662..619,312] ~ overlap (-1.0%)
for-of loop 5,092 ops/sec [5,086..5,111] → 5,109 ops/sec [5,096..5,145] ~ overlap (+0.3%) 19,023 ops/sec [18,815..19,402] → 18,138 ops/sec [18,005..18,179] 🔴 -4.7%
spread into array 17,590 ops/sec [17,566..17,616] → 17,278 ops/sec [17,223..17,493] 🔴 -1.8% 96,451 ops/sec [96,001..96,743] → 97,217 ops/sec [96,657..98,208] ~ overlap (+0.8%)

Measured on ubuntu-latest x64. Benchmark ranges compare cached main-branch min/max ops/sec with the PR run; overlapping ranges are treated as unchanged noise. Percentage deltas are secondary context.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
tests/language/modules/jsonl-import.js (1)

12-26: Add one loader-level blank-line/error case here.

This file only exercises happy-path imports/re-exports. The new .jsonl module contract also promises ignored blank lines and line-numbered failures for invalid input, and neither path is exercised end-to-end through TGocciaModuleLoader.

As per coding guidelines, JavaScript tests should cover happy paths, edge cases, and error cases.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/language/modules/jsonl-import.js` around lines 12 - 26, Add tests to
cover the loader-level blank-line and failure cases: extend the "JSONL module
imports" suite by adding one test that imports a JSONL module containing an
empty line and asserts the loader (TGocciaModuleLoader) ignores it (e.g., record
count unchanged and labels still correct), and add another test that attempts to
load a syntactically invalid JSONL module via TGocciaModuleLoader and asserts
the thrown error includes the failing line number (or message matching /line
\d+/) to verify line-numbered failures; reference the existing test names and
variables (firstRecord, count, labels, reExportedFirstRecord, reExportedCount)
when adding these new tests so they integrate with the current fixtures.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/built-ins.md`:
- Line 20: The docs snippet is out of sync with the engine defaults: ensure the
registration examples reflect TGocciaEngine.DefaultGlobals and
TGocciaGlobalBuiltin by re-adding ggYAML where it was removed and keeping
ggJSONL present; update the enum/example list and the default-set example so
both include ggYAML (and any other builtins present in
TGocciaGlobalBuiltin/DefaultGlobals) so the documentation matches the actual
defaults.

In `@units/Goccia.Builtins.JSONL.pas`:
- Around line 94-104: ReadUint8ArrayBytes currently throws
EGocciaJSONLParseError for non-Uint8Array typed arrays which gets remapped to a
SyntaxError by the public parse/parseChunk wrappers; change the error to an
argument/type error instead (e.g. throw a distinct
EGocciaInvalidArgument/EGocciaTypeError or create EGocciaJSONLInvalidInputError)
so callers can map it to an argument-type exception rather than
ThrowSyntaxError; update TGocciaJSONLBuiltin.ReadUint8ArrayBytes and the other
JSONL input-validation sites referenced (lines ~128-150 and ~153-217) to raise
that argument/type-specific exception (or ensure the public methods do not remap
that specific exception to ThrowSyntaxError) and keep existing parse error
semantics for real parse failures.

---

Nitpick comments:
In `@tests/language/modules/jsonl-import.js`:
- Around line 12-26: Add tests to cover the loader-level blank-line and failure
cases: extend the "JSONL module imports" suite by adding one test that imports a
JSONL module containing an empty line and asserts the loader
(TGocciaModuleLoader) ignores it (e.g., record count unchanged and labels still
correct), and add another test that attempts to load a syntactically invalid
JSONL module via TGocciaModuleLoader and asserts the thrown error includes the
failing line number (or message matching /line \d+/) to verify line-numbered
failures; reference the existing test names and variables (firstRecord, count,
labels, reExportedFirstRecord, reExportedCount) when adding these new tests so
they integrate with the current fixtures.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 690c0cd1-257a-4840-bd70-622b24895e51

📥 Commits

Reviewing files that changed from the base of the PR and between 837ebf2 and 780ab1a.

📒 Files selected for processing (17)
  • README.md
  • docs/built-ins.md
  • docs/design-decisions.md
  • docs/language-restrictions.md
  • tests/built-ins/JSONL/parse.js
  • tests/built-ins/JSONL/parseChunk.js
  • tests/language/modules/helpers/event-stream.jsonl
  • tests/language/modules/helpers/jsonl-re-exporter.js
  • tests/language/modules/jsonl-import.js
  • units/Goccia.Builtins.JSONL.pas
  • units/Goccia.Constants.PropertyNames.pas
  • units/Goccia.Engine.pas
  • units/Goccia.FileExtensions.pas
  • units/Goccia.JSONL.pas
  • units/Goccia.Modules.Loader.pas
  • units/Goccia.Runtime.Bootstrap.pas
  • units/Goccia.ScriptLoader.Globals.pas

Comment thread docs/built-ins.md
Comment thread units/Goccia.Builtins.JSONL.pas
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
units/Goccia.Builtins.JSONL.pas (1)

175-183: Check for NaN/Infinity before Trunc to match codebase patterns.

The code calls Trunc(AArgs.GetElement(n).ToNumberLiteral.Value) without first checking if the value is NaN or Infinity. While ClampOffset safely handles extreme integer values, the codebase consistently checks IsNaN and IsInfinite before calling Trunc (see GlobalArrayBuffer.pas, Goccia.Builtins.Math.pas). This aligns with the documented guidance: "Always check the special value flags first and handle each case explicitly."

♻️ Suggested pattern
+      if AArgs.GetElement(1).ToNumberLiteral.IsNaN then
+        StartOffset := 0
+      else if AArgs.GetElement(1).ToNumberLiteral.IsInfinite then
+        StartOffset := TextLength
+      else
         StartOffset := ClampOffset(
           Trunc(AArgs.GetElement(1).ToNumberLiteral.Value), TextLength)

Apply the same check to the end offset (lines 181–185).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@units/Goccia.Builtins.JSONL.pas` around lines 175 - 183, The start and end
offset extraction in units/Goccia.Builtins.JSONL.pas calls Trunc on
AArgs.GetElement(...).ToNumberLiteral.Value without checking special float
flags; update the StartOffset and EndOffset branches to first read the numeric
value, test IsNaN and IsInfinite on that value (using the same pattern as in
GlobalArrayBuffer.pas / Goccia.Builtins.Math.pas), handle those cases explicitly
(e.g., set sensible defaults or clamp), and only then call Trunc and pass the
result to ClampOffset; reference the existing identifiers AArgs, GetElement,
ToNumberLiteral, Trunc, IsNaN/IsInfinite checks, and ClampOffset when making the
change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@units/Goccia.Builtins.JSONL.pas`:
- Around line 175-183: The start and end offset extraction in
units/Goccia.Builtins.JSONL.pas calls Trunc on
AArgs.GetElement(...).ToNumberLiteral.Value without checking special float
flags; update the StartOffset and EndOffset branches to first read the numeric
value, test IsNaN and IsInfinite on that value (using the same pattern as in
GlobalArrayBuffer.pas / Goccia.Builtins.Math.pas), handle those cases explicitly
(e.g., set sensible defaults or clamp), and only then call Trunc and pass the
result to ClampOffset; reference the existing identifiers AArgs, GetElement,
ToNumberLiteral, Trunc, IsNaN/IsInfinite checks, and ClampOffset when making the
change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: df005ff9-ebe5-43c8-b7dd-94d871c75247

📥 Commits

Reviewing files that changed from the base of the PR and between 780ab1a and 5ff7590.

📒 Files selected for processing (5)
  • docs/built-ins.md
  • tests/built-ins/JSONL/parse.js
  • tests/built-ins/JSONL/parseChunk.js
  • units/Goccia.Builtins.JSONL.pas
  • units/Goccia.JSONL.pas
✅ Files skipped from review due to trivial changes (2)
  • tests/built-ins/JSONL/parse.js
  • tests/built-ins/JSONL/parseChunk.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/built-ins.md

frostney added 2 commits April 4, 2026 14:26
- Treat NaN and -Infinity as zero offsets
- Clamp positive infinity to the input length
- Add tests for start and end offset edge cases
@frostney frostney merged commit 980b4d0 into main Apr 4, 2026
9 checks passed
@frostney frostney deleted the feature/jsonl-support branch April 4, 2026 19:38
@frostney frostney added the new feature New feature or request label Apr 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add JSONL support

1 participant