Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/lazy-knives-write.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@qwik.dev/core': minor
---

feat: add `Temporal` serialization support
16 changes: 16 additions & 0 deletions packages/qwik/src/core/shared/serdes/allocate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,22 @@ export const allocate = (container: DeserializeContainer, typeId: number, value:
return new URL(value as string);
case TypeIds.Date:
return new Date(value as number);
case TypeIds.TemporalDuration:
return Temporal.Duration.from(value as string);
case TypeIds.TemporalInstant:
return Temporal.Instant.from(value as string);
case TypeIds.TemporalPlainDate:
return Temporal.PlainDate.from(value as string);
case TypeIds.TemporalPlainDateTime:
return Temporal.PlainDateTime.from(value as string);
case TypeIds.TemporalPlainMonthDay:
return Temporal.PlainMonthDay.from(value as string);
case TypeIds.TemporalPlainTime:
return Temporal.PlainTime.from(value as string);
case TypeIds.TemporalPlainYearMonth:
return Temporal.PlainYearMonth.from(value as string);
case TypeIds.TemporalZonedDateTime:
return Temporal.ZonedDateTime.from(value as string);
case TypeIds.Regex:
const idx = (value as string).lastIndexOf('/');
return new RegExp((value as string).slice(1, idx), (value as string).slice(idx + 1));
Expand Down
16 changes: 16 additions & 0 deletions packages/qwik/src/core/shared/serdes/can-serialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,22 @@ export const canSerialize = (value: unknown, seen: WeakSet<any> = new WeakSet())
return true;
} else if (value instanceof Date) {
return true;
} else if (typeof Temporal !== 'undefined' && value instanceof Temporal.Duration) {
return true;
} else if (typeof Temporal !== 'undefined' && value instanceof Temporal.Instant) {
return true;
} else if (typeof Temporal !== 'undefined' && value instanceof Temporal.PlainDate) {
return true;
} else if (typeof Temporal !== 'undefined' && value instanceof Temporal.PlainDateTime) {
return true;
} else if (typeof Temporal !== 'undefined' && value instanceof Temporal.PlainMonthDay) {
return true;
} else if (typeof Temporal !== 'undefined' && value instanceof Temporal.PlainTime) {
return true;
} else if (typeof Temporal !== 'undefined' && value instanceof Temporal.PlainYearMonth) {
return true;
} else if (typeof Temporal !== 'undefined' && value instanceof Temporal.ZonedDateTime) {
return true;
} else if (value instanceof RegExp) {
return true;
} else if (value instanceof URLSearchParams) {
Expand Down
16 changes: 16 additions & 0 deletions packages/qwik/src/core/shared/serdes/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,14 @@ export const enum TypeIds {
BigInt,
URLSearchParams,
ForwardRefs,
TemporalDuration,
TemporalInstant,
TemporalPlainDate,
TemporalPlainDateTime,
TemporalPlainMonthDay,
TemporalPlainTime,
TemporalPlainYearMonth,
TemporalZonedDateTime,
/// All types below will be inflate()d
Error,
Promise,
Expand Down Expand Up @@ -127,6 +135,14 @@ export const _typeIdNames = [
'BigInt',
'URLSearchParams',
'ForwardRefs',
'TemporalDuration',
'TemporalInstant',
'TemporalPlainDate',
'TemporalPlainDateTime',
'TemporalPlainMonthDay',
'TemporalPlainTime',
'TemporalPlainYearMonth',
'TemporalZonedDateTime',
'Error',
'Promise',
'Set',
Expand Down
83 changes: 83 additions & 0 deletions packages/qwik/src/core/shared/serdes/serdes.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,63 @@ describe('shared-serialization', () => {
(6 chars)"
`);
});
it.skipIf(typeof Temporal === 'undefined')(title(TypeIds.TemporalDuration), async () => {
expect(await dump(Temporal.Duration.from('PT194972H22M2.783S'))).toMatchInlineSnapshot(`
"
0 TemporalDuration "PT194972H22M2.783S"
(25 chars)"
`);
});
it.skipIf(typeof Temporal === 'undefined')(title(TypeIds.TemporalInstant), async () => {
expect(await dump(Temporal.Instant.from('2003-12-29T00:00:00Z'))).toMatchInlineSnapshot(`
"
0 TemporalInstant "2003-12-29T00:00:00Z"
(27 chars)"
`);
});
it.skipIf(typeof Temporal === 'undefined')(title(TypeIds.TemporalPlainDate), async () => {
expect(await dump(Temporal.PlainDate.from('2003-12-29'))).toMatchInlineSnapshot(`
"
0 TemporalPlainDate "2003-12-29"
(17 chars)"
`);
});
it.skipIf(typeof Temporal === 'undefined')(title(TypeIds.TemporalPlainDateTime), async () => {
expect(await dump(Temporal.PlainDateTime.from('2003-12-29T04:20:00'))).toMatchInlineSnapshot(`
"
0 TemporalPlainDateTime "2003-12-29T04:20:00"
(26 chars)"
`);
});
it.skipIf(typeof Temporal === 'undefined')(title(TypeIds.TemporalPlainMonthDay), async () => {
expect(await dump(Temporal.PlainMonthDay.from('12-29'))).toMatchInlineSnapshot(`
"
0 TemporalPlainMonthDay "12-29"
(12 chars)"
`);
});
it.skipIf(typeof Temporal === 'undefined')(title(TypeIds.TemporalPlainTime), async () => {
expect(await dump(Temporal.PlainTime.from('04:20:00'))).toMatchInlineSnapshot(`
"
0 TemporalPlainTime "04:20:00"
(15 chars)"
`);
});
it.skipIf(typeof Temporal === 'undefined')(title(TypeIds.TemporalPlainYearMonth), async () => {
expect(await dump(Temporal.PlainYearMonth.from('2003-12'))).toMatchInlineSnapshot(`
"
0 TemporalPlainYearMonth "2003-12"
(14 chars)"
`);
});
it.skipIf(typeof Temporal === 'undefined')(title(TypeIds.TemporalZonedDateTime), async () => {
expect(await dump(Temporal.ZonedDateTime.from('2003-12-29T04:20:00+01:00[Europe/Berlin]')))
.toMatchInlineSnapshot(`
"
0 TemporalZonedDateTime "2003-12-29T04:20:00+01:00[Europe/Berlin]"
(47 chars)"
`);
});
it(title(TypeIds.Regex), async () => {
expect(await dump(/abc/gm)).toMatchInlineSnapshot(`
"
Expand Down Expand Up @@ -953,6 +1010,32 @@ describe('shared-serialization', () => {
expect(date).toBeInstanceOf(Date);
expect(date.toISOString()).toBe('2009-02-13T23:31:30.000Z');
});
const testTemporal = (id: TypeIds, T_: () => typeof __TemporalStub<unknown>, value: string) => {
it.skipIf(typeof Temporal === 'undefined')(title(id), async () => {
const T = T_();
const original = T.from(value);
const objs = await serialize(original);
const deserialized = deserialize(objs)[0];
expect(deserialized).toBeInstanceOf(T);
expect(original).toEqual(deserialized);
});
};
testTemporal(TypeIds.TemporalDuration, () => Temporal.Duration, 'PT194972H22M2.783S');
testTemporal(TypeIds.TemporalInstant, () => Temporal.Instant, '2003-12-29T00:00:00Z');
testTemporal(TypeIds.TemporalPlainDate, () => Temporal.PlainDate, '2003-12-29');
testTemporal(
TypeIds.TemporalPlainDateTime,
() => Temporal.PlainDateTime,
'2003-12-29T04:20:00'
);
testTemporal(TypeIds.TemporalPlainMonthDay, () => Temporal.PlainMonthDay, '12-29');
testTemporal(TypeIds.TemporalPlainTime, () => Temporal.PlainTime, '04:20:00');
testTemporal(TypeIds.TemporalPlainYearMonth, () => Temporal.PlainYearMonth, '2003-12');
testTemporal(
TypeIds.TemporalZonedDateTime,
() => Temporal.ZonedDateTime,
'2003-12-29T04:20:00+01:00[Europe/Berlin]'
);
it(title(TypeIds.Regex), async () => {
const objs = await serialize(/abc/gm);
const regex = deserialize(objs)[0] as RegExp;
Expand Down
17 changes: 17 additions & 0 deletions packages/qwik/src/core/shared/serdes/serialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export class Serializer {
private $parent$: SeenRef | undefined;
private $qrlMap$ = new Map<string, QRLInternal>();
private $writer$: StreamWriter;
private $temporalDefined$: boolean = typeof Temporal !== 'undefined';

constructor(public $serializationContext$: SerializationContext) {
this.$writer$ = $serializationContext$.$writer$;
Expand Down Expand Up @@ -486,6 +487,22 @@ export class Serializer {
this.output(TypeIds.URL, value.href);
} else if (value instanceof Date) {
this.output(TypeIds.Date, Number.isNaN(value.valueOf()) ? '' : value.valueOf());
} else if (this.$temporalDefined$ && value instanceof Temporal.Duration) {
this.output(TypeIds.TemporalDuration, value.toJSON());
} else if (this.$temporalDefined$ && value instanceof Temporal.Instant) {
this.output(TypeIds.TemporalInstant, value.toJSON());
} else if (this.$temporalDefined$ && value instanceof Temporal.PlainDate) {
this.output(TypeIds.TemporalPlainDate, value.toJSON());
} else if (this.$temporalDefined$ && value instanceof Temporal.PlainDateTime) {
this.output(TypeIds.TemporalPlainDateTime, value.toJSON());
} else if (this.$temporalDefined$ && value instanceof Temporal.PlainMonthDay) {
this.output(TypeIds.TemporalPlainMonthDay, value.toJSON());
} else if (this.$temporalDefined$ && value instanceof Temporal.PlainTime) {
this.output(TypeIds.TemporalPlainTime, value.toJSON());
} else if (this.$temporalDefined$ && value instanceof Temporal.PlainYearMonth) {
this.output(TypeIds.TemporalPlainYearMonth, value.toJSON());
} else if (this.$temporalDefined$ && value instanceof Temporal.ZonedDateTime) {
this.output(TypeIds.TemporalZonedDateTime, value.toJSON());
} else if (value instanceof RegExp) {
this.output(TypeIds.Regex, value.toString());
} else if (value instanceof Error) {
Expand Down
17 changes: 17 additions & 0 deletions packages/qwik/src/core/shared/serdes/type-stub.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/** Minimal type-stub for the types in `Temporal`. Contains methods required for (de-)serializing. */
declare class __TemporalStub<T> {
static from(item: string): T;
toJSON(): string;
}

/** Type-Stub for the types in `Temporal` */
declare namespace Temporal {
class Duration extends __TemporalStub<Duration> {}
class Instant extends __TemporalStub<Instant> {}
class PlainDate extends __TemporalStub<PlainDate> {}
class PlainDateTime extends __TemporalStub<PlainDateTime> {}
class PlainMonthDay extends __TemporalStub<PlainMonthDay> {}
class PlainTime extends __TemporalStub<PlainTime> {}
class PlainYearMonth extends __TemporalStub<PlainTime> {}
class ZonedDateTime extends __TemporalStub<ZonedDateTime> {}
}