mirror of https://github.com/sveltejs/svelte
parent
853d28efe5
commit
ab837f24b2
@ -1,145 +1,234 @@
|
|||||||
import { make_reactive } from './utils.js';
|
import { make_reactive } from './utils.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {(keyof 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 {Date} current_datetime
|
||||||
|
* @param {Date} new_datetime
|
||||||
|
* @param {import("./utils.js").InterceptorOptions<Date, (keyof Date)[], (keyof Date)[]>["notify_read_properties"]} notify_read_properties
|
||||||
|
* @return {boolean} - returns true if any changes happened
|
||||||
*/
|
*/
|
||||||
const write_properties = /** @type {const} */ ([
|
const notify_datetime_changes = (current_datetime, new_datetime, notify_read_properties) => {
|
||||||
'setDate',
|
let had_time_changes = false;
|
||||||
'setFullYear',
|
let had_date_changes = false;
|
||||||
'setHours',
|
|
||||||
'setMilliseconds',
|
|
||||||
'setMinutes',
|
|
||||||
'setMonth',
|
|
||||||
'setSeconds',
|
|
||||||
'setTime',
|
|
||||||
'setUTCDate',
|
|
||||||
'setUTCFullYear',
|
|
||||||
'setUTCHours',
|
|
||||||
'setUTCMilliseconds',
|
|
||||||
'setUTCMinutes',
|
|
||||||
'setUTCMonth',
|
|
||||||
'setUTCSeconds',
|
|
||||||
// @ts-expect-error this is deprecated
|
|
||||||
'setYear'
|
|
||||||
]);
|
|
||||||
|
|
||||||
/**
|
if (current_datetime.getFullYear() !== new_datetime.getFullYear()) {
|
||||||
* @type {(keyof Date)[]}
|
notify_read_properties(['getFullYear', 'getUTCFullYear']);
|
||||||
*/
|
had_date_changes = true;
|
||||||
const read_properties = /** @type {const} */ ([
|
}
|
||||||
'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',
|
|
||||||
'toLocaleTimeString',
|
|
||||||
'toTimeString'
|
|
||||||
]);
|
|
||||||
|
|
||||||
/**
|
// @ts-expect-error
|
||||||
* @type {Record<(typeof write_properties)[number], (typeof read_properties)[number][]>}
|
if (current_datetime.getYear && current_datetime.getYear() !== new_datetime.getYear()) {
|
||||||
*/
|
// @ts-expect-error
|
||||||
const affected_changes = {
|
notify_read_properties(['getYear']);
|
||||||
setDate: ['getDate', 'getUTCDate', 'toDateString', 'toLocaleDateString'],
|
had_date_changes = true;
|
||||||
setFullYear: [
|
}
|
||||||
'getFullYear',
|
|
||||||
'getUTCFullYear',
|
if (current_datetime.getMonth() !== new_datetime.getMonth()) {
|
||||||
'getDate',
|
notify_read_properties(['getMonth', 'getUTCMonth']);
|
||||||
'getUTCDate',
|
had_date_changes = true;
|
||||||
'toDateString',
|
}
|
||||||
'toLocaleDateString'
|
|
||||||
],
|
if (current_datetime.getDay() !== new_datetime.getDay()) {
|
||||||
setHours: ['getHours', 'getUTCHours', 'toTimeString', 'toLocaleTimeString'],
|
notify_read_properties(['getDay', 'getUTCDay']);
|
||||||
setMilliseconds: ['getMilliseconds', 'getUTCMilliseconds', 'toTimeString', 'toLocaleTimeString'],
|
had_date_changes = true;
|
||||||
setMinutes: [
|
}
|
||||||
'getMinutes',
|
|
||||||
'getUTCMinutes',
|
if (current_datetime.getHours() !== new_datetime.getHours()) {
|
||||||
'getHours',
|
notify_read_properties(['getHours', 'getUTCHours']);
|
||||||
'getUTCHours',
|
had_time_changes = true;
|
||||||
'toTimeString',
|
}
|
||||||
'toLocaleTimeString'
|
|
||||||
|
if (current_datetime.getMinutes() !== new_datetime.getMinutes()) {
|
||||||
|
notify_read_properties(['getMinutes', 'getUTCMinutes']);
|
||||||
|
had_time_changes = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_datetime.getSeconds() !== new_datetime.getSeconds()) {
|
||||||
|
notify_read_properties(['getSeconds', 'getUTCSeconds']);
|
||||||
|
had_time_changes = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_datetime.getMilliseconds() !== new_datetime.getMilliseconds()) {
|
||||||
|
notify_read_properties(['getMilliseconds', 'getUTCMilliseconds']);
|
||||||
|
had_time_changes = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (had_time_changes) {
|
||||||
|
notify_read_properties(['toTimeString', 'toLocaleTimeString']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (had_date_changes) {
|
||||||
|
notify_read_properties(['toDateString', 'toLocaleDateString']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return had_date_changes || had_time_changes;
|
||||||
|
};
|
||||||
|
|
||||||
|
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'
|
||||||
],
|
],
|
||||||
setMonth: [
|
read_properties: [
|
||||||
'getMonth',
|
|
||||||
'getUTCMonth',
|
|
||||||
'getDate',
|
'getDate',
|
||||||
'getUTCDate',
|
'getDay',
|
||||||
'toDateString',
|
|
||||||
'toLocaleDateString'
|
|
||||||
],
|
|
||||||
setSeconds: ['getSeconds', 'getUTCSeconds', 'toTimeString', 'toLocaleTimeString'],
|
|
||||||
setTime: [
|
|
||||||
'toDateString',
|
|
||||||
'toTimeString',
|
|
||||||
'toLocaleDateString',
|
|
||||||
'toLocaleTimeString',
|
|
||||||
'getFullYear',
|
'getFullYear',
|
||||||
'getMonth',
|
|
||||||
'getDate',
|
|
||||||
'getHours',
|
'getHours',
|
||||||
|
'getMilliseconds',
|
||||||
'getMinutes',
|
'getMinutes',
|
||||||
|
'getMonth',
|
||||||
'getSeconds',
|
'getSeconds',
|
||||||
'getMilliseconds',
|
'getTimezoneOffset',
|
||||||
'getUTCFullYear',
|
|
||||||
'getUTCMonth',
|
|
||||||
'getUTCDate',
|
'getUTCDate',
|
||||||
|
'getUTCDay',
|
||||||
|
'getUTCFullYear',
|
||||||
'getUTCHours',
|
'getUTCHours',
|
||||||
|
'getUTCMilliseconds',
|
||||||
'getUTCMinutes',
|
'getUTCMinutes',
|
||||||
|
'getUTCMonth',
|
||||||
'getUTCSeconds',
|
'getUTCSeconds',
|
||||||
'getUTCMilliseconds'
|
// @ts-expect-error this is deprecated
|
||||||
|
'getYear',
|
||||||
|
'toDateString',
|
||||||
|
'toLocaleDateString',
|
||||||
|
'toTimeString',
|
||||||
|
'toLocaleTimeString'
|
||||||
],
|
],
|
||||||
setUTCDate: ['getUTCDate', 'getDate'],
|
|
||||||
setUTCFullYear: ['getUTCFullYear', 'getFullYear', 'getUTCDate', 'getDate'],
|
|
||||||
setUTCHours: ['getUTCHours', 'getHours'],
|
|
||||||
setUTCMilliseconds: ['getUTCMilliseconds', 'getMilliseconds'],
|
|
||||||
setUTCMinutes: ['getUTCMinutes', 'getMinutes', 'getUTCHours', 'getHours'],
|
|
||||||
setUTCMonth: ['getUTCMonth', 'getMonth', 'getUTCDate', 'getDate'],
|
|
||||||
setUTCSeconds: ['getUTCSeconds', 'getSeconds'],
|
|
||||||
// @ts-expect-error
|
|
||||||
setYear: ['getYear', 'getFullYear', 'toDateString']
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {import("./utils.js").Interceptors<InstanceType<Date>, typeof write_properties, typeof read_properties>} ReactiveDateInterceptor
|
|
||||||
*/
|
|
||||||
|
|
||||||
export const ReactiveDate = make_reactive(Date, {
|
|
||||||
write_properties: write_properties,
|
|
||||||
read_properties: read_properties,
|
|
||||||
// @ts-expect-error - because of `setYear` which deprecated all types are screwed so have to compromise
|
|
||||||
interceptors: {
|
interceptors: {
|
||||||
...write_properties.map((write_property) => {
|
setDate: (options, ...params) => {
|
||||||
return /** @type {import("./utils.js").Interceptors<InstanceType<Date>, typeof write_properties, typeof read_properties>} */ ({
|
const tmp = new Date(options.value);
|
||||||
/**
|
tmp.setDate(/**@type {number}*/ (params[0]));
|
||||||
* @param {import("./utils.js").InterceptorOptions<InstanceType<Date>, typeof write_properties, typeof read_properties>} options
|
return notify_datetime_changes(options.value, tmp, options.notify_read_properties);
|
||||||
* @param {unknown[]} params
|
},
|
||||||
**/
|
setFullYear: (options, ...params) => {
|
||||||
[write_property]: (options, ...params) => {
|
const tmp = new Date(options.value);
|
||||||
if (options.value[write_property]() === params[0]) {
|
tmp.setFullYear(
|
||||||
return false;
|
/**@type {number}*/ (params[0]),
|
||||||
}
|
/**@type {number | undefined}*/ (params[1]),
|
||||||
affected_changes[write_property].forEach((affected) => {
|
/**@type {number | undefined}*/ (params[2])
|
||||||
options.notify_read_properties([affected]);
|
);
|
||||||
});
|
return notify_datetime_changes(options.value, tmp, options.notify_read_properties);
|
||||||
return true;
|
},
|
||||||
}
|
setHours: (options, ...params) => {
|
||||||
});
|
const tmp = new Date(options.value);
|
||||||
})
|
tmp.setHours(
|
||||||
|
/**@type {number}*/ (params[0]),
|
||||||
|
/**@type {number | undefined}*/ (params[1]),
|
||||||
|
/**@type {number | undefined}*/ (params[2]),
|
||||||
|
/**@type {number | undefined}*/ (params[3])
|
||||||
|
);
|
||||||
|
return notify_datetime_changes(options.value, tmp, options.notify_read_properties);
|
||||||
|
},
|
||||||
|
setMilliseconds: (options, ...params) => {
|
||||||
|
const tmp = new Date(options.value);
|
||||||
|
tmp.setMilliseconds(/**@type {number}*/ (params[0]));
|
||||||
|
return notify_datetime_changes(options.value, tmp, options.notify_read_properties);
|
||||||
|
},
|
||||||
|
setMinutes: (options, ...params) => {
|
||||||
|
const tmp = new Date(options.value);
|
||||||
|
tmp.setMinutes(
|
||||||
|
/**@type {number}*/ (params[0]),
|
||||||
|
/**@type {number | undefined}*/ (params[1]),
|
||||||
|
/**@type {number | undefined}*/ (params[2])
|
||||||
|
);
|
||||||
|
return notify_datetime_changes(options.value, tmp, options.notify_read_properties);
|
||||||
|
},
|
||||||
|
setMonth: (options, ...params) => {
|
||||||
|
const tmp = new Date(options.value);
|
||||||
|
tmp.setMonth(/**@type {number}*/ (params[0]), /**@type {number | undefined}*/ (params[1]));
|
||||||
|
return notify_datetime_changes(options.value, tmp, options.notify_read_properties);
|
||||||
|
},
|
||||||
|
setSeconds: (options, ...params) => {
|
||||||
|
const tmp = new Date(options.value);
|
||||||
|
tmp.setSeconds(/**@type {number}*/ (params[0]), /**@type {number | undefined}*/ (params[1]));
|
||||||
|
return notify_datetime_changes(options.value, tmp, options.notify_read_properties);
|
||||||
|
},
|
||||||
|
setTime: (options, ...params) => {
|
||||||
|
const tmp = new Date(options.value);
|
||||||
|
tmp.setTime(/**@type {number}*/ (params[0]));
|
||||||
|
return notify_datetime_changes(options.value, tmp, options.notify_read_properties);
|
||||||
|
},
|
||||||
|
setUTCDate: (options, ...params) => {
|
||||||
|
const tmp = new Date(options.value);
|
||||||
|
tmp.setUTCDate(/**@type {number}*/ (params[0]));
|
||||||
|
return notify_datetime_changes(options.value, tmp, options.notify_read_properties);
|
||||||
|
},
|
||||||
|
setUTCFullYear: (options, ...params) => {
|
||||||
|
const tmp = new Date(options.value);
|
||||||
|
tmp.setUTCFullYear(
|
||||||
|
/**@type {number}*/ (params[0]),
|
||||||
|
/**@type {number | undefined}*/ (params[1]),
|
||||||
|
/**@type {number | undefined}*/ (params[2])
|
||||||
|
);
|
||||||
|
return notify_datetime_changes(options.value, tmp, options.notify_read_properties);
|
||||||
|
},
|
||||||
|
setUTCHours: (options, ...params) => {
|
||||||
|
const tmp = new Date(options.value);
|
||||||
|
tmp.setUTCHours(
|
||||||
|
/**@type {number}*/ (params[0]),
|
||||||
|
/**@type {number | undefined}*/ (params[1]),
|
||||||
|
/**@type {number | undefined}*/ (params[2]),
|
||||||
|
/**@type {number | undefined}*/ (params[3])
|
||||||
|
);
|
||||||
|
return notify_datetime_changes(options.value, tmp, options.notify_read_properties);
|
||||||
|
},
|
||||||
|
setUTCMilliseconds: (options, ...params) => {
|
||||||
|
const tmp = new Date(options.value);
|
||||||
|
tmp.setUTCMilliseconds(/**@type {number}*/ (params[0]));
|
||||||
|
return notify_datetime_changes(options.value, tmp, options.notify_read_properties);
|
||||||
|
},
|
||||||
|
setUTCMinutes: (options, ...params) => {
|
||||||
|
const tmp = new Date(options.value);
|
||||||
|
tmp.setUTCMinutes(
|
||||||
|
/**@type {number}*/ (params[0]),
|
||||||
|
/**@type {number | undefined}*/ (params[1]),
|
||||||
|
/**@type {number | undefined}*/ (params[2])
|
||||||
|
);
|
||||||
|
return notify_datetime_changes(options.value, tmp, options.notify_read_properties);
|
||||||
|
},
|
||||||
|
setUTCMonth: (options, ...params) => {
|
||||||
|
const tmp = new Date(options.value);
|
||||||
|
tmp.setUTCMonth(/**@type {number}*/ (params[0]), /**@type {number | undefined}*/ (params[1]));
|
||||||
|
return notify_datetime_changes(options.value, tmp, options.notify_read_properties);
|
||||||
|
},
|
||||||
|
setUTCSeconds: (options, ...params) => {
|
||||||
|
const tmp = new Date(options.value);
|
||||||
|
tmp.setUTCSeconds(
|
||||||
|
/**@type {number}*/ (params[0]),
|
||||||
|
/**@type {number | undefined}*/ (params[1])
|
||||||
|
);
|
||||||
|
return notify_datetime_changes(options.value, tmp, options.notify_read_properties);
|
||||||
|
},
|
||||||
|
// @ts-expect-error - deprecated method
|
||||||
|
setYear: (options, ...params) => {
|
||||||
|
// it might be removed from browsers
|
||||||
|
if (!options.value.getYear) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const tmp = new Date(options.value);
|
||||||
|
// @ts-expect-error
|
||||||
|
tmp.setYear(/**@type {number}*/ (params[0]));
|
||||||
|
return notify_datetime_changes(options.value, tmp, options.notify_read_properties);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in new issue