Skip to content

Add YAML parsing and module imports#166

Merged
frostney merged 1 commit into
mainfrom
feature/yaml-parser
Apr 2, 2026
Merged

Add YAML parsing and module imports#166
frostney merged 1 commit into
mainfrom
feature/yaml-parser

Conversation

@frostney
Copy link
Copy Markdown
Owner

@frostney frostney commented Apr 2, 2026

Summary

  • Add a standalone YAML parser and expose it through YAML.parse(...) and YAML.parseDocuments(...).
  • Enable .yaml and .yml module imports, plus YAML-backed --globals loading in ScriptLoader.
  • Add coverage for anchors, aliases, merge keys, block scalars, quoted escapes, numeric forms, tags, explicit keys, and multi-document streams.
  • Document the YAML runtime surface, module behavior, and validation workflow in the README and docs.
  • Add a helper script to run the official yaml-test-suite parse-validity check.

Testing

  • Not run in this session.
  • Added JavaScript coverage under tests/built-ins/YAML/parse.js and tests/built-ins/YAML/parseDocuments.js.
  • Added module import coverage under tests/language/modules/ for YAML files and re-exports.
  • Added scripts/run_yaml_test_suite.py for local parse-validity verification against the upstream YAML suite.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added YAML module import support alongside JSON, allowing .yaml/.yml files to be imported as named exports.
    • Introduced YAML.parse() and YAML.parseDocuments() builtin functions for runtime YAML parsing with Bun-compatible semantics.
    • Extended --globals=file CLI to accept both JSON and YAML globals files based on file extension.
  • Documentation

    • Added comprehensive YAML usage guides, feature descriptions, and compatibility documentation.
    • Added YAML test suite runner documentation and examples.

- Add YAML parser support and `YAML.parse`/`parseDocuments`
- Allow `.yaml`/`.yml` globals and module imports
- Document YAML behavior and add parser coverage tests
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 2, 2026

📝 Walkthrough

Walkthrough

This PR adds comprehensive YAML parsing support to GocciaScript, including new built-in YAML.parse() and YAML.parseDocuments() methods, YAML module imports, YAML-based globals injection, and extensive test coverage with official yaml-test-suite integration.

Changes

Cohort / File(s) Summary
Documentation
README.md, docs/build-system.md, docs/built-ins.md, docs/design-decisions.md, docs/language-restrictions.md, docs/testing.md
Added YAML feature documentation including supported constructs, usage examples, parse semantics (document-marker-dependent return shapes), module import behavior, official test-suite coverage (336/402 = 83.6%), and clarifications on globals injection via --globals=file.
YAML Parsing Infrastructure
units/Goccia.Builtins.YAML.pas, units/Goccia.YAML (implied via references)
New builtin unit registering YAML.parse and YAML.parseDocuments static methods with error handling, delegating to internal parser and converting YAML exceptions to syntax errors.
Engine & Runtime Integration
units/Goccia.Engine.pas, units/Goccia.Engine.Backend.pas, units/Goccia.Runtime.Bootstrap.pas
Extended engine to include YAML builtin in global builtins, added InjectGlobalsFromYAML method for YAML-based globals with single-document validation, and wired YAML builtin instantiation into engine initialization.
File Extension & Globals Handling
units/Goccia.FileExtensions.pas, units/Goccia.ScriptLoader.Globals.pas, ScriptLoader.dpr
Added YAML extension constants (.yaml, .yml), introduced IsYAMLExtension and IsStructuredDataExtension helpers, replaced JSON-only IsJSONGlobalsFile with IsStructuredGlobalsFile, and updated CLI globals injection to branch on YAML vs JSON format.
Module Loading Refactoring
units/Goccia.Modules.Loader.pas
Refactored LoadJsonModuleLoadStructuredDataModule to support both JSON and YAML; YAML files parsed via ParseDocuments with single-document enforcement and top-level object validation; export extraction unified for both formats.
Constants
units/Goccia.Constants.PropertyNames.pas
Added PROP_TAG_NAME constant for YAML tag metadata property.
YAML Test Fixtures
tests/language/modules/helpers/*, tests/language/modules/yaml-*.js
Created 8 YAML fixture files exercising aliases, block scalars, multiline scalars, quoted escapes, merge keys, explicit keys, tagged values, and simple values; added 9 Jest test files validating YAML module imports, re-exports, and parsed values.
Built-in YAML API Tests
tests/built-ins/YAML/parse.js, tests/built-ins/YAML/parseDocuments.js
Comprehensive Jest suites validating YAML.parse behavior (arrays when document markers present, tag handling, alias graphs, escape sequences, numeric forms) and YAML.parseDocuments consistency across single/multi-document streams.
Test Suite Infrastructure
scripts/run_yaml_test_suite.py
New Python script running Goccia's YAML parser against official yaml-test-suite repository; clones suite, generates FreePascal harness, compiles, executes per-case tests with timeout support, reports parse-validity results (336/402 passing).

Sequence Diagram

sequenceDiagram
    participant Client
    participant Engine
    participant YAMLParser
    participant ModuleLoader
    participant FileSystem
    
    Client->>Engine: YAML.parse(text) or YAML.parseDocuments(text)
    Engine->>YAMLParser: TGocciaYAMLParser.Parse/ParseDocuments(text)
    YAMLParser->>YAMLParser: Parse YAML constructs (scalars, sequences, mappings, tags, aliases)
    YAMLParser->>Engine: Return TGocciaValue or TGocciaArrayValue[]
    Engine->>Client: Return parsed result
    
    Note over Client,FileSystem: Parallel: YAML Module Import Flow
    
    Client->>ModuleLoader: import './config.yaml'
    ModuleLoader->>FileSystem: Read file (isStructuredDataExtension check)
    FileSystem->>ModuleLoader: Return file content
    ModuleLoader->>YAMLParser: ParseDocuments(content) for YAML file
    YAMLParser->>ModuleLoader: Return TGocciaArrayValue with documents
    ModuleLoader->>ModuleLoader: Validate single top-level document
    ModuleLoader->>ModuleLoader: Extract own property keys as exports
    ModuleLoader->>Client: Return module with exported bindings
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~65 minutes

Possibly related PRs

Poem

🐰 Hop along the YAML stream, where documents dance and aliases gleam!
Parse anchors, merge those keys with ease, fold those scalars through the trees.
From !!timestamp to !!binary, structured data flows so free,
Now Engine and Loader waltz as one—YAML's home at last! 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add YAML parsing and module imports' directly and clearly describes the main changes: introducing YAML parsing capabilities and enabling YAML module imports. It is concise, specific, and accurately reflects the primary objectives of the pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/yaml-parser

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.

@frostney
Copy link
Copy Markdown
Owner Author

frostney commented Apr 2, 2026

Literal-string named module support has been deferred as #165

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 2, 2026

Benchmark Results

263 benchmarks

Interpreted: 🟢 30 improved · 🔴 122 regressed · 111 unchanged · avg -1.4%
Bytecode: 🟢 148 improved · 🔴 36 regressed · 79 unchanged · avg +3.5%

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

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.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 2, 2026

Suite Timing

Suite Metric Interpreted Bytecode
Tests Total 3563 3563
Tests Passed 3522 ✅ 3563 ✅
Tests Skipped 41 0
Tests Execution 167.2ms 161.3ms
Tests Engine 328.5ms 600.4ms
Benchmarks Total 263 263
Benchmarks Duration 7.24min 6.45min

Measured on ubuntu-latest x64.

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: 1

🧹 Nitpick comments (3)
tests/language/modules/helpers/tagged-values.yaml (1)

1-10: Consider adding explicit document start marker after directives.

While YAML 1.2 allows content to follow directives without ---, some parsers (including YAMLlint) expect an explicit document start marker. Adding --- after the %TAG directive would improve compatibility without changing semantics.

♻️ Suggested improvement
 %YAML 1.2
 %TAG !e! tag:example.com,2026:
+---
 name: !!str true
 count: !!int "42"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/language/modules/helpers/tagged-values.yaml` around lines 1 - 10, The
YAML file currently places content directly after the %TAG directive which can
confuse linters; add an explicit document start marker '---' immediately after
the %TAG !e! tag:example.com,2026: directive so the document begins with '---'
before the mapping (i.e., insert '---' following the %TAG directive to improve
compatibility with parsers like YAMLlint).
units/Goccia.FileExtensions.pas (1)

68-74: Minor: redundant LowerCase call in IsStructuredDataExtension.

Ext is already lowercased on line 72, but IsYAMLExtension(Ext) on line 73 will lowercase it again internally. This is functionally correct but slightly inefficient.

♻️ Suggested optimization
 function IsStructuredDataExtension(const AExtension: string): Boolean;
 var
   Ext: string;
 begin
   Ext := LowerCase(AExtension);
-  Result := (Ext = EXT_JSON) or IsYAMLExtension(Ext);
+  Result := (Ext = EXT_JSON) or (Ext = EXT_YAML) or (Ext = EXT_YML);
 end;

Alternatively, add an internal variant of IsYAMLExtension that assumes pre-lowercased input.

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

In `@units/Goccia.FileExtensions.pas` around lines 68 - 74,
IsStructuredDataExtension lowercases AExtension then calls IsYAMLExtension which
itself lowercases again; remove this redundant work by adding a lowercased-aware
helper and using it: introduce a new function IsYAMLExtensionLower(const
AExtensionLower: string): Boolean that assumes its input is already lowercased
(or adapt IsYAMLExtension to call it), change IsStructuredDataExtension to
compute Ext := LowerCase(AExtension) once and call IsYAMLExtensionLower(Ext)
(and compare Ext to EXT_JSON), and update IsYAMLExtension to delegate to
IsYAMLExtensionLower so other callers keep existing behavior.
docs/testing.md (1)

231-231: Use consistent heading level for this section.

Other test-related sections like "TestRunner Options" use ### for subsections. This section should follow the same pattern for consistency.

-**Official YAML Suite**
+### Official YAML Suite
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/testing.md` at line 231, The "Official YAML Suite" section is currently
formatted as bold text ("**Official YAML Suite**") instead of a subsection
heading; change it to the same subsection level used elsewhere by replacing the
bold line with a level-3 heading ("### Official YAML Suite") so it matches the
"TestRunner Options" and other `###` subsections and keeps heading hierarchy
consistent in docs/testing.md.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/run_yaml_test_suite.py`:
- Around line 42-59: The Halt(0) inside the try block makes the subsequent
Parser.Free, Source.Free and TGarbageCollector.Shutdown unreachable; wrap the
resource lifecycle in a try..finally so Source (TStringList), Parser
(TGocciaYAMLParser) and any Documents are freed in the finally section
regardless of success or failure, and move the Halt calls out of the cleanup (or
call Halt after the finally). Specifically, ensure ParseDocuments/Documents
freeing happens inside the main try, catch exceptions to Writeln(E.Message) and
set exit code, and perform Parser.Free, Source.Free and
TGarbageCollector.Shutdown in the outer finally block so resources are always
released.

---

Nitpick comments:
In `@docs/testing.md`:
- Line 231: The "Official YAML Suite" section is currently formatted as bold
text ("**Official YAML Suite**") instead of a subsection heading; change it to
the same subsection level used elsewhere by replacing the bold line with a
level-3 heading ("### Official YAML Suite") so it matches the "TestRunner
Options" and other `###` subsections and keeps heading hierarchy consistent in
docs/testing.md.

In `@tests/language/modules/helpers/tagged-values.yaml`:
- Around line 1-10: The YAML file currently places content directly after the
%TAG directive which can confuse linters; add an explicit document start marker
'---' immediately after the %TAG !e! tag:example.com,2026: directive so the
document begins with '---' before the mapping (i.e., insert '---' following the
%TAG directive to improve compatibility with parsers like YAMLlint).

In `@units/Goccia.FileExtensions.pas`:
- Around line 68-74: IsStructuredDataExtension lowercases AExtension then calls
IsYAMLExtension which itself lowercases again; remove this redundant work by
adding a lowercased-aware helper and using it: introduce a new function
IsYAMLExtensionLower(const AExtensionLower: string): Boolean that assumes its
input is already lowercased (or adapt IsYAMLExtension to call it), change
IsStructuredDataExtension to compute Ext := LowerCase(AExtension) once and call
IsYAMLExtensionLower(Ext) (and compare Ext to EXT_JSON), and update
IsYAMLExtension to delegate to IsYAMLExtensionLower so other callers keep
existing behavior.
🪄 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: 6a1ee642-79e3-4ee5-8b15-76ab4b5b5327

📥 Commits

Reviewing files that changed from the base of the PR and between d88aa4d and cb12a27.

📒 Files selected for processing (39)
  • README.md
  • ScriptLoader.dpr
  • docs/build-system.md
  • docs/built-ins.md
  • docs/design-decisions.md
  • docs/language-restrictions.md
  • docs/testing.md
  • scripts/run_yaml_test_suite.py
  • tests/built-ins/YAML/parse.js
  • tests/built-ins/YAML/parseDocuments.js
  • tests/language/modules/helpers/alias-graph.yaml
  • tests/language/modules/helpers/block-scalars.yaml
  • tests/language/modules/helpers/config.yaml
  • tests/language/modules/helpers/explicit-keys.yaml
  • tests/language/modules/helpers/merged.yaml
  • tests/language/modules/helpers/multiline-scalars.yaml
  • tests/language/modules/helpers/quoted-escapes.yaml
  • tests/language/modules/helpers/simple-values.yml
  • tests/language/modules/helpers/tagged-values.yaml
  • tests/language/modules/helpers/yaml-re-exporter.js
  • tests/language/modules/yaml-alias-graph.js
  • tests/language/modules/yaml-block-scalars.js
  • tests/language/modules/yaml-explicit-keys.js
  • tests/language/modules/yaml-import-aliased.js
  • tests/language/modules/yaml-import.js
  • tests/language/modules/yaml-merge.js
  • tests/language/modules/yaml-multiline-scalars.js
  • tests/language/modules/yaml-quoted-escapes.js
  • tests/language/modules/yaml-re-export.js
  • tests/language/modules/yaml-tags.js
  • units/Goccia.Builtins.YAML.pas
  • units/Goccia.Constants.PropertyNames.pas
  • units/Goccia.Engine.Backend.pas
  • units/Goccia.Engine.pas
  • units/Goccia.FileExtensions.pas
  • units/Goccia.Modules.Loader.pas
  • units/Goccia.Runtime.Bootstrap.pas
  • units/Goccia.ScriptLoader.Globals.pas
  • units/Goccia.YAML.pas

Comment thread scripts/run_yaml_test_suite.py
@frostney frostney merged commit f0beafb into main Apr 2, 2026
9 checks passed
@frostney frostney deleted the feature/yaml-parser branch April 2, 2026 20: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.

1 participant