Skip to content

fix(path/string): path.format/relative arg validation + String.includes position#3498

Merged
proggeramlug merged 3 commits into
mainfrom
fix-path-includes-2992-2995-2812
May 31, 2026
Merged

fix(path/string): path.format/relative arg validation + String.includes position#3498
proggeramlug merged 3 commits into
mainfrom
fix-path-includes-2992-2995-2812

Conversation

@proggeramlug
Copy link
Copy Markdown
Contributor

Closes #2992
Closes #2995
Closes #2812

Implementation

#2992 — path.format argument validation + field coercion

js_path_format / js_path_win32_format (crates/perry-runtime/src/path.rs) now reimplement Node's _format exactly via a shared format_descriptor(obj_f64, sep) helper:

  • The top-level pathObject is validated: a non-object (null, undefined, number, string, ...) throws TypeError [ERR_INVALID_ARG_TYPE] with the "pathObject" argument must be of type object message.
  • Descriptor fields (dir, root, base, name, ext) are read with Node's || semantics: truthy values are ToString-coerced (js_jsvalue_to_string), falsy values (0, false, null, "") contribute nothing. Fixes the bug where a numeric dir was dropped ({dir:1, base:"b"} returned "b" instead of "1/b").
  • Separator handling matches Node precisely: dir = pathObject.dir || pathObject.root; the separator is omitted only when dir === pathObject.root. Removes the old dedup hacks that diverged from Node.

The top-level object handle already reached the runtime as a NaN-boxed f64, so no codegen change was needed for format.

#2995 — path.relative argument validation on the compiled path

Added validating entry points js_path_relative_checked(from_f64, to_f64) / js_path_win32_relative_checked that receive the NaN-boxed operands, validate each is a string (throwing TypeError [ERR_INVALID_ARG_TYPE] naming from / to), then forward to the existing string-only helpers. The compiled lowerings (Expr::PathRelative in arrays_finds.rs/instance_misc1.rs, and PathWin32Method::Relative split out of its shared arm) now pass the doubles to these checked wrappers instead of silently unboxing invalid pointers to "".

#2812 — honor position in String.prototype.includes

The typed includes lowering (crates/perry-codegen/src/lower_string_method.rs) now routes the optional second argument through the new js_string_position_to_index runtime helper (JS ToIntegerOrInfinity + clamp: NaN/-Infinity -> 0, +Infinity -> i32::MAX, otherwise truncate/saturate) and calls js_string_index_of_from instead of js_string_index_of. This avoids LLVM fptosi's undefined result on non-finite inputs and matches Node ("ababa".includes("a", Infinity) === false). The second argument is still evaluated for side effects.

New codegen-emitted #[no_mangle] fns (js_path_relative_checked, js_path_win32_relative_checked, js_string_position_to_index) have #[used] keepalive anchors + runtime_decls declarations so the auto-optimize whole-program bitcode pass does not dead-strip them.

No new HIR variant added.

Validation

  • New gap test test-files/test_gap_path_includes_2992_2995_2812.ts is byte-identical to node --experimental-strip-types under the DEFAULT auto-optimize compile (covers all issue repro cases incl. err.name/message/code for throws).
  • #[used] anchors verified present in the freshly-rebuilt libperry_runtime.a (each symbol count == 1).
  • ./scripts/check_file_size.sh -> OK. cargo fmt --all -- --check -> clean.
  • cargo test --release -p perry-runtime (path/string modules) and cargo test --release -p perry-hir -> green.

@proggeramlug proggeramlug merged commit 48f237e into main May 31, 2026
1 check passed
@proggeramlug proggeramlug deleted the fix-path-includes-2992-2995-2812 branch May 31, 2026 01:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant