Skip to content

Allow string-literal module export names#181

Merged
frostney merged 4 commits into
mainfrom
fix/string-literal-module-export-names
Apr 4, 2026
Merged

Allow string-literal module export names#181
frostney merged 4 commits into
mainfrom
fix/string-literal-module-export-names

Conversation

@frostney
Copy link
Copy Markdown
Owner

@frostney frostney commented Apr 4, 2026

Summary

  • Added parser support for string-literal names in module import/export specifiers.
  • Enabled importing and re-exporting keys like "foo-bar" and "0" from JavaScript, JSON, and YAML modules.
  • Updated language restriction docs and tutorial examples to describe the new syntax.
  • Added end-to-end module tests covering string-literal named imports, exports, and re-exports.

Fixes #165

Testing

  • Added tests/language/modules/string-literal-named-import-export.js to cover JavaScript, JSON, and YAML module cases.
  • Verified parser changes allow string-literal specifier names while still requiring as for string-literal import bindings.

Summary by CodeRabbit

  • New Features

    • Support for string-literal named imports/exports (import/export bindings with non-identifier names).
    • Multi-document YAML import support: each document is exposed as a string-indexed named export ("0", "1", ...).
  • Documentation

    • Expanded Modules tutorial, README, and design docs with examples and updated YAML import semantics.
  • Tests

    • Added tests covering string-literal imports/exports, identifier-name exports/re-exports, and multi-document YAML streams.

- Parse string-literal named imports and exports in module syntax
- Add coverage for JS, JSON, and YAML module export names
- Update docs to describe quoted export identifiers
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 4, 2026

📝 Walkthrough

Walkthrough

Added parser support and runtime loader handling for string-literal module export names (e.g., import { "0" as firstDoc }, export { local as "foo-bar" }), plus YAML multi-document module export semantics, tests, and documentation updates.

Changes

Cohort / File(s) Summary
Docs
docs/language-restrictions.md, docs/tutorial.md, docs/design-decisions.md, README.md
Documented string-literal named imports/exports and updated YAML import semantics and examples for multi-document YAML exports ("0", "1", ...).
Parser
units/Goccia.Parser.pas
Added IsIdentifierNameToken and ConsumeModuleExportName; accept string literals or identifiers for module export names; enforce identifier for local as bindings; buffer specifiers and validate local vs exported name usage.
Module Loader
units/Goccia.Modules.Loader.pas
YAML loader now accepts multi-document streams (rejects only empty input) and populates module exports for each document under string-index keys ("0", "1", ...); single-document/object behavior preserved.
Tests — fixtures
tests/language/modules/helpers/string-literal-export-source.js, tests/language/modules/helpers/string-literal-re-exporter.js, tests/language/modules/helpers/string-literal-keys.json, tests/language/modules/helpers/string-literal-keys.yaml, tests/language/modules/helpers/multi-document-stream.yaml, tests/language/modules/helpers/multi-document-re-exporter.js, tests/language/modules/helpers/identifier-name-export-source.js, tests/language/modules/helpers/identifier-name-re-exporter.js
Added JS/JSON/YAML fixtures exposing non-identifier export names, identifier-like export names, and multi-document YAML sources plus re-exporters.
Tests — suites
tests/language/modules/string-literal-named-import-export.js, tests/language/modules/yaml-multi-document-streams.js, tests/language/modules/identifier-name-module-export-names.js
Added Jest tests verifying string-literal named imports/exports, re-exports, and YAML multi-document import semantics.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Source as SourceCode
participant Parser as TGocciaParser
participant Loader as ModuleLoader
participant Module as Module.ExportsTable
participant Importer as ImportSite

Source->>Parser: parse import/export specifiers (identifier or string)
Parser-->>Loader: request module load with export-name tokens
Loader->>Loader: parse JSON/YAML; produce ParsedDocument(s)
alt multi-document YAML
    Loader->>Module: add export keys `"0"`,`"1"`,... → document values
else single-document / object
    Loader->>Module: populate exports from object keys or default export
end
Importer->>Module: resolve binding by literal name (e.g., "0", "foo-bar")
Module-->>Importer: return exported value

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped through tokens, quotes in tow,
"foo-bar" and "0" now freely go,
From YAML streams to JSON's flow,
Re-exports bounce and tests all show,
A nibble of syntax — off we go! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Allow string-literal module export names' is concise and directly summarizes the main change: enabling string-literal names in module import/export specifiers.
Linked Issues check ✅ Passed The PR addresses all coding objectives from issue #165: parser support for string-literal ModuleExportName in imports/exports/re-exports, proper export lookup semantics, language-wide implementation, and comprehensive end-to-end tests.
Out of Scope Changes check ✅ Passed All changes directly support string-literal module export names: parser updates (Goccia.Parser.pas), loader changes (Goccia.Modules.Loader.pas), test fixtures and cases, and documentation updates are all in scope per issue #165.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/string-literal-module-export-names

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.

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 (2)
docs/language-restrictions.md (1)

178-205: Update the opening extension list in this section too.

These new JSON/YAML examples make the earlier “Supported file extensions” sentence in the Modules section read stale, because it still sounds like only .js/.jsx/.ts/.tsx/.mjs modules are supported. Please update that prose so the section does not contradict itself.

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

In `@docs/language-restrictions.md` around lines 178 - 205, The Modules section's
opening sentence listing supported file extensions is now out of date; update
that prose to include JSON and YAML module extensions (add `.json`, `.yaml`,
`.yml`) and briefly note that JSON/YAML imports expose top-level keys as named
exports (consistent with examples like import { "foo-bar" as fooBar } from
"./config.json" and import { "0" as firstDoc } from "./multi-doc-index.yaml");
ensure the updated sentence remains concise and references the
single-top-level-document constraint for `.yaml` / `.yml` imports so the section
no longer contradicts the later examples and YAML explanation.
tests/language/modules/string-literal-named-import-export.js (1)

22-46: Add error-case coverage for the new grammar restrictions.

These tests only exercise successful imports/re-exports. The parser changes also add rejection paths like import { "foo-bar" } ... and non-re-export export { "foo-bar" }, so adding one or two syntax-error assertions here would make regressions much easier to catch and would pair well with matching native parser tests.

Based on learnings: "When modifying AST logic, scope chain, evaluator, or value types, update the native Pascal tests in units/*.Test.pas"; 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/string-literal-named-import-export.js` around lines 22
- 46, Add negative tests to the "string-literal named imports and exports" suite
that assert the parser rejects string-literal specifiers; specifically add
assertions that code like import { "foo-bar" } from "./mod.js" and a
non-re-export export like export { "foo-bar" } produce syntax errors. Place
these alongside the existing tests (in the same describe block) and use the same
test harness/assertion style as the other cases (e.g., expect a thrown syntax
error) so regressions in the new grammar restrictions are caught.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@units/Goccia.Parser.pas`:
- Around line 2432-2451: The error currently reports the statement-level
coordinates instead of the offending specifier; capture and store the local-name
token coordinates when you record LocalNameTokenTypes (e.g. add arrays like
LocalNameLines/LocalNameColumns or a LocalNameTokens array and set them where
LocalNameTokenTypes[SpecifierCount] := NameToken.TokenType is assigned), then
when raising TGocciaSyntaxError for LocalNameTokenTypes[I] = gttString use those
stored coordinates (instead of Line/Column) so the diagnostic points at the
actual token.

---

Nitpick comments:
In `@docs/language-restrictions.md`:
- Around line 178-205: The Modules section's opening sentence listing supported
file extensions is now out of date; update that prose to include JSON and YAML
module extensions (add `.json`, `.yaml`, `.yml`) and briefly note that JSON/YAML
imports expose top-level keys as named exports (consistent with examples like
import { "foo-bar" as fooBar } from "./config.json" and import { "0" as firstDoc
} from "./multi-doc-index.yaml"); ensure the updated sentence remains concise
and references the single-top-level-document constraint for `.yaml` / `.yml`
imports so the section no longer contradicts the later examples and YAML
explanation.

In `@tests/language/modules/string-literal-named-import-export.js`:
- Around line 22-46: Add negative tests to the "string-literal named imports and
exports" suite that assert the parser rejects string-literal specifiers;
specifically add assertions that code like import { "foo-bar" } from "./mod.js"
and a non-re-export export like export { "foo-bar" } produce syntax errors.
Place these alongside the existing tests (in the same describe block) and use
the same test harness/assertion style as the other cases (e.g., expect a thrown
syntax error) so regressions in the new grammar restrictions are caught.
🪄 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: 4b73e91a-4699-4ac2-852f-07a4cc754820

📥 Commits

Reviewing files that changed from the base of the PR and between 8ac685e and 73d3363.

📒 Files selected for processing (8)
  • docs/language-restrictions.md
  • docs/tutorial.md
  • tests/language/modules/helpers/string-literal-export-source.js
  • tests/language/modules/helpers/string-literal-keys.json
  • tests/language/modules/helpers/string-literal-keys.yaml
  • tests/language/modules/helpers/string-literal-re-exporter.js
  • tests/language/modules/string-literal-named-import-export.js
  • units/Goccia.Parser.pas

Comment thread units/Goccia.Parser.pas Outdated
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 4, 2026

Benchmark Results

274 benchmarks

Interpreted: 🟢 67 improved · 🔴 82 regressed · 125 unchanged · avg -0.1%
Bytecode: 🟢 4 improved · 🔴 256 regressed · 14 unchanged · avg -9.1%

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

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 4, 2026

Suite Timing

Suite Metric Interpreted Bytecode
Tests Total 3631 3631
Tests Passed 3590 ✅ 3631 ✅
Tests Skipped 41 0
Tests Execution 191.6ms 178.6ms
Tests Engine 358.6ms 627.6ms
Benchmarks Total 274 274
Benchmarks Duration 7.43min 6.47min

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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@units/Goccia.Parser.pas`:
- Around line 443-447: TGocciaParser.ConsumeModuleExportName currently only
accepts gttIdentifier and gttString, so reserved-word identifier-names like
"if", "class", "from" are rejected; change the function to accept IdentifierName
forms as well by updating the Match call to include the token kind used for
identifier-name tokens (e.g., gttIdentifierName) or by adding a runtime check
(e.g., TokenIsIdentifierName(Current) / checking Current.Kind in [gttIdentifier,
gttIdentifierName, gttString]) before returning Previous; reference
TGocciaParser.ConsumeModuleExportName, Match, gttIdentifier, gttString, and
Previous when making this change so ImportDeclaration/ExportDeclaration accept
reserved-word IdentifierName forms per the spec.
🪄 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: 1ff37f23-e33d-40c5-b198-8020d38c8042

📥 Commits

Reviewing files that changed from the base of the PR and between 73d3363 and 7dff608.

📒 Files selected for processing (9)
  • README.md
  • docs/design-decisions.md
  • docs/language-restrictions.md
  • docs/tutorial.md
  • tests/language/modules/helpers/multi-document-re-exporter.js
  • tests/language/modules/helpers/multi-document-stream.yaml
  • tests/language/modules/yaml-multi-document-streams.js
  • units/Goccia.Modules.Loader.pas
  • units/Goccia.Parser.pas
✅ Files skipped from review due to trivial changes (4)
  • tests/language/modules/helpers/multi-document-stream.yaml
  • tests/language/modules/helpers/multi-document-re-exporter.js
  • README.md
  • docs/tutorial.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/language-restrictions.md

Comment thread units/Goccia.Parser.pas Outdated
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.Parser.pas (1)

2350-2370: Consider extracting specifier metadata into a record type.

The parallel arrays (LocalNames, ExportedNames, LocalNameTokenTypes, LocalNameLines, LocalNameColumns) work correctly but could be consolidated into a single dynamic array of records for improved maintainability and reduced risk of index misalignment:

♻️ Optional refactor using a record type
+type
+  TExportSpecifierInfo = record
+    LocalName: string;
+    ExportedName: string;
+    LocalNameTokenType: TGocciaTokenType;
+    LocalNameLine: Integer;
+    LocalNameColumn: Integer;
+  end;
+
 var
   ExportsTable: TStringStringMap;
-  LocalNames: array of string;
-  ExportedNames: array of string;
-  LocalNameTokenTypes: array of TGocciaTokenType;
-  LocalNameLines: array of Integer;
-  LocalNameColumns: array of Integer;
+  Specifiers: array of TExportSpecifierInfo;
   SpecifierCount: Integer;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@units/Goccia.Parser.pas` around lines 2350 - 2370, The parser currently uses
parallel dynamic arrays (LocalNames, ExportedNames, LocalNameTokenTypes,
LocalNameLines, LocalNameColumns) plus SpecifierCount which risks index
misalignment; define a new record (e.g. TExportSpecifier with fields Name,
ExportedName, TokenType, Line, Column, maybe IsReExport/NameToken) and replace
the parallel arrays with a single dynamic array (e.g. Specifiers: array of
TExportSpecifier), update SpecifierCount usages to Length(Specifiers) and change
all code that reads/writes
LocalNames/ExportedNames/LocalNameTokenTypes/LocalNameLines/LocalNameColumns/NameToken
to use the corresponding fields on Specifiers[I], preserving semantics in
routines like the named export parser and any iterations or increments, keeping
HasFromClauseAfterNamedExports unchanged.
🤖 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.Parser.pas`:
- Around line 2350-2370: The parser currently uses parallel dynamic arrays
(LocalNames, ExportedNames, LocalNameTokenTypes, LocalNameLines,
LocalNameColumns) plus SpecifierCount which risks index misalignment; define a
new record (e.g. TExportSpecifier with fields Name, ExportedName, TokenType,
Line, Column, maybe IsReExport/NameToken) and replace the parallel arrays with a
single dynamic array (e.g. Specifiers: array of TExportSpecifier), update
SpecifierCount usages to Length(Specifiers) and change all code that
reads/writes
LocalNames/ExportedNames/LocalNameTokenTypes/LocalNameLines/LocalNameColumns/NameToken
to use the corresponding fields on Specifiers[I], preserving semantics in
routines like the named export parser and any iterations or increments, keeping
HasFromClauseAfterNamedExports unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0109c8df-03ee-4d24-ba40-65802914c008

📥 Commits

Reviewing files that changed from the base of the PR and between 7dff608 and 498f98e.

📒 Files selected for processing (4)
  • tests/language/modules/helpers/identifier-name-export-source.js
  • tests/language/modules/helpers/identifier-name-re-exporter.js
  • tests/language/modules/identifier-name-module-export-names.js
  • units/Goccia.Parser.pas
✅ Files skipped from review due to trivial changes (3)
  • tests/language/modules/helpers/identifier-name-re-exporter.js
  • tests/language/modules/helpers/identifier-name-export-source.js
  • tests/language/modules/identifier-name-module-export-names.js

@frostney frostney merged commit 837ebf2 into main Apr 4, 2026
9 checks passed
@frostney frostney deleted the fix/string-literal-module-export-names branch April 4, 2026 07:07
@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.

Support string-literal named imports and exports in ES module syntax

1 participant