Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: generic utility for making any class reactive #11504

Open
wants to merge 71 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
f076bbc
a new take on reactivity package
May 7, 2024
72cb168
removed unnecessary as const cast
May 7, 2024
54e33aa
fixed condition of `delete` in ReactiveSet
May 7, 2024
10c8197
better describe what `mutation_properties` does
May 7, 2024
c163ec7
improved types
May 8, 2024
35d9906
improved jsdocs for interceptors
May 8, 2024
6162079
removed map from utils because it wasnt used anymore
May 8, 2024
8da76fa
removed enforcement of defining interceptors since each mutation_prop…
May 8, 2024
6c4a4b6
1- interceptors can be used for anything now (types)
May 8, 2024
81d33e3
renamed signal to version_signal
May 8, 2024
ea91192
added some comments
May 9, 2024
6885f1c
again another take on this matter, but this version is not optimized …
May 9, 2024
3dc711d
added comments to read_methods_signals and version_signal
May 9, 2024
785e51e
fixed a bug where if a method didn't take arguments reactivity wouldn…
May 9, 2024
0df3dcd
fixed test because logging false after clear for 3 is not fine-graine…
May 9, 2024
2177272
initial map support
May 9, 2024
cb8bf44
instead of nested functions used separate function
May 9, 2024
80a73b4
added the ability to notify with all params
May 9, 2024
eaa3fc2
fixed test
May 9, 2024
2ad0a21
used symbol instead of stupid uuid! what was I thinking??
May 10, 2024
1bfdd60
optimized when we create the signals
May 10, 2024
c6c4f46
added tests regarding handling of values not the set/map
May 10, 2024
68dfe79
removed size from read properties because it can depend on version si…
May 11, 2024
b7049d8
removed todo comment
May 12, 2024
5950d47
improved comments
May 17, 2024
9715aa8
notifying other signals of changes, AFTER the change has actually too…
May 18, 2024
d8bc4c7
added fix to work with $inspect rune
May 18, 2024
58b8c10
optimized version signal updates
May 18, 2024
77405de
simplified reactivity for map
May 18, 2024
2d12cba
improved comments and simplified code
May 20, 2024
dc89f8d
ran build which auto updated index.d.ts
May 20, 2024
38a0d5e
fixed linter issue
May 20, 2024
662a48d
made read_properties optional
May 20, 2024
cfc219e
simplify and improve types
May 20, 2024
90531c1
improved utility for reactivity package so if we wanted to we can exp…
May 22, 2024
42bf1e9
changed reactivity/url to use the new utility, also made it fine-grai…
May 22, 2024
7ac79e6
renamed notify_read_methods to notify_read_properties
May 22, 2024
0ccda20
refactored date.js to use the generic make_reactive utility
May 22, 2024
989f429
improved comments
May 22, 2024
0e4239c
added more tests for searchParams
May 22, 2024
12ddf38
removed sending the constructor params to getters!
May 22, 2024
416a68e
made url more fine-grained
May 22, 2024
45025be
fixed where updating the search wouldn't keep the new order of how th…
May 22, 2024
8ddf061
added more tests for url
May 22, 2024
7f3634e
ran build and updated generated index.d.ts
May 22, 2024
82f62e3
fixed copy pasta errors
May 22, 2024
f79784a
added fine-grained test for url
May 22, 2024
ab13b7f
removed searchParams on url from write_properties
May 22, 2024
c9a9881
used version_signal's initial value to determine if it has already ch…
May 22, 2024
376297e
added more tests
May 23, 2024
968d0d6
improved and simplified console.log/debug/etc behavior of Reactive[So…
May 23, 2024
353184c
renamed NOTIFY_WITH_ALL_PARAMS to NOTIFY_WITH_ALL_REGISTERED_PARAMS
May 23, 2024
7f2b7b0
used `//` comments so that internal stuff won't show in the index.d.ts
May 23, 2024
6734775
simplified `get_signal_for_function` and added more tests
May 24, 2024
68b1423
renamed variables and created config so interceptors can be extended …
May 24, 2024
bcd2927
made set and map more fine-grained and improved tests
May 24, 2024
dc80bf3
more streamlined behavior: only returning true will increment the ver…
May 24, 2024
df4ae4d
initial attempt to make date fine-grained
May 24, 2024
b5067af
used the new utility to create a fine-grained ReactiveDate
May 24, 2024
4885739
simplified tmp date creation for notify_datetime_changes
May 24, 2024
045f8a2
added tests for date
May 24, 2024
37fafab
renamed test name
May 24, 2024
2e8225a
fixed url tests
May 24, 2024
11f2508
improved date tests
May 24, 2024
65c0064
added comments describing why we use get_registered_params before not…
May 24, 2024
c48f6ff
improved tests
May 24, 2024
cf2f76f
moved `modified_date_to_compare` out of function to prevent creating …
May 24, 2024
d59a51a
simplified interceptors for date
May 25, 2024
474155b
improved date tests
FoHoOV May 30, 2024
2459461
improved reactivity for search-params
FoHoOV May 30, 2024
d3fd750
fixed url to work with node18
FoHoOV Jun 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
246 changes: 148 additions & 98 deletions packages/svelte/src/reactivity/date.js
Original file line number Diff line number Diff line change
@@ -1,102 +1,152 @@
import { source, set } from '../internal/client/reactivity/sources.js';
import { get } from '../internal/client/runtime.js';

/** @type {Array<keyof Date>} */
const read = [
'getDate',
'getDay',
'getFullYear',
'getHours',
'getMilliseconds',
'getMinutes',
'getMonth',
'getSeconds',
'getTime',
'getTimezoneOffset',
'getUTCDate',
'getUTCDay',
'getUTCFullYear',
'getUTCHours',
'getUTCMilliseconds',
'getUTCMinutes',
'getUTCMonth',
'getUTCSeconds',
// @ts-expect-error this is deprecated
'getYear',
'toDateString',
'toISOString',
'toJSON',
'toLocaleDateString',
'toLocaleString',
'toLocaleTimeString',
'toString',
'toTimeString',
'toUTCString'
];

/** @type {Array<keyof Date>} */
const write = [
'setDate',
'setFullYear',
'setHours',
'setMilliseconds',
'setMinutes',
'setMonth',
'setSeconds',
'setTime',
'setUTCDate',
'setUTCFullYear',
'setUTCHours',
'setUTCMilliseconds',
'setUTCMinutes',
'setUTCMonth',
'setUTCSeconds',
// @ts-expect-error this is deprecated
'setYear'
];

var inited = false;

export class ReactiveDate extends Date {
#raw_time = source(super.getTime());

// We init as part of the first instance so that we can treeshake this class
#init() {
if (!inited) {
inited = true;
const proto = ReactiveDate.prototype;
const date_proto = Date.prototype;

for (const method of read) {
// @ts-ignore
proto[method] = function (...args) {
get(this.#raw_time);
// @ts-ignore
return date_proto[method].apply(this, args);
};
}
import { make_reactive } from './utils.js';

for (const method of write) {
// @ts-ignore
proto[method] = function (...args) {
// @ts-ignore
const v = date_proto[method].apply(this, args);
const time = date_proto.getTime.call(this);
if (time !== this.#raw_time.v) {
set(this.#raw_time, time);
}
return v;
};
}
}
const modified_date_to_compare = new Date();
/**
* we have to create a new Date to compare, because setting `X` might or might not affect `Y`
* for instance calling `date.setMonth(55)` will also change the `date.getYear()`
* but calling `date.setMonth(1)` (assuming its not 12) will not increase the year.
* we could check all of these edge-cases but I think that might become complicated very soon and introduce more bugs
* also there is the possibility of these behaviors to change as well,
* so creating a new date and applying the change is a better idea I guess
* @param {import("./utils.js").InterceptorOptions<Date, (keyof Date)[], (keyof Date)[]>} options
* @param {unknown[]} params
* @return {boolean} - returns true if any changes happened
*/
const notify_datetime_changes = (options, ...params) => {
modified_date_to_compare.setTime(options.value.getTime());

let is_time_changed = false;
let is_date_changed = false;

// @ts-ignore
modified_date_to_compare[options.property](...params);

if (options.value.getFullYear() !== modified_date_to_compare.getFullYear()) {
options.notify_read_properties(['getFullYear', 'getUTCFullYear']);
is_date_changed = true;
}

// @ts-expect-error
if (options.value.getYear && options.value.getYear() !== modified_date_to_compare.getYear()) {
// @ts-expect-error
options.notify_read_properties(['getYear']);
is_date_changed = true;
}

/**
* @param {any[]} values
*/
constructor(...values) {
// @ts-ignore
super(...values);
this.#init();
if (options.value.getMonth() !== modified_date_to_compare.getMonth()) {
options.notify_read_properties(['getMonth', 'getUTCMonth']);
is_date_changed = true;
}

if (options.value.getDate() !== modified_date_to_compare.getDate()) {
options.notify_read_properties(['getDate', 'getUTCDate']);
is_date_changed = true;
}

if (options.value.getDay() !== modified_date_to_compare.getDay()) {
options.notify_read_properties(['getDay', 'getUTCDay']);
is_date_changed = true;
}

if (options.value.getHours() !== modified_date_to_compare.getHours()) {
options.notify_read_properties(['getHours', 'getUTCHours']);
is_time_changed = true;
}

if (options.value.getMinutes() !== modified_date_to_compare.getMinutes()) {
options.notify_read_properties(['getMinutes', 'getUTCMinutes']);
is_time_changed = true;
}

if (options.value.getSeconds() !== modified_date_to_compare.getSeconds()) {
options.notify_read_properties(['getSeconds', 'getUTCSeconds']);
is_time_changed = true;
}

if (options.value.getMilliseconds() !== modified_date_to_compare.getMilliseconds()) {
options.notify_read_properties(['getMilliseconds', 'getUTCMilliseconds']);
is_time_changed = true;
}

if (is_time_changed) {
options.notify_read_properties(['toTimeString', 'toLocaleTimeString']);
}

if (is_date_changed) {
options.notify_read_properties(['toDateString', 'toLocaleDateString']);
}

return is_date_changed || is_time_changed;
};

export const ReactiveDate = make_reactive(Date, {
write_properties: [
'setDate',
'setFullYear',
'setHours',
'setMilliseconds',
'setMinutes',
'setMonth',
'setSeconds',
'setTime',
'setUTCDate',
'setUTCFullYear',
'setUTCHours',
'setUTCMilliseconds',
'setUTCMinutes',
'setUTCMonth',
'setUTCSeconds',
// @ts-expect-error this is deprecated
'setYear'
],
read_properties: [
'getDate',
'getDay',
'getFullYear',
'getHours',
'getMilliseconds',
'getMinutes',
'getMonth',
'getSeconds',
'getTimezoneOffset',
'getUTCDate',
'getUTCDay',
'getUTCFullYear',
'getUTCHours',
'getUTCMilliseconds',
'getUTCMinutes',
'getUTCMonth',
'getUTCSeconds',
// @ts-expect-error this is deprecated
'getYear',
'toDateString',
'toLocaleDateString',
'toTimeString',
'toLocaleTimeString'
],
interceptors: {
setDate: (options, ...params) => notify_datetime_changes(options, ...params),
setFullYear: (options, ...params) => notify_datetime_changes(options, ...params),
setHours: (options, ...params) => notify_datetime_changes(options, ...params),
setMilliseconds: (options, ...params) => notify_datetime_changes(options, ...params),
setMinutes: (options, ...params) => notify_datetime_changes(options, ...params),
setMonth: (options, ...params) => notify_datetime_changes(options, ...params),
setSeconds: (options, ...params) => notify_datetime_changes(options, ...params),
setTime: (options, ...params) => notify_datetime_changes(options, ...params),
setUTCDate: (options, ...params) => notify_datetime_changes(options, ...params),
setUTCFullYear: (options, ...params) => notify_datetime_changes(options, ...params),
setUTCHours: (options, ...params) => notify_datetime_changes(options, ...params),
setUTCMilliseconds: (options, ...params) => notify_datetime_changes(options, ...params),
setUTCMinutes: (options, ...params) => notify_datetime_changes(options, ...params),
setUTCMonth: (options, ...params) => notify_datetime_changes(options, ...params),
setUTCSeconds: (options, ...params) => notify_datetime_changes(options, ...params),
// @ts-expect-error - deprecated method
setYear: (options, ...params) => {
// it might be removed from browsers
if (!options.value.getYear) {
return false;
}
return notify_datetime_changes(options, ...params);
}
}
}
});