mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 02:31:13 +08:00
feat: Duration 构造器逐字段强转与负零归一
This commit is contained in:
Generated
+21
-21
@@ -1160,7 +1160,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_builtins"
|
||||
version = "0.19.19"
|
||||
version = "0.19.20"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"fast-float",
|
||||
@@ -1185,7 +1185,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_bytecode"
|
||||
version = "0.19.19"
|
||||
version = "0.19.20"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxide_log",
|
||||
@@ -1193,7 +1193,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cfg"
|
||||
version = "0.19.19"
|
||||
version = "0.19.20"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_emit",
|
||||
@@ -1204,7 +1204,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cli"
|
||||
version = "0.19.19"
|
||||
version = "0.19.20"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"bumpalo",
|
||||
@@ -1228,7 +1228,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_code_cache"
|
||||
version = "0.19.19"
|
||||
version = "0.19.20"
|
||||
dependencies = [
|
||||
"lru",
|
||||
"oxide_bytecode",
|
||||
@@ -1237,7 +1237,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_compiler"
|
||||
version = "0.19.19"
|
||||
version = "0.19.20"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1258,7 +1258,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_dce"
|
||||
version = "0.19.19"
|
||||
version = "0.19.20"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1272,7 +1272,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_emit"
|
||||
version = "0.19.19"
|
||||
version = "0.19.20"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxc_allocator",
|
||||
@@ -1288,7 +1288,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_engine"
|
||||
version = "0.19.19"
|
||||
version = "0.19.20"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1300,7 +1300,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_fold"
|
||||
version = "0.19.19"
|
||||
version = "0.19.20"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxide_bytecode",
|
||||
@@ -1312,7 +1312,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_ir"
|
||||
version = "0.19.19"
|
||||
version = "0.19.20"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_log",
|
||||
@@ -1321,7 +1321,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_kernel"
|
||||
version = "0.19.19"
|
||||
version = "0.19.20"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1335,7 +1335,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_liveness"
|
||||
version = "0.19.19"
|
||||
version = "0.19.20"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1347,7 +1347,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_log"
|
||||
version = "0.19.19"
|
||||
version = "0.19.20"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
"tracing-appender",
|
||||
@@ -1356,11 +1356,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_net"
|
||||
version = "0.19.19"
|
||||
version = "0.19.20"
|
||||
|
||||
[[package]]
|
||||
name = "oxide_parser"
|
||||
version = "0.19.19"
|
||||
version = "0.19.20"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast",
|
||||
@@ -1375,7 +1375,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_regalloc"
|
||||
version = "0.19.19"
|
||||
version = "0.19.20"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1391,7 +1391,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_runtime_api"
|
||||
version = "0.19.19"
|
||||
version = "0.19.20"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
@@ -1404,7 +1404,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_test262"
|
||||
version = "0.19.19"
|
||||
version = "0.19.20"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1424,7 +1424,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_types"
|
||||
version = "0.19.19"
|
||||
version = "0.19.20"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1437,7 +1437,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_vm"
|
||||
version = "0.19.19"
|
||||
version = "0.19.20"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"chrono",
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.19.19"
|
||||
version = "0.19.20"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
rust-version = "1.80"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Temporal.Duration:ISO 字符串与 property bag 解析、构造、getter、total/round、
|
||||
//! 加减比较与格式化。
|
||||
|
||||
use oxide_runtime_api::{to_number, to_string, NativeResult, ProtoKind, VmHost};
|
||||
use oxide_runtime_api::{to_number, to_number_full, to_string, NativeResult, ProtoKind, VmHost};
|
||||
use oxide_types::object::JsObject;
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
@@ -264,6 +264,18 @@ pub(crate) fn duration_like_values<H: VmHost>(vm: &mut H, val: JsValue) -> Resul
|
||||
}
|
||||
|
||||
/// `Temporal.Duration` 构造器,保存十个整数时长分量。
|
||||
///
|
||||
/// # 步骤
|
||||
/// 1. 校验构造调用(非 `new` 形态抛 TypeError)。
|
||||
/// 2. 按年、月、周、日、时、分、秒、毫秒、微秒、纳秒顺序逐字段转换:
|
||||
/// undefined 视为 0;BigInt 抛 TypeError;其余经完整 ToNumber
|
||||
/// (对象走 valueOf 路径,Symbol 抛 TypeError);NaN、非整数、
|
||||
/// 非有限值抛 RangeError。
|
||||
/// 3. 共享校验器做符号一致性与范围检查。
|
||||
///
|
||||
/// # 注意事项
|
||||
/// 零分量归一为 +0:规范经整数往返(取整再还原为 Number),
|
||||
/// 传入 −0 时 getter 仍返回 +0。
|
||||
pub fn duration_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let ctor_proto = vm.builtin_proto(ProtoKind::DurationProto);
|
||||
if !is_ctor_call(vm, args, ctor_proto) {
|
||||
@@ -277,11 +289,22 @@ pub fn duration_constructor<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
|
||||
if args.len() <= index + 1 {
|
||||
continue;
|
||||
}
|
||||
let number = to_number(vm.reg(args[index + 1]));
|
||||
let arg = vm.reg(args[index + 1]);
|
||||
if arg.is_undefined() {
|
||||
continue;
|
||||
}
|
||||
if arg.is_bigint() {
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, "cannot convert duration field to number"));
|
||||
}
|
||||
let number = match to_number_full(arg, vm) {
|
||||
Ok(value) => value,
|
||||
Err(error) => return NativeResult::Err(native_engine_error(vm, &error)),
|
||||
};
|
||||
if !number.is_finite() || number.fract() != 0.0 {
|
||||
return NativeResult::Err(crate::error::create_range_error(vm, "invalid duration"));
|
||||
}
|
||||
*value = number;
|
||||
// 零分量归一为 +0:规范整数往返(取整再还原 Number)使 −0 落为 +0。
|
||||
*value = if number == 0.0 { 0.0 } else { number };
|
||||
}
|
||||
native_try!(validate_duration_values(vm, &values));
|
||||
initialize_temporal_receiver(vm, args, JsObject::OBJ_TYPE_DURATION, values.map(JsValue::float))
|
||||
|
||||
@@ -574,6 +574,32 @@ fn duration_constructor_exposes_components() {
|
||||
assert_eq!(str_val(&vm, r), "P1Y2M3W4D");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duration_constructor_coerces_fields_per_spec() {
|
||||
let mut vm = Vm::new();
|
||||
// undefined 分量视为 0
|
||||
let r = eval(&mut vm, "new Temporal.Duration(undefined).toString()").unwrap();
|
||||
assert_eq!(str_val(&vm, r), "PT0S");
|
||||
let r = eval(&mut vm, "new Temporal.Duration(1, undefined).toString()").unwrap();
|
||||
assert_eq!(str_val(&vm, r), "P1Y");
|
||||
// Symbol 与 BigInt 抛 TypeError
|
||||
let r = eval(&mut vm, "try { new Temporal.Duration(Symbol()) } catch (e) { e.constructor.name }").unwrap();
|
||||
assert_eq!(str_val(&vm, r), "TypeError");
|
||||
let r = eval(&mut vm, "try { new Temporal.Duration(0n) } catch (e) { e.constructor.name }").unwrap();
|
||||
assert_eq!(str_val(&vm, r), "TypeError");
|
||||
// 对象经 valueOf 转换
|
||||
assert_eq!(num(&mut vm, "new Temporal.Duration({valueOf(){return 1}}).years"), 1.0);
|
||||
// ±Infinity 抛 RangeError
|
||||
let r = eval(&mut vm, "try { new Temporal.Duration(Infinity) } catch (e) { e.constructor.name }").unwrap();
|
||||
assert_eq!(str_val(&vm, r), "RangeError");
|
||||
let r = eval(&mut vm, "try { new Temporal.Duration(-Infinity) } catch (e) { e.constructor.name }").unwrap();
|
||||
assert_eq!(str_val(&vm, r), "RangeError");
|
||||
// 传入 −0 时 getter 返回 +0(整数往返归一)
|
||||
assert!(eval(&mut vm, "Object.is(new Temporal.Duration(-0).years, 0)")
|
||||
.unwrap()
|
||||
.as_bool());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duration_from_validates_property_bags_and_preserves_precision() {
|
||||
let mut vm = Vm::new();
|
||||
|
||||
Reference in New Issue
Block a user