diff --git a/tests/built-ins/Temporal/duration.js b/tests/built-ins/Temporal/duration.js index cb4dd168..3eed2a47 100644 --- a/tests/built-ins/Temporal/duration.js +++ b/tests/built-ins/Temporal/duration.js @@ -109,6 +109,17 @@ describe("Temporal.Duration", () => { expect(d.total("seconds")).toBe(5400); }); + test("total() throws RangeError for durations with years or months", () => { + const withYears = new Temporal.Duration(1); + expect(() => withYears.total("days")).toThrow("RangeError"); + + const withMonths = new Temporal.Duration(0, 3); + expect(() => withMonths.total("days")).toThrow("RangeError"); + + const withBoth = new Temporal.Duration(1, 2, 0, 5); + expect(() => withBoth.total("hours")).toThrow("RangeError"); + }); + test("from() with string", () => { const d = Temporal.Duration.from("P1Y2M3DT4H5M6S"); expect(d.years).toBe(1); diff --git a/units/Goccia.Builtins.Temporal.pas b/units/Goccia.Builtins.Temporal.pas index 06866d40..6b57a2c9 100644 --- a/units/Goccia.Builtins.Temporal.pas +++ b/units/Goccia.Builtins.Temporal.pas @@ -70,6 +70,7 @@ implementation TimingUtils, + Goccia.GarbageCollector, Goccia.Temporal.Utils, Goccia.Values.ErrorHelper, Goccia.Values.ObjectPropertyDescriptor, @@ -87,15 +88,19 @@ constructor TGocciaTemporalBuiltin.Create(const AName: string; const AScope: TGo inherited Create(AName, AScope, AThrowError); FTemporalNamespace := TGocciaObjectValue.Create; - - RegisterDuration; - RegisterInstant; - RegisterPlainDate; - RegisterPlainTime; - RegisterPlainDateTime; - RegisterNow; - - AScope.DefineLexicalBinding(AName, FTemporalNamespace, dtLet); + TGocciaGC.Instance.AddTempRoot(FTemporalNamespace); + try + RegisterDuration; + RegisterInstant; + RegisterPlainDate; + RegisterPlainTime; + RegisterPlainDateTime; + RegisterNow; + + AScope.DefineLexicalBinding(AName, FTemporalNamespace, dtLet); + finally + TGocciaGC.Instance.RemoveTempRoot(FTemporalNamespace); + end; end; { Duration } diff --git a/units/Goccia.Values.TemporalDuration.pas b/units/Goccia.Values.TemporalDuration.pas index 7c1f75be..ff71d45a 100644 --- a/units/Goccia.Values.TemporalDuration.pas +++ b/units/Goccia.Values.TemporalDuration.pas @@ -504,20 +504,28 @@ function TGocciaTemporalDurationValue.DurationTotal(const AArgs: TGocciaArgument var D: TGocciaTemporalDurationValue; UnitStr: string; - Arg: TGocciaValue; + Arg, RelToArg: TGocciaValue; + OptionsObj: TGocciaObjectValue; + HasRelativeTo: Boolean; TotalNs: Double; begin D := AsDuration(AThisValue, 'Duration.prototype.total'); Arg := AArgs.GetElement(0); + HasRelativeTo := False; if Arg is TGocciaStringLiteralValue then UnitStr := TGocciaStringLiteralValue(Arg).Value else if Arg is TGocciaObjectValue then begin - Arg := TGocciaObjectValue(Arg).GetProperty('unit'); + OptionsObj := TGocciaObjectValue(Arg); + + Arg := OptionsObj.GetProperty('unit'); if (Arg = nil) or (Arg is TGocciaUndefinedLiteralValue) then ThrowRangeError('total() requires a unit option'); UnitStr := Arg.ToStringLiteral.Value; + + RelToArg := OptionsObj.GetProperty('relativeTo'); + HasRelativeTo := (RelToArg <> nil) and not (RelToArg is TGocciaUndefinedLiteralValue); end else begin @@ -525,7 +533,14 @@ function TGocciaTemporalDurationValue.DurationTotal(const AArgs: TGocciaArgument UnitStr := ''; end; - // Convert everything to nanoseconds first (ignoring calendar units for simplicity) + if (D.FYears <> 0) or (D.FMonths <> 0) then + begin + if HasRelativeTo then + ThrowRangeError('relativeTo for Duration.prototype.total is not yet supported') + else + ThrowRangeError('Duration with years or months requires relativeTo for total()'); + end; + TotalNs := D.FNanoseconds + D.FMicroseconds * 1000.0 + D.FMilliseconds * 1000000.0 + diff --git a/units/Goccia.Values.TemporalPlainDate.pas b/units/Goccia.Values.TemporalPlainDate.pas index c76d0fb4..82cc0ab1 100644 --- a/units/Goccia.Values.TemporalPlainDate.pas +++ b/units/Goccia.Values.TemporalPlainDate.pas @@ -449,11 +449,16 @@ function TGocciaTemporalPlainDateValue.DateSubtract(const AArgs: TGocciaArgument -Dur.Hours, -Dur.Minutes, -Dur.Seconds, -Dur.Milliseconds, -Dur.Microseconds, -Dur.Nanoseconds); - NewArgs := TGocciaArgumentsCollection.Create([NegatedDur]); + TGocciaGC.Instance.AddTempRoot(NegatedDur); try - Result := DateAdd(NewArgs, AThisValue); + NewArgs := TGocciaArgumentsCollection.Create([NegatedDur]); + try + Result := DateAdd(NewArgs, AThisValue); + finally + NewArgs.Free; + end; finally - NewArgs.Free; + TGocciaGC.Instance.RemoveTempRoot(NegatedDur); end; end;