From 26c40ffe66578e90e5842bbd208ba4d4652131d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Fri, 31 Jul 2026 09:36:28 +0200 Subject: [PATCH 1/4] fix(intl): RelativeTimeFormat numeric:auto word forms + subclass instanceof (#6960) `numeric: "auto"` now substitutes en-US CLDR relative word forms (yesterday/today/tomorrow, last/this/next unit, now) instead of always rendering the numeric form. `instanceof Intl.` is true for `class X extends Intl.` subclass instances via brand matching on the `__intlKind` field copied by intl_subclass_super. --- CLAUDE.md | 2 +- Cargo.lock | 152 +++++++-------- Cargo.toml | 2 +- changelog.d/6960-intl-rtf-auto-instanceof.md | 22 +++ .../src/intl/list_relative_plural.rs | 103 +++++++++-- crates/perry-runtime/src/intl/subclass.rs | 175 +++++++++++++----- .../test_gap_intl_rtf_auto_instanceof_6960.ts | 71 +++++++ 7 files changed, 381 insertions(+), 146 deletions(-) create mode 100644 changelog.d/6960-intl-rtf-auto-instanceof.md create mode 100644 test-files/test_gap_intl_rtf_auto_instanceof_6960.ts diff --git a/CLAUDE.md b/CLAUDE.md index 355e1e5b8d..a642c4bad7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -8,7 +8,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co Perry is a native TypeScript compiler written in Rust that compiles TypeScript source code directly to native executables. It uses SWC for TypeScript parsing and LLVM for code generation. -**Current Version:** 0.5.1265 +**Current Version:** 0.5.1266 ## TypeScript Parity Status diff --git a/Cargo.lock b/Cargo.lock index 09786f5717..8f7e7875d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5503,7 +5503,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "perry" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "anyhow", "base64", @@ -5563,14 +5563,14 @@ dependencies = [ [[package]] name = "perry-api-manifest" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "serde", ] [[package]] name = "perry-audio-miniaudio" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "cc", "libc", @@ -5578,7 +5578,7 @@ dependencies = [ [[package]] name = "perry-codegen" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "anyhow", "log", @@ -5592,7 +5592,7 @@ dependencies = [ [[package]] name = "perry-codegen-arkts" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "anyhow", "perry-hir", @@ -5600,7 +5600,7 @@ dependencies = [ [[package]] name = "perry-codegen-glance" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "anyhow", "perry-hir", @@ -5608,7 +5608,7 @@ dependencies = [ [[package]] name = "perry-codegen-js" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "anyhow", "perry-dispatch", @@ -5617,7 +5617,7 @@ dependencies = [ [[package]] name = "perry-codegen-swiftui" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "anyhow", "perry-hir", @@ -5625,7 +5625,7 @@ dependencies = [ [[package]] name = "perry-codegen-wasm" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "anyhow", "base64", @@ -5637,7 +5637,7 @@ dependencies = [ [[package]] name = "perry-codegen-wear-tiles" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "anyhow", "perry-hir", @@ -5645,7 +5645,7 @@ dependencies = [ [[package]] name = "perry-container-compose" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "anyhow", "async-trait", @@ -5674,14 +5674,14 @@ dependencies = [ [[package]] name = "perry-container-e2e" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "anyhow", ] [[package]] name = "perry-diagnostics" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "serde", "serde_json", @@ -5689,7 +5689,7 @@ dependencies = [ [[package]] name = "perry-dispatch" -version = "0.5.1265" +version = "0.5.1266" [[package]] name = "perry-doc-fixture-my-bindings" @@ -5700,7 +5700,7 @@ dependencies = [ [[package]] name = "perry-doc-tests" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "anyhow", "clap", @@ -5715,7 +5715,7 @@ dependencies = [ [[package]] name = "perry-ext-ads" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "block2", "objc2", @@ -5725,7 +5725,7 @@ dependencies = [ [[package]] name = "perry-ext-argon2" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "argon2", "perry-ffi", @@ -5733,7 +5733,7 @@ dependencies = [ [[package]] name = "perry-ext-axios" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "perry-ffi", "reqwest", @@ -5742,7 +5742,7 @@ dependencies = [ [[package]] name = "perry-ext-bcrypt" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "bcrypt", "perry-ffi", @@ -5750,7 +5750,7 @@ dependencies = [ [[package]] name = "perry-ext-better-sqlite3" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "perry-ffi", "rusqlite", @@ -5758,7 +5758,7 @@ dependencies = [ [[package]] name = "perry-ext-cheerio" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "perry-ffi", "scraper", @@ -5766,7 +5766,7 @@ dependencies = [ [[package]] name = "perry-ext-commander" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "perry-ffi", "perry-runtime", @@ -5774,7 +5774,7 @@ dependencies = [ [[package]] name = "perry-ext-cron" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "chrono", "cron", @@ -5784,7 +5784,7 @@ dependencies = [ [[package]] name = "perry-ext-dayjs" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "chrono", "perry-ffi", @@ -5792,7 +5792,7 @@ dependencies = [ [[package]] name = "perry-ext-decimal" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "perry-ffi", "rust_decimal", @@ -5800,7 +5800,7 @@ dependencies = [ [[package]] name = "perry-ext-dotenv" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "perry-ffi", "serde_json", @@ -5808,7 +5808,7 @@ dependencies = [ [[package]] name = "perry-ext-ethers" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "perry-ffi", "rand 0.10.1", @@ -5816,7 +5816,7 @@ dependencies = [ [[package]] name = "perry-ext-events" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "perry-ffi", "perry-runtime", @@ -5824,14 +5824,14 @@ dependencies = [ [[package]] name = "perry-ext-exponential-backoff" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "perry-ffi", ] [[package]] name = "perry-ext-fastify" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "bytes", "http-body-util", @@ -5849,7 +5849,7 @@ dependencies = [ [[package]] name = "perry-ext-fetch" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "bytes", "lazy_static", @@ -5862,7 +5862,7 @@ dependencies = [ [[package]] name = "perry-ext-http" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "bytes", "h2", @@ -5886,7 +5886,7 @@ dependencies = [ [[package]] name = "perry-ext-ioredis" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "lazy_static", "perry-ffi", @@ -5896,7 +5896,7 @@ dependencies = [ [[package]] name = "perry-ext-jsonwebtoken" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "base64", "jsonwebtoken", @@ -5907,7 +5907,7 @@ dependencies = [ [[package]] name = "perry-ext-lru-cache" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "lru", "perry-ffi", @@ -5915,7 +5915,7 @@ dependencies = [ [[package]] name = "perry-ext-moment" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "chrono", "perry-ffi", @@ -5923,7 +5923,7 @@ dependencies = [ [[package]] name = "perry-ext-mongodb" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "bson", "futures-util", @@ -5935,7 +5935,7 @@ dependencies = [ [[package]] name = "perry-ext-mysql2" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "chrono", "perry-ffi", @@ -5945,7 +5945,7 @@ dependencies = [ [[package]] name = "perry-ext-nanoid" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "nanoid", "perry-ffi", @@ -5954,7 +5954,7 @@ dependencies = [ [[package]] name = "perry-ext-net" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "bytes", "perry-ffi", @@ -5967,7 +5967,7 @@ dependencies = [ [[package]] name = "perry-ext-node-forge" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "const-oid 0.9.6", "der 0.7.10", @@ -5986,7 +5986,7 @@ dependencies = [ [[package]] name = "perry-ext-nodemailer" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "lettre", "perry-ffi", @@ -5996,7 +5996,7 @@ dependencies = [ [[package]] name = "perry-ext-pdf" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "perry-ffi", "printpdf", @@ -6004,7 +6004,7 @@ dependencies = [ [[package]] name = "perry-ext-pg" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "perry-ffi", "sqlx", @@ -6013,7 +6013,7 @@ dependencies = [ [[package]] name = "perry-ext-ratelimit" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "governor", "perry-ffi", @@ -6021,7 +6021,7 @@ dependencies = [ [[package]] name = "perry-ext-sharp" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "fast_image_resize", "image", @@ -6031,14 +6031,14 @@ dependencies = [ [[package]] name = "perry-ext-slugify" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "perry-ffi", ] [[package]] name = "perry-ext-streams" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "lazy_static", "perry-ffi", @@ -6047,7 +6047,7 @@ dependencies = [ [[package]] name = "perry-ext-undici" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "perry-ffi", "perry-runtime", @@ -6056,7 +6056,7 @@ dependencies = [ [[package]] name = "perry-ext-uuid" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "perry-ffi", "uuid", @@ -6064,7 +6064,7 @@ dependencies = [ [[package]] name = "perry-ext-validator" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "perry-ffi", "regex", @@ -6074,7 +6074,7 @@ dependencies = [ [[package]] name = "perry-ext-ws" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "futures-util", "lazy_static", @@ -6087,7 +6087,7 @@ dependencies = [ [[package]] name = "perry-ext-zlib" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "brotli", "flate2", @@ -6097,7 +6097,7 @@ dependencies = [ [[package]] name = "perry-ffi" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "dashmap", "once_cell", @@ -6106,7 +6106,7 @@ dependencies = [ [[package]] name = "perry-hir" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "anyhow", "perry-api-manifest", @@ -6124,7 +6124,7 @@ dependencies = [ [[package]] name = "perry-parser" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "anyhow", "perry-diagnostics", @@ -6136,7 +6136,7 @@ dependencies = [ [[package]] name = "perry-runtime" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "anyhow", "base64", @@ -6177,14 +6177,14 @@ dependencies = [ [[package]] name = "perry-runtime-static" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "perry-runtime", ] [[package]] name = "perry-stdlib" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "aes 0.8.4", "aes 0.9.1", @@ -6279,14 +6279,14 @@ dependencies = [ [[package]] name = "perry-stdlib-static" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "perry-stdlib", ] [[package]] name = "perry-transform" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "anyhow", "perry-hir", @@ -6295,14 +6295,14 @@ dependencies = [ [[package]] name = "perry-ui" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "perry-ui-model", ] [[package]] name = "perry-ui-android" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "base64", "itoa", @@ -6319,7 +6319,7 @@ dependencies = [ [[package]] name = "perry-ui-geisterhand" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "rand 0.10.1", "serde", @@ -6329,7 +6329,7 @@ dependencies = [ [[package]] name = "perry-ui-gtk4" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "base64", "cairo-rs 0.22.0", @@ -6352,7 +6352,7 @@ dependencies = [ [[package]] name = "perry-ui-ios" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "base64", "block2", @@ -6368,7 +6368,7 @@ dependencies = [ [[package]] name = "perry-ui-macos" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "base64", "block2", @@ -6383,7 +6383,7 @@ dependencies = [ [[package]] name = "perry-ui-model" -version = "0.5.1265" +version = "0.5.1266" [[package]] name = "perry-ui-test" @@ -6394,11 +6394,11 @@ dependencies = [ [[package]] name = "perry-ui-testkit" -version = "0.5.1265" +version = "0.5.1266" [[package]] name = "perry-ui-tvos" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "base64", "block2", @@ -6414,7 +6414,7 @@ dependencies = [ [[package]] name = "perry-ui-visionos" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "base64", "block2", @@ -6430,7 +6430,7 @@ dependencies = [ [[package]] name = "perry-ui-watchos" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "block2", "libc", @@ -6443,7 +6443,7 @@ dependencies = [ [[package]] name = "perry-ui-windows" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "base64", "libc", @@ -6460,14 +6460,14 @@ dependencies = [ [[package]] name = "perry-ui-windows-winui" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "perry-ui-windows", ] [[package]] name = "perry-updater" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "anyhow", "base64", @@ -6483,7 +6483,7 @@ dependencies = [ [[package]] name = "perry-wasm-host" -version = "0.5.1265" +version = "0.5.1266" dependencies = [ "wasmi", ] diff --git a/Cargo.toml b/Cargo.toml index 7358b3c628..19b4d94ebb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -292,7 +292,7 @@ codegen-units = 16 codegen-units = 16 [workspace.package] -version = "0.5.1265" +version = "0.5.1266" edition = "2021" license = "MIT" repository = "https://github.com/PerryTS/perry" diff --git a/changelog.d/6960-intl-rtf-auto-instanceof.md b/changelog.d/6960-intl-rtf-auto-instanceof.md new file mode 100644 index 0000000000..917d049d04 --- /dev/null +++ b/changelog.d/6960-intl-rtf-auto-instanceof.md @@ -0,0 +1,22 @@ +**Intl:** two parity fixes for #6960. + +1. `Intl.RelativeTimeFormat` with `numeric: "auto"` now substitutes the en-US + CLDR relative word forms (`yesterday`/`today`/`tomorrow`, `last`/`this`/ + `next `, `now`, …) instead of always rendering the numeric form. + `format` and `formatToParts` share the path; a word-form result is a single + `"literal"` part (no `unit` field), matching Node. Short/narrow styles + abbreviate `week`/`year` (`wk.` / `yr.`). Values without a CLDR word form + (including non-integers and `|value| > 1` for most units) still use the + numeric form; `numeric: "always"` is unchanged. + +2. `value instanceof Intl.` is true for `class X extends Intl.` + subclass instances. `intl_subclass_super` already copied the constructor's + `__intlKind` brand onto `this`, but `intl_instanceof` only walked the + static-prototype side table — which never linked `X.prototype` to + `Intl..prototype` because Intl constructors are closures without a + class-id registry edge. The probe now brand-matches first (same shape as + Temporal's brand-cell arm) and still falls through to a real + `getPrototypeOf` walk for direct instances. + +Regression: `test-files/test_gap_intl_rtf_auto_instanceof_6960.ts` (byte-for- +byte vs Node 26.5.0). diff --git a/crates/perry-runtime/src/intl/list_relative_plural.rs b/crates/perry-runtime/src/intl/list_relative_plural.rs index 89e85c845a..43f125a125 100644 --- a/crates/perry-runtime/src/intl/list_relative_plural.rs +++ b/crates/perry-runtime/src/intl/list_relative_plural.rs @@ -291,12 +291,68 @@ pub(crate) fn rtf_singular_unit(unit: &str) -> Option<&'static str> { RTF_SINGULAR_UNITS.iter().copied().find(|u| *u == candidate) } -/// Build the long-form, `numeric: "always"` en-US relative-time parts for -/// `value` in `unit`. (`short`/`narrow` abbreviations and the `numeric: "auto"` -/// special words — "tomorrow"/"yesterday" — need CLDR data and fall back to the -/// long numeric form here.) Returns `(leading, number, trailing)` literal/number -/// fragments so `format` and `formatToParts` stay consistent. -pub(crate) fn rtf_parts(value: f64, unit: &str) -> Vec<(&'static str, String)> { +/// en-US CLDR relative word form for `numeric: "auto"` when one exists for +/// `(value, unit, style)`. Returns a single full phrase (e.g. `"yesterday"`, +/// `"last week"`); `None` means fall through to the numeric form. Only the +/// discrete integer values that CLDR actually names for en are covered — +/// everything else (including non-integers and |value| > 1) stays numeric. +/// +/// `style` is `"long"` / `"short"` / `"narrow"`; short and narrow only differ +/// from long for `week` and `year` unit abbreviations (`wk.` / `yr.`). +fn rtf_auto_word(value: f64, unit: &str, style: &str) -> Option<&'static str> { + // Auto forms apply only to exact integers. `0.0` is fine; `0.5` is not. + if value.fract() != 0.0 { + return None; + } + let n = value as i64; + let shortish = style == "short" || style == "narrow"; + match (unit, n) { + ("second", 0) => Some("now"), + ("minute", 0) => Some("this minute"), + ("hour", 0) => Some("this hour"), + ("day", -1) => Some("yesterday"), + ("day", 0) => Some("today"), + ("day", 1) => Some("tomorrow"), + ("week", -1) => Some(if shortish { "last wk." } else { "last week" }), + ("week", 0) => Some(if shortish { "this wk." } else { "this week" }), + ("week", 1) => Some(if shortish { "next wk." } else { "next week" }), + ("month", -1) => Some("last month"), + ("month", 0) => Some("this month"), + ("month", 1) => Some("next month"), + ("quarter", -1) => Some("last quarter"), + ("quarter", 0) => Some("this quarter"), + ("quarter", 1) => Some("next quarter"), + ("year", -1) => Some(if shortish { "last yr." } else { "last year" }), + ("year", 0) => Some(if shortish { "this yr." } else { "this year" }), + ("year", 1) => Some(if shortish { "next yr." } else { "next year" }), + _ => None, + } +} + +/// Build en-US relative-time parts for `value` in `unit`. +/// +/// When `numeric == "auto"`, substitutes the CLDR relative word form +/// (`"yesterday"` / `"today"` / `"tomorrow"`, `"last/this/next "`, +/// `"now"`, …) for the discrete integer values CLDR names; otherwise (and for +/// every other value) renders the long numeric form (`"in 2 days"` / +/// `"1 day ago"`). `format` and `formatToParts` share this path so they stay +/// consistent. A word-form result is a single `"literal"` part (no unit field), +/// matching Node / ECMA-402 FormatRelativeTimeToParts. +/// +/// `style` is consulted only for the auto word forms (`week`/`year` short +/// abbreviations); the numeric path still uses the long unit names (a +/// pre-existing limitation of the en-US fallback formatter). +pub(crate) fn rtf_parts( + value: f64, + unit: &str, + numeric: &str, + style: &str, +) -> Vec<(&'static str, String)> { + if numeric == "auto" { + if let Some(word) = rtf_auto_word(value, unit, style) { + return vec![("literal", word.to_string())]; + } + } let abs = value.abs(); let num_str = format_number_parts(abs, "en-US", None, None); let unit_display = if abs == 1.0 { @@ -332,9 +388,12 @@ pub(crate) fn to_number_reject_bigint(value: f64) -> f64 { /// Shared steps of `format`/`formatToParts`: `value = ? ToNumber(value)` (a /// Symbol or BigInt throws TypeError; an object's `valueOf` is honoured), then /// `unit = ? ToString(unit)`, then the RangeError guards for a non-finite value -/// or an unsanctioned unit. Returns the rendered parts together with the -/// resolved singular `unit` (the `[[Unit]]` field formatToParts attaches). +/// or an unsanctioned unit. Reads the instance's `[[Numeric]]` / `[[Style]]` +/// slots so `numeric: "auto"` can select CLDR word forms (#6960). Returns the +/// rendered parts together with the resolved singular `unit` (the `[[Unit]]` +/// field formatToParts attaches — omitted for pure-literal auto words). pub(crate) fn rtf_instance_parts_and_unit( + obj: *const ObjectHeader, value: f64, unit_arg: f64, ) -> (Vec<(&'static str, String)>, &'static str) { @@ -355,11 +414,17 @@ pub(crate) fn rtf_instance_parts_and_unit( "Value {unit_str} out of range for Intl.RelativeTimeFormat.format() unit" )); }; - (rtf_parts(number, unit), unit) + let numeric = get_string_field(obj, KEY_NUMERIC).unwrap_or_else(|| "always".to_string()); + let style = get_string_field(obj, KEY_RTF_STYLE).unwrap_or_else(|| "long".to_string()); + (rtf_parts(number, unit, &numeric, &style), unit) } -pub(crate) fn rtf_instance_parts(value: f64, unit_arg: f64) -> Vec<(&'static str, String)> { - rtf_instance_parts_and_unit(value, unit_arg).0 +pub(crate) fn rtf_instance_parts( + obj: *const ObjectHeader, + value: f64, + unit_arg: f64, +) -> Vec<(&'static str, String)> { + rtf_instance_parts_and_unit(obj, value, unit_arg).0 } /// Build the `formatToParts` array, attaching the `[[Unit]]` field to every part @@ -384,9 +449,9 @@ pub(crate) extern "C" fn rtf_format_thunk( value: f64, unit: f64, ) -> f64 { - let _obj = this_intl_object("format", KIND_RELATIVE_TIME); + let obj = this_intl_object("format", KIND_RELATIVE_TIME); string_value( - &rtf_instance_parts(value, unit) + &rtf_instance_parts(obj, value, unit) .iter() .map(|(_, v)| v.as_str()) .collect::(), @@ -398,9 +463,9 @@ pub(crate) extern "C" fn rtf_bound_format_thunk( value: f64, unit: f64, ) -> f64 { - let _obj = captured_intl_object(closure, "format", KIND_RELATIVE_TIME); + let obj = captured_intl_object(closure, "format", KIND_RELATIVE_TIME); string_value( - &rtf_instance_parts(value, unit) + &rtf_instance_parts(obj, value, unit) .iter() .map(|(_, v)| v.as_str()) .collect::(), @@ -412,8 +477,8 @@ pub(crate) extern "C" fn rtf_to_parts_thunk( value: f64, unit: f64, ) -> f64 { - let _obj = this_intl_object("formatToParts", KIND_RELATIVE_TIME); - let (parts, unit) = rtf_instance_parts_and_unit(value, unit); + let obj = this_intl_object("formatToParts", KIND_RELATIVE_TIME); + let (parts, unit) = rtf_instance_parts_and_unit(obj, value, unit); rtf_parts_to_js_array(&parts, unit) } @@ -422,8 +487,8 @@ pub(crate) extern "C" fn rtf_bound_to_parts_thunk( value: f64, unit: f64, ) -> f64 { - let _obj = captured_intl_object(closure, "formatToParts", KIND_RELATIVE_TIME); - let (parts, unit) = rtf_instance_parts_and_unit(value, unit); + let obj = captured_intl_object(closure, "formatToParts", KIND_RELATIVE_TIME); + let (parts, unit) = rtf_instance_parts_and_unit(obj, value, unit); rtf_parts_to_js_array(&parts, unit) } diff --git a/crates/perry-runtime/src/intl/subclass.rs b/crates/perry-runtime/src/intl/subclass.rs index ef67543ba0..a44d80c61f 100644 --- a/crates/perry-runtime/src/intl/subclass.rs +++ b/crates/perry-runtime/src/intl/subclass.rs @@ -52,42 +52,77 @@ pub(super) fn locale_instance_tag(value: f64) -> Option { get_string_field(obj, "__localeFull") } -/// The compiled function pointers of every `Intl.*` service constructor thunk. +/// The compiled function pointers of every `Intl.*` service constructor thunk, +/// paired with the `__intlKind` brand string each stamps on its instances. /// Used by [`is_intl_constructor_value`] to recognize a `class X extends /// Intl.` parent value from its closure so `super(...)` can construct it /// correctly (with `new.target` set) rather than tripping the -/// `require_new_target` guard. -fn intl_constructor_func_ptrs() -> [*const u8; 10] { +/// `require_new_target` guard, and by [`intl_instanceof`] to brand-match +/// subclass instances (#6960). +fn intl_constructor_entries() -> [(*const u8, &'static str); 10] { [ - super::number_format_constructor_thunk as *const u8, - super::date_time_format_constructor_thunk as *const u8, - super::collator_constructor_thunk as *const u8, - super::segmenter_constructor_thunk as *const u8, - super::list_format_constructor_thunk as *const u8, - super::relative_time_format_constructor_thunk as *const u8, - super::plural_rules_constructor_thunk as *const u8, - super::duration_format::constructor_thunk as *const u8, - super::display_names::constructor_thunk as *const u8, - super::locale::locale_constructor_thunk as *const u8, + ( + super::number_format_constructor_thunk as *const u8, + "NumberFormat", + ), + ( + super::date_time_format_constructor_thunk as *const u8, + "DateTimeFormat", + ), + (super::collator_constructor_thunk as *const u8, "Collator"), + (super::segmenter_constructor_thunk as *const u8, "Segmenter"), + ( + super::list_format_constructor_thunk as *const u8, + "ListFormat", + ), + ( + super::relative_time_format_constructor_thunk as *const u8, + "RelativeTimeFormat", + ), + ( + super::plural_rules_constructor_thunk as *const u8, + "PluralRules", + ), + ( + super::duration_format::constructor_thunk as *const u8, + "DurationFormat", + ), + ( + super::display_names::constructor_thunk as *const u8, + "DisplayNames", + ), + ( + super::locale::locale_constructor_thunk as *const u8, + "Locale", + ), ] } -/// `true` when `parent_val` is (the closure for) an `Intl.*` service -/// constructor. `class X extends Intl.ListFormat` routes its `super()` through -/// the generic runtime-value dispatcher, which would invoke the constructor -/// without a `new.target` and throw "Constructor Intl.X requires 'new'"; this -/// lets the super-call path recognize the parent and construct it properly. -pub(crate) fn is_intl_constructor_value(parent_val: f64) -> bool { +/// If `parent_val` is an `Intl.*` service constructor closure, return the +/// `__intlKind` brand string it stamps on instances (`"NumberFormat"`, …). +fn intl_constructor_kind(parent_val: f64) -> Option<&'static str> { let jsval = JSValue::from_bits(parent_val.to_bits()); if !jsval.is_pointer() { - return false; + return None; } let closure = jsval.as_pointer() as *const ClosureHeader; if closure.is_null() { - return false; + return None; } let fp = unsafe { (*closure).func_ptr }; - intl_constructor_func_ptrs().iter().any(|p| *p == fp) + intl_constructor_entries() + .iter() + .find(|(p, _)| *p == fp) + .map(|(_, kind)| *kind) +} + +/// `true` when `parent_val` is (the closure for) an `Intl.*` service +/// constructor. `class X extends Intl.ListFormat` routes its `super()` through +/// the generic runtime-value dispatcher, which would invoke the constructor +/// without a `new.target` and throw "Constructor Intl.X requires 'new'"; this +/// lets the super-call path recognize the parent and construct it properly. +pub(crate) fn is_intl_constructor_value(parent_val: f64) -> bool { + intl_constructor_kind(parent_val).is_some() } /// `class X extends Intl.` super-call handling. An `Intl.*` service @@ -132,46 +167,88 @@ pub(crate) unsafe fn intl_subclass_super( /// is an Intl service constructor. Intl instances are plain heap objects whose /// `[[Prototype]]` is set to `Intl..prototype` (via /// `object_set_static_prototype`), but the generic dynamic-`instanceof` path has -/// no class-id for them and no generic prototype walk, so it returned `false` -/// even though `Object.getPrototypeOf(inst) === Intl..prototype`. Walk the -/// value's static-prototype chain and compare each link against the -/// constructor's `.prototype`. Returns `None` when `type_ref` is not an Intl -/// constructor (caller keeps its existing resolution); `Some(bool)` otherwise. +/// no class-id for them, so without this hook a direct instance returned +/// `false` even though `Object.getPrototypeOf(inst) === Intl..prototype`. +/// +/// Two recognition arms (#6960): +/// +/// 1. **Brand** — `intl_subclass_super` copies the constructor's `__intlKind` +/// field onto the subclass `this`, so a `class X extends Intl.NumberFormat` +/// instance carries the same brand as a direct instance even when the +/// prototype chain is not yet wired through `Intl.NumberFormat.prototype` +/// (Perry's class-registry parent edge only tracks class-id parents, and +/// Intl constructors are closures). Mirrors the Temporal brand-cell arm. +/// 2. **Prototype walk** — OrdinaryHasInstance via +/// `js_object_get_prototype_of`, covering direct instances and any subclass +/// whose `X.prototype` *is* linked to `Intl..prototype`. +/// +/// Returns `None` when `type_ref` is not an Intl constructor (caller keeps its +/// existing resolution); `Some(bool)` otherwise. pub(crate) fn intl_instanceof(value: f64, type_ref: f64) -> Option { - if !is_intl_constructor_value(type_ref) { + let Some(expected_kind) = intl_constructor_kind(type_ref) else { return None; + }; + // OrdinaryHasInstance step 3: a non-Object left operand is never an + // instance. Guard before any walk — primitives would either throw + // (null/undefined) or climb a wrapper chain (string/symbol) and spuriously + // match. + { + let jv = JSValue::from_bits(value.to_bits()); + if jv.is_null() + || jv.is_undefined() + || jv.is_bool() + || jv.is_int32() + || jv.is_any_string() + || jv.is_bigint() + || unsafe { crate::symbol::js_is_symbol(value) != 0 } + { + return Some(false); + } + } + // Brand arm: subclass instances re-homed by `intl_subclass_super`. + if let Some(obj) = object_ptr_from_value(value) { + if get_string_field(obj, KEY_KIND).as_deref() == Some(expected_kind) { + return Some(true); + } } let jsval = JSValue::from_bits(type_ref.to_bits()); let closure = jsval.as_pointer::() as usize; let proto = crate::closure::closure_get_dynamic_prop(closure, "prototype"); - let proto_js = JSValue::from_bits(proto.to_bits()); - if !proto_js.is_pointer() { + let target = proto_identity_addr(proto); + if target == 0 { return Some(false); } - let target_bits = proto.to_bits(); - // Walk `value`'s [[Prototype]] chain (bounded against cycles). - let mut cur = value.to_bits(); + // Prototype-walk arm: direct instances (and any fully-linked subclass). + let mut cur = crate::object::js_object_get_prototype_of(value); for _ in 0..64 { - let top16 = cur >> 48; - let raw = if top16 == 0x7FFD { - (cur & 0x0000_FFFF_FFFF_FFFF) as usize - } else if top16 == 0 { - cur as usize - } else { + if JSValue::from_bits(cur.to_bits()).is_null() { return Some(false); - }; - if raw < 0x10000 { + } + let cur_addr = proto_identity_addr(cur); + if cur_addr == 0 { return Some(false); } - match crate::object::prototype_chain::object_static_prototype(raw) { - Some(p) => { - if p == target_bits { - return Some(true); - } - cur = p; - } - None => return Some(false), + if cur_addr == target { + return Some(true); } + cur = crate::object::js_object_get_prototype_of(cur); } Some(false) } + +/// Normalize a value to its heap-pointer address for prototype identity +/// comparison — a NaN-boxed `POINTER_TAG` value or a raw heap pointer both +/// resolve to their address; any non-pointer yields 0. Mirrors the helper in +/// `object/instanceof.rs` (kept local so this module stays free of a private +/// cross-crate dependency on that helper). +fn proto_identity_addr(v: f64) -> usize { + let bits = v.to_bits(); + let top16 = bits >> 48; + if top16 == 0x7FFD { + (bits & crate::value::POINTER_MASK) as usize + } else if top16 == 0 && bits >= 0x1000 { + bits as usize + } else { + 0 + } +} diff --git a/test-files/test_gap_intl_rtf_auto_instanceof_6960.ts b/test-files/test_gap_intl_rtf_auto_instanceof_6960.ts new file mode 100644 index 0000000000..f4f11beed2 --- /dev/null +++ b/test-files/test_gap_intl_rtf_auto_instanceof_6960.ts @@ -0,0 +1,71 @@ +// #6960: two Intl parity gaps — +// 1. RelativeTimeFormat with numeric:"auto" must use CLDR relative word +// forms (yesterday/today/tomorrow, last/this/next , now, …) +// instead of always rendering the numeric form. +// 2. `instanceof Intl.` must be true for `class X extends Intl.` +// subclass instances (OrdinaryHasInstance walks the real prototype +// chain: X.prototype → Intl..prototype). + +const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" }); + +// day: the canonical three word forms +console.log("day -1 :", rtf.format(-1, "day")); +console.log("day 0 :", rtf.format(0, "day")); +console.log("day 1 :", rtf.format(1, "day")); +// day ±2 stays numeric +console.log("day -2 :", rtf.format(-2, "day")); +console.log("day 2 :", rtf.format(2, "day")); + +// second / minute / hour: only the zero form is special +console.log("second 0:", rtf.format(0, "second")); +console.log("minute 0:", rtf.format(0, "minute")); +console.log("hour 0 :", rtf.format(0, "hour")); +console.log("second -1:", rtf.format(-1, "second")); + +// week / month / quarter / year: last/this/next +console.log("week -1 :", rtf.format(-1, "week")); +console.log("week 0 :", rtf.format(0, "week")); +console.log("week 1 :", rtf.format(1, "week")); +console.log("month -1:", rtf.format(-1, "month")); +console.log("month 0:", rtf.format(0, "month")); +console.log("year -1 :", rtf.format(-1, "year")); +console.log("year 0 :", rtf.format(0, "year")); +console.log("year 1 :", rtf.format(1, "year")); +console.log("quarter 0:", rtf.format(0, "quarter")); + +// numeric:"always" still produces the numeric form even for -1 day +const always = new Intl.RelativeTimeFormat("en", { numeric: "always" }); +console.log("always day -1:", always.format(-1, "day")); + +// short style auto forms abbreviate week/year +const short = new Intl.RelativeTimeFormat("en", { numeric: "auto", style: "short" }); +console.log("short week -1:", short.format(-1, "week")); +console.log("short year 1:", short.format(1, "year")); +console.log("short day -1:", short.format(-1, "day")); + +// formatToParts for a word form is a single literal (no unit field) +const parts = rtf.formatToParts(-1, "day"); +console.log( + "parts day -1:", + parts.map((p) => p.type + ":" + p.value + (p.unit ? "@" + p.unit : "")).join("|"), +); +// numeric form still attaches unit to the number part +const partsNum = rtf.formatToParts(-2, "day"); +console.log( + "parts day -2:", + partsNum.map((p) => p.type + ":" + p.value + (p.unit ? "@" + p.unit : "")).join("|"), +); + +// --- instanceof through an Intl subclass --- +class MyNF extends Intl.NumberFormat {} +const m = new MyNF("en-US"); +console.log("subclass format:", m.format(99)); +console.log("instanceof NumberFormat:", m instanceof Intl.NumberFormat); +console.log("instanceof MyNF:", m instanceof MyNF); +console.log("direct instanceof NumberFormat:", new Intl.NumberFormat("en-US") instanceof Intl.NumberFormat); +console.log("plain object instanceof:", ({} as any) instanceof Intl.NumberFormat); + +class MyRTF extends Intl.RelativeTimeFormat {} +const mr = new MyRTF("en", { numeric: "auto" }); +console.log("subclass RTF format:", mr.format(-1, "day")); +console.log("subclass RTF instanceof:", mr instanceof Intl.RelativeTimeFormat); From c0067758eb164330b8ccc868989dad970bd4dce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Fri, 31 Jul 2026 09:36:51 +0200 Subject: [PATCH 2/4] changelog: key #6960 fragment on PR #7126 --- ...tl-rtf-auto-instanceof.md => 7126-intl-rtf-auto-instanceof.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename changelog.d/{6960-intl-rtf-auto-instanceof.md => 7126-intl-rtf-auto-instanceof.md} (100%) diff --git a/changelog.d/6960-intl-rtf-auto-instanceof.md b/changelog.d/7126-intl-rtf-auto-instanceof.md similarity index 100% rename from changelog.d/6960-intl-rtf-auto-instanceof.md rename to changelog.d/7126-intl-rtf-auto-instanceof.md From f646a503b7455aa3ea5f8cf683595cd1fb986480 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Fri, 31 Jul 2026 09:55:33 +0200 Subject: [PATCH 3/4] fix(intl): address CodeRabbit review on #7126 - Read [[Numeric]]/[[Style]] before ToNumber/ToString so the receiver pointer is not held across a user-callback/GC point. - Add short/narrow auto word forms for month (mo.) and quarter (qtr.). - Route proto_identity_addr through is_plausible_heap_addr. --- .../src/intl/list_relative_plural.rs | 44 +++++++++++++------ crates/perry-runtime/src/intl/subclass.rs | 16 ++++--- .../test_gap_intl_rtf_auto_instanceof_6960.ts | 4 +- 3 files changed, 45 insertions(+), 19 deletions(-) diff --git a/crates/perry-runtime/src/intl/list_relative_plural.rs b/crates/perry-runtime/src/intl/list_relative_plural.rs index 43f125a125..3d1247d93a 100644 --- a/crates/perry-runtime/src/intl/list_relative_plural.rs +++ b/crates/perry-runtime/src/intl/list_relative_plural.rs @@ -297,8 +297,9 @@ pub(crate) fn rtf_singular_unit(unit: &str) -> Option<&'static str> { /// discrete integer values that CLDR actually names for en are covered — /// everything else (including non-integers and |value| > 1) stays numeric. /// -/// `style` is `"long"` / `"short"` / `"narrow"`; short and narrow only differ -/// from long for `week` and `year` unit abbreviations (`wk.` / `yr.`). +/// `style` is `"long"` / `"short"` / `"narrow"`; short and narrow differ from +/// long for `week`/`month`/`quarter`/`year` abbreviations (`wk.` / `mo.` / +/// `qtr.` / `yr.`), matching ICU en. fn rtf_auto_word(value: f64, unit: &str, style: &str) -> Option<&'static str> { // Auto forms apply only to exact integers. `0.0` is fine; `0.5` is not. if value.fract() != 0.0 { @@ -316,12 +317,24 @@ fn rtf_auto_word(value: f64, unit: &str, style: &str) -> Option<&'static str> { ("week", -1) => Some(if shortish { "last wk." } else { "last week" }), ("week", 0) => Some(if shortish { "this wk." } else { "this week" }), ("week", 1) => Some(if shortish { "next wk." } else { "next week" }), - ("month", -1) => Some("last month"), - ("month", 0) => Some("this month"), - ("month", 1) => Some("next month"), - ("quarter", -1) => Some("last quarter"), - ("quarter", 0) => Some("this quarter"), - ("quarter", 1) => Some("next quarter"), + ("month", -1) => Some(if shortish { "last mo." } else { "last month" }), + ("month", 0) => Some(if shortish { "this mo." } else { "this month" }), + ("month", 1) => Some(if shortish { "next mo." } else { "next month" }), + ("quarter", -1) => Some(if shortish { + "last qtr." + } else { + "last quarter" + }), + ("quarter", 0) => Some(if shortish { + "this qtr." + } else { + "this quarter" + }), + ("quarter", 1) => Some(if shortish { + "next qtr." + } else { + "next quarter" + }), ("year", -1) => Some(if shortish { "last yr." } else { "last year" }), ("year", 0) => Some(if shortish { "this yr." } else { "this year" }), ("year", 1) => Some(if shortish { "next yr." } else { "next year" }), @@ -339,9 +352,9 @@ fn rtf_auto_word(value: f64, unit: &str, style: &str) -> Option<&'static str> { /// consistent. A word-form result is a single `"literal"` part (no unit field), /// matching Node / ECMA-402 FormatRelativeTimeToParts. /// -/// `style` is consulted only for the auto word forms (`week`/`year` short -/// abbreviations); the numeric path still uses the long unit names (a -/// pre-existing limitation of the en-US fallback formatter). +/// `style` is consulted only for the auto word forms (`week`/`month`/ +/// `quarter`/`year` short abbreviations); the numeric path still uses the long +/// unit names (a pre-existing limitation of the en-US fallback formatter). pub(crate) fn rtf_parts( value: f64, unit: &str, @@ -397,6 +410,13 @@ pub(crate) fn rtf_instance_parts_and_unit( value: f64, unit_arg: f64, ) -> (Vec<(&'static str, String)>, &'static str) { + // Read `[[Numeric]]` / `[[Style]]` before ToNumber/ToString: those ops can + // invoke user `valueOf`/`toString`/`Symbol.toPrimitive`, which may allocate + // and evacuate `obj`. The slots are immutable after construction, so + // reading them first is observationally identical and keeps `obj` from + // being held as a raw pointer across a GC-capable call (#6960 / CodeRabbit). + let numeric = get_string_field(obj, KEY_NUMERIC).unwrap_or_else(|| "always".to_string()); + let style = get_string_field(obj, KEY_RTF_STYLE).unwrap_or_else(|| "long".to_string()); // ToNumber: a Symbol/BigInt value throws TypeError *before* the finite-ness // RangeError (format/value-symbol.js); an object's valueOf is invoked. let number = to_number_reject_bigint(value); @@ -414,8 +434,6 @@ pub(crate) fn rtf_instance_parts_and_unit( "Value {unit_str} out of range for Intl.RelativeTimeFormat.format() unit" )); }; - let numeric = get_string_field(obj, KEY_NUMERIC).unwrap_or_else(|| "always".to_string()); - let style = get_string_field(obj, KEY_RTF_STYLE).unwrap_or_else(|| "long".to_string()); (rtf_parts(number, unit, &numeric, &style), unit) } diff --git a/crates/perry-runtime/src/intl/subclass.rs b/crates/perry-runtime/src/intl/subclass.rs index a44d80c61f..45b7886527 100644 --- a/crates/perry-runtime/src/intl/subclass.rs +++ b/crates/perry-runtime/src/intl/subclass.rs @@ -238,16 +238,22 @@ pub(crate) fn intl_instanceof(value: f64, type_ref: f64) -> Option { /// Normalize a value to its heap-pointer address for prototype identity /// comparison — a NaN-boxed `POINTER_TAG` value or a raw heap pointer both -/// resolve to their address; any non-pointer yields 0. Mirrors the helper in -/// `object/instanceof.rs` (kept local so this module stays free of a private -/// cross-crate dependency on that helper). +/// resolve to their address; any non-pointer / non-heap yields 0. Mirrors +/// `object/instanceof.rs::proto_identity_addr` but routes the floor check +/// through the canonical `is_plausible_heap_addr` predicate so handle-band +/// rejection stays single-sourced. fn proto_identity_addr(v: f64) -> usize { let bits = v.to_bits(); let top16 = bits >> 48; - if top16 == 0x7FFD { + let addr = if top16 == 0x7FFD { (bits & crate::value::POINTER_MASK) as usize - } else if top16 == 0 && bits >= 0x1000 { + } else if top16 == 0 { bits as usize + } else { + return 0; + }; + if crate::value::addr_class::is_plausible_heap_addr(addr) { + addr } else { 0 } diff --git a/test-files/test_gap_intl_rtf_auto_instanceof_6960.ts b/test-files/test_gap_intl_rtf_auto_instanceof_6960.ts index f4f11beed2..b13c722551 100644 --- a/test-files/test_gap_intl_rtf_auto_instanceof_6960.ts +++ b/test-files/test_gap_intl_rtf_auto_instanceof_6960.ts @@ -37,9 +37,11 @@ console.log("quarter 0:", rtf.format(0, "quarter")); const always = new Intl.RelativeTimeFormat("en", { numeric: "always" }); console.log("always day -1:", always.format(-1, "day")); -// short style auto forms abbreviate week/year +// short style auto forms abbreviate week/month/quarter/year const short = new Intl.RelativeTimeFormat("en", { numeric: "auto", style: "short" }); console.log("short week -1:", short.format(-1, "week")); +console.log("short month 0:", short.format(0, "month")); +console.log("short quarter 1:", short.format(1, "quarter")); console.log("short year 1:", short.format(1, "year")); console.log("short day -1:", short.format(-1, "day")); From e417957ce923ca265fbdbc0afb6a5ac5231224b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Fri, 31 Jul 2026 09:56:00 +0200 Subject: [PATCH 4/4] chore: drop version bump from #7126 (maintainer bumps at merge) Leave workspace package version and CLAUDE.md Current Version at 0.5.1265 so the PR does not race with concurrent main bumps. --- CLAUDE.md | 2 +- Cargo.lock | 152 ++++++++++++++++++++++++++--------------------------- Cargo.toml | 2 +- 3 files changed, 78 insertions(+), 78 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index a642c4bad7..355e1e5b8d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -8,7 +8,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co Perry is a native TypeScript compiler written in Rust that compiles TypeScript source code directly to native executables. It uses SWC for TypeScript parsing and LLVM for code generation. -**Current Version:** 0.5.1266 +**Current Version:** 0.5.1265 ## TypeScript Parity Status diff --git a/Cargo.lock b/Cargo.lock index 8f7e7875d7..09786f5717 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5503,7 +5503,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "perry" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "anyhow", "base64", @@ -5563,14 +5563,14 @@ dependencies = [ [[package]] name = "perry-api-manifest" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "serde", ] [[package]] name = "perry-audio-miniaudio" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "cc", "libc", @@ -5578,7 +5578,7 @@ dependencies = [ [[package]] name = "perry-codegen" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "anyhow", "log", @@ -5592,7 +5592,7 @@ dependencies = [ [[package]] name = "perry-codegen-arkts" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "anyhow", "perry-hir", @@ -5600,7 +5600,7 @@ dependencies = [ [[package]] name = "perry-codegen-glance" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "anyhow", "perry-hir", @@ -5608,7 +5608,7 @@ dependencies = [ [[package]] name = "perry-codegen-js" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "anyhow", "perry-dispatch", @@ -5617,7 +5617,7 @@ dependencies = [ [[package]] name = "perry-codegen-swiftui" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "anyhow", "perry-hir", @@ -5625,7 +5625,7 @@ dependencies = [ [[package]] name = "perry-codegen-wasm" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "anyhow", "base64", @@ -5637,7 +5637,7 @@ dependencies = [ [[package]] name = "perry-codegen-wear-tiles" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "anyhow", "perry-hir", @@ -5645,7 +5645,7 @@ dependencies = [ [[package]] name = "perry-container-compose" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "anyhow", "async-trait", @@ -5674,14 +5674,14 @@ dependencies = [ [[package]] name = "perry-container-e2e" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "anyhow", ] [[package]] name = "perry-diagnostics" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "serde", "serde_json", @@ -5689,7 +5689,7 @@ dependencies = [ [[package]] name = "perry-dispatch" -version = "0.5.1266" +version = "0.5.1265" [[package]] name = "perry-doc-fixture-my-bindings" @@ -5700,7 +5700,7 @@ dependencies = [ [[package]] name = "perry-doc-tests" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "anyhow", "clap", @@ -5715,7 +5715,7 @@ dependencies = [ [[package]] name = "perry-ext-ads" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "block2", "objc2", @@ -5725,7 +5725,7 @@ dependencies = [ [[package]] name = "perry-ext-argon2" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "argon2", "perry-ffi", @@ -5733,7 +5733,7 @@ dependencies = [ [[package]] name = "perry-ext-axios" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "perry-ffi", "reqwest", @@ -5742,7 +5742,7 @@ dependencies = [ [[package]] name = "perry-ext-bcrypt" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "bcrypt", "perry-ffi", @@ -5750,7 +5750,7 @@ dependencies = [ [[package]] name = "perry-ext-better-sqlite3" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "perry-ffi", "rusqlite", @@ -5758,7 +5758,7 @@ dependencies = [ [[package]] name = "perry-ext-cheerio" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "perry-ffi", "scraper", @@ -5766,7 +5766,7 @@ dependencies = [ [[package]] name = "perry-ext-commander" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "perry-ffi", "perry-runtime", @@ -5774,7 +5774,7 @@ dependencies = [ [[package]] name = "perry-ext-cron" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "chrono", "cron", @@ -5784,7 +5784,7 @@ dependencies = [ [[package]] name = "perry-ext-dayjs" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "chrono", "perry-ffi", @@ -5792,7 +5792,7 @@ dependencies = [ [[package]] name = "perry-ext-decimal" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "perry-ffi", "rust_decimal", @@ -5800,7 +5800,7 @@ dependencies = [ [[package]] name = "perry-ext-dotenv" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "perry-ffi", "serde_json", @@ -5808,7 +5808,7 @@ dependencies = [ [[package]] name = "perry-ext-ethers" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "perry-ffi", "rand 0.10.1", @@ -5816,7 +5816,7 @@ dependencies = [ [[package]] name = "perry-ext-events" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "perry-ffi", "perry-runtime", @@ -5824,14 +5824,14 @@ dependencies = [ [[package]] name = "perry-ext-exponential-backoff" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "perry-ffi", ] [[package]] name = "perry-ext-fastify" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "bytes", "http-body-util", @@ -5849,7 +5849,7 @@ dependencies = [ [[package]] name = "perry-ext-fetch" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "bytes", "lazy_static", @@ -5862,7 +5862,7 @@ dependencies = [ [[package]] name = "perry-ext-http" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "bytes", "h2", @@ -5886,7 +5886,7 @@ dependencies = [ [[package]] name = "perry-ext-ioredis" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "lazy_static", "perry-ffi", @@ -5896,7 +5896,7 @@ dependencies = [ [[package]] name = "perry-ext-jsonwebtoken" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "base64", "jsonwebtoken", @@ -5907,7 +5907,7 @@ dependencies = [ [[package]] name = "perry-ext-lru-cache" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "lru", "perry-ffi", @@ -5915,7 +5915,7 @@ dependencies = [ [[package]] name = "perry-ext-moment" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "chrono", "perry-ffi", @@ -5923,7 +5923,7 @@ dependencies = [ [[package]] name = "perry-ext-mongodb" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "bson", "futures-util", @@ -5935,7 +5935,7 @@ dependencies = [ [[package]] name = "perry-ext-mysql2" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "chrono", "perry-ffi", @@ -5945,7 +5945,7 @@ dependencies = [ [[package]] name = "perry-ext-nanoid" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "nanoid", "perry-ffi", @@ -5954,7 +5954,7 @@ dependencies = [ [[package]] name = "perry-ext-net" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "bytes", "perry-ffi", @@ -5967,7 +5967,7 @@ dependencies = [ [[package]] name = "perry-ext-node-forge" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "const-oid 0.9.6", "der 0.7.10", @@ -5986,7 +5986,7 @@ dependencies = [ [[package]] name = "perry-ext-nodemailer" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "lettre", "perry-ffi", @@ -5996,7 +5996,7 @@ dependencies = [ [[package]] name = "perry-ext-pdf" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "perry-ffi", "printpdf", @@ -6004,7 +6004,7 @@ dependencies = [ [[package]] name = "perry-ext-pg" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "perry-ffi", "sqlx", @@ -6013,7 +6013,7 @@ dependencies = [ [[package]] name = "perry-ext-ratelimit" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "governor", "perry-ffi", @@ -6021,7 +6021,7 @@ dependencies = [ [[package]] name = "perry-ext-sharp" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "fast_image_resize", "image", @@ -6031,14 +6031,14 @@ dependencies = [ [[package]] name = "perry-ext-slugify" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "perry-ffi", ] [[package]] name = "perry-ext-streams" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "lazy_static", "perry-ffi", @@ -6047,7 +6047,7 @@ dependencies = [ [[package]] name = "perry-ext-undici" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "perry-ffi", "perry-runtime", @@ -6056,7 +6056,7 @@ dependencies = [ [[package]] name = "perry-ext-uuid" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "perry-ffi", "uuid", @@ -6064,7 +6064,7 @@ dependencies = [ [[package]] name = "perry-ext-validator" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "perry-ffi", "regex", @@ -6074,7 +6074,7 @@ dependencies = [ [[package]] name = "perry-ext-ws" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "futures-util", "lazy_static", @@ -6087,7 +6087,7 @@ dependencies = [ [[package]] name = "perry-ext-zlib" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "brotli", "flate2", @@ -6097,7 +6097,7 @@ dependencies = [ [[package]] name = "perry-ffi" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "dashmap", "once_cell", @@ -6106,7 +6106,7 @@ dependencies = [ [[package]] name = "perry-hir" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "anyhow", "perry-api-manifest", @@ -6124,7 +6124,7 @@ dependencies = [ [[package]] name = "perry-parser" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "anyhow", "perry-diagnostics", @@ -6136,7 +6136,7 @@ dependencies = [ [[package]] name = "perry-runtime" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "anyhow", "base64", @@ -6177,14 +6177,14 @@ dependencies = [ [[package]] name = "perry-runtime-static" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "perry-runtime", ] [[package]] name = "perry-stdlib" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "aes 0.8.4", "aes 0.9.1", @@ -6279,14 +6279,14 @@ dependencies = [ [[package]] name = "perry-stdlib-static" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "perry-stdlib", ] [[package]] name = "perry-transform" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "anyhow", "perry-hir", @@ -6295,14 +6295,14 @@ dependencies = [ [[package]] name = "perry-ui" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "perry-ui-model", ] [[package]] name = "perry-ui-android" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "base64", "itoa", @@ -6319,7 +6319,7 @@ dependencies = [ [[package]] name = "perry-ui-geisterhand" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "rand 0.10.1", "serde", @@ -6329,7 +6329,7 @@ dependencies = [ [[package]] name = "perry-ui-gtk4" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "base64", "cairo-rs 0.22.0", @@ -6352,7 +6352,7 @@ dependencies = [ [[package]] name = "perry-ui-ios" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "base64", "block2", @@ -6368,7 +6368,7 @@ dependencies = [ [[package]] name = "perry-ui-macos" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "base64", "block2", @@ -6383,7 +6383,7 @@ dependencies = [ [[package]] name = "perry-ui-model" -version = "0.5.1266" +version = "0.5.1265" [[package]] name = "perry-ui-test" @@ -6394,11 +6394,11 @@ dependencies = [ [[package]] name = "perry-ui-testkit" -version = "0.5.1266" +version = "0.5.1265" [[package]] name = "perry-ui-tvos" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "base64", "block2", @@ -6414,7 +6414,7 @@ dependencies = [ [[package]] name = "perry-ui-visionos" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "base64", "block2", @@ -6430,7 +6430,7 @@ dependencies = [ [[package]] name = "perry-ui-watchos" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "block2", "libc", @@ -6443,7 +6443,7 @@ dependencies = [ [[package]] name = "perry-ui-windows" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "base64", "libc", @@ -6460,14 +6460,14 @@ dependencies = [ [[package]] name = "perry-ui-windows-winui" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "perry-ui-windows", ] [[package]] name = "perry-updater" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "anyhow", "base64", @@ -6483,7 +6483,7 @@ dependencies = [ [[package]] name = "perry-wasm-host" -version = "0.5.1266" +version = "0.5.1265" dependencies = [ "wasmi", ] diff --git a/Cargo.toml b/Cargo.toml index 19b4d94ebb..7358b3c628 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -292,7 +292,7 @@ codegen-units = 16 codegen-units = 16 [workspace.package] -version = "0.5.1266" +version = "0.5.1265" edition = "2021" license = "MIT" repository = "https://github.com/PerryTS/perry"