]> git.ipfire.org Git - thirdparty/moment.git/commitdiff
Implement Moment, Duration, and Locale prototypes with immutable API
authorLucas Sanders <butterflyhug@google.com>
Sun, 30 Oct 2016 18:27:54 +0000 (14:27 -0400)
committerLucas Sanders <butterflyhug@google.com>
Wed, 22 Mar 2017 10:12:27 +0000 (06:12 -0400)
This is done by wrapping all mutation methods with a function that clones
a new object before the mutation algorithm.

src/lib/duration/prototype.js
src/lib/locale/constructor.js
src/lib/locale/prototype.js
src/lib/moment/locale.js
src/lib/moment/prototype.js
src/lib/utils/wrap.js [new file with mode: 0644]
src/moment.js

index d923375cbe80c8531aafad0b49aa09edddc99f69..3fd516a5650d4127816fb51e416afa6d741abf50 100644 (file)
@@ -1,4 +1,5 @@
 import { Duration } from './constructor';
+import wrap from '../utils/wrap';
 
 var proto = Duration.prototype;
 
@@ -14,8 +15,8 @@ import { isValid } from './valid';
 
 proto.isValid        = isValid;
 proto.abs            = abs;
-proto.add            = add;
-proto.subtract       = subtract;
+proto.add            = wrap(Duration, add);
+proto.subtract       = wrap(Duration, subtract);
 proto.as             = as;
 proto.asMilliseconds = asMilliseconds;
 proto.asSeconds      = asSeconds;
@@ -40,11 +41,11 @@ proto.humanize       = humanize;
 proto.toISOString    = toISOString;
 proto.toString       = toISOString;
 proto.toJSON         = toISOString;
-proto.locale         = locale;
+proto.locale         = wrap(Duration, locale, true);
 proto.localeData     = localeData;
 
 // Deprecations
 import { deprecate } from '../utils/deprecate';
 
 proto.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', toISOString);
-proto.lang = lang;
+proto.lang = deprecate('duration.lang() is deprecated. Use locale() or localeData() instead.', wrap(Duration, lang));
index c32b73ee11c6d3e6759d91237c169ff343ba852d..dfaaed2a3a309aaab2f937e4213823947078f891 100644 (file)
@@ -1,5 +1,7 @@
+import { set } from './set';
+
 export function Locale(config) {
     if (config != null) {
-        this.set(config);
+        set.call(this, config);
     }
 }
index 24eef89f14b917821a40c003e4f4aba5ddf13e7b..5be98757f79a428ac894f672595aaed06fe3bab4 100644 (file)
@@ -9,6 +9,7 @@ import { ordinal } from './ordinal';
 import { preParsePostFormat } from './pre-post-format';
 import { relativeTime, pastFuture } from './relative';
 import { set } from './set';
+import wrap from '../utils/wrap';
 
 proto.calendar        = calendar;
 proto.longDateFormat  = longDateFormat;
@@ -18,7 +19,7 @@ proto.preparse        = preParsePostFormat;
 proto.postformat      = preParsePostFormat;
 proto.relativeTime    = relativeTime;
 proto.pastFuture      = pastFuture;
-proto.set             = set;
+proto.set             = wrap(Locale, set);
 
 // Month
 import {
@@ -29,9 +30,9 @@ import {
     monthsShortRegex
 } from '../units/month';
 
-proto.months            =        localeMonths;
-proto.monthsShort       =        localeMonthsShort;
-proto.monthsParse       =        localeMonthsParse;
+proto.months            = localeMonths;
+proto.monthsShort       = localeMonthsShort;
+proto.monthsParse       = localeMonthsParse;
 proto.monthsRegex       = monthsRegex;
 proto.monthsShortRegex  = monthsShortRegex;
 
@@ -53,14 +54,14 @@ import {
     weekdaysMinRegex
 } from '../units/day-of-week';
 
-proto.weekdays       =        localeWeekdays;
-proto.weekdaysMin    =        localeWeekdaysMin;
-proto.weekdaysShort  =        localeWeekdaysShort;
-proto.weekdaysParse  =        localeWeekdaysParse;
+proto.weekdays       = localeWeekdays;
+proto.weekdaysMin    = localeWeekdaysMin;
+proto.weekdaysShort  = localeWeekdaysShort;
+proto.weekdaysParse  = localeWeekdaysParse;
 
-proto.weekdaysRegex       =        weekdaysRegex;
-proto.weekdaysShortRegex  =        weekdaysShortRegex;
-proto.weekdaysMinRegex    =        weekdaysMinRegex;
+proto.weekdaysRegex       = weekdaysRegex;
+proto.weekdaysShortRegex  = weekdaysShortRegex;
+proto.weekdaysMinRegex    = weekdaysMinRegex;
 
 // Hours
 import { localeIsPM, localeMeridiem } from '../units/hour';
index fb46e6569e8c0d71fb3be0ec23cdf1901acaaf30..27d8ab036fa0a7a1fc470f3196930d82cfce02ff 100644 (file)
@@ -18,16 +18,13 @@ export function locale (key) {
     }
 }
 
-export var lang = deprecate(
-    'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',
-    function (key) {
-        if (key === undefined) {
-            return this.localeData();
-        } else {
-            return this.locale(key);
-        }
+export function lang (key) {
+    if (key === undefined) {
+        return this.localeData();
+    } else {
+        return this.locale(key);
     }
-);
+}
 
 export function localeData () {
     return this._locale;
index bd8fff79c201e4e588c824e97296cffa14d79981..dab62143f687bda762e04de4aa651103c64da238 100644 (file)
@@ -1,4 +1,5 @@
 import { Moment } from './constructor';
+import wrap from '../utils/wrap';
 
 var proto = Moment.prototype;
 
@@ -18,96 +19,92 @@ import { valueOf, toDate, toArray, toObject, toJSON, unix } from './to-type';
 import { isValid, parsingFlags, invalidAt } from './valid';
 import { creationData } from './creation-data';
 
-proto.add               = add;
-proto.calendar          = calendar;
-proto.clone             = clone;
-proto.diff              = diff;
-proto.endOf             = endOf;
-proto.format            = format;
-proto.from              = from;
-proto.fromNow           = fromNow;
-proto.to                = to;
-proto.toNow             = toNow;
-proto.get               = stringGet;
-proto.invalidAt         = invalidAt;
-proto.isAfter           = isAfter;
-proto.isBefore          = isBefore;
-proto.isBetween         = isBetween;
-proto.isSame            = isSame;
-proto.isSameOrAfter     = isSameOrAfter;
-proto.isSameOrBefore    = isSameOrBefore;
-proto.isValid           = isValid;
-proto.lang              = lang;
-proto.locale            = locale;
-proto.localeData        = localeData;
-proto.max               = prototypeMax;
-proto.min               = prototypeMin;
-proto.parsingFlags      = parsingFlags;
-proto.set               = stringSet;
-proto.startOf           = startOf;
-proto.subtract          = subtract;
-proto.toArray           = toArray;
-proto.toObject          = toObject;
-proto.toDate            = toDate;
-proto.toISOString       = toISOString;
-proto.inspect           = inspect;
-proto.toJSON            = toJSON;
-proto.toString          = toString;
-proto.unix              = unix;
-proto.valueOf           = valueOf;
-proto.creationData      = creationData;
+proto.add            = wrap(Moment, add);
+proto.calendar       = calendar;
+proto.diff           = diff;
+proto.endOf          = wrap(Moment, endOf);
+proto.format         = format;
+proto.from           = from;
+proto.fromNow        = fromNow;
+proto.to             = to;
+proto.toNow          = toNow;
+proto.get            = stringGet;
+proto.invalidAt      = invalidAt;
+proto.isAfter        = isAfter;
+proto.isBefore       = isBefore;
+proto.isBetween      = isBetween;
+proto.isSame         = isSame;
+proto.isSameOrAfter  = isSameOrAfter;
+proto.isSameOrBefore = isSameOrBefore;
+proto.isValid        = isValid;
+proto.locale         = wrap(Moment, locale);
+proto.localeData     = localeData;
+proto.parsingFlags   = parsingFlags;
+proto.set            = wrap(Moment, stringSet);
+proto.startOf        = wrap(Moment, startOf);
+proto.subtract       = wrap(Moment, subtract);
+proto.toArray        = toArray;
+proto.toObject       = toObject;
+proto.toDate         = toDate;
+proto.toISOString    = toISOString;
+proto.inspect        = inspect;
+proto.toJSON         = toJSON;
+proto.toString       = toString;
+proto.unix           = unix;
+proto.valueOf        = valueOf;
+proto.creationData   = creationData;
 
 // Year
 import { getSetYear, getIsLeapYear } from '../units/year';
-proto.year       = getSetYear;
+proto.year       = wrap(Moment, getSetYear, true);
 proto.isLeapYear = getIsLeapYear;
 
 // Week Year
 import { getSetWeekYear, getSetISOWeekYear, getWeeksInYear, getISOWeeksInYear } from '../units/week-year';
-proto.weekYear    = getSetWeekYear;
-proto.isoWeekYear = getSetISOWeekYear;
+proto.weekYear    = wrap(Moment, getSetWeekYear, true);
+proto.isoWeekYear = wrap(Moment, getSetISOWeekYear, true);
 
 // Quarter
 import { getSetQuarter } from '../units/quarter';
-proto.quarter = proto.quarters = getSetQuarter;
+proto.quarter = proto.quarters = wrap(Moment, getSetQuarter, true);
 
 // Month
 import { getSetMonth, getDaysInMonth } from '../units/month';
-proto.month       = getSetMonth;
+proto.month       = wrap(Moment, getSetMonth, true);
 proto.daysInMonth = getDaysInMonth;
 
 // Week
 import { getSetWeek, getSetISOWeek } from '../units/week';
-proto.week           = proto.weeks        = getSetWeek;
-proto.isoWeek        = proto.isoWeeks     = getSetISOWeek;
-proto.weeksInYear    = getWeeksInYear;
-proto.isoWeeksInYear = getISOWeeksInYear;
+proto.week    = proto.weeks    = wrap(Moment, getSetWeek, true);
+proto.isoWeek = proto.isoWeeks = wrap(Moment, getSetISOWeek, true);
+proto.weeksInYear              = getWeeksInYear;
+proto.isoWeeksInYear           = getISOWeeksInYear;
 
 // Day
 import { getSetDayOfMonth } from '../units/day-of-month';
 import { getSetDayOfWeek, getSetISODayOfWeek, getSetLocaleDayOfWeek } from '../units/day-of-week';
 import { getSetDayOfYear } from '../units/day-of-year';
-proto.date       = getSetDayOfMonth;
-proto.day        = proto.days             = getSetDayOfWeek;
-proto.weekday    = getSetLocaleDayOfWeek;
-proto.isoWeekday = getSetISODayOfWeek;
-proto.dayOfYear  = getSetDayOfYear;
+proto.date             = wrap(Moment, getSetDayOfMonth, true);
+proto.day = proto.days = wrap(Moment, getSetDayOfWeek, true);
+proto.weekday          = wrap(Moment, getSetLocaleDayOfWeek, true);
+proto.isoWeekday       = wrap(Moment, getSetISODayOfWeek, true);
+proto.dayOfYear        = wrap(Moment, getSetDayOfYear, true);
 
 // Hour
 import { getSetHour } from '../units/hour';
-proto.hour = proto.hours = getSetHour;
+proto.hour = proto.hours = wrap(Moment, getSetHour, true);
 
 // Minute
 import { getSetMinute } from '../units/minute';
-proto.minute = proto.minutes = getSetMinute;
+proto.minute = proto.minutes = wrap(Moment, getSetMinute, true);
 
 // Second
 import { getSetSecond } from '../units/second';
-proto.second = proto.seconds = getSetSecond;
+proto.second = proto.seconds = wrap(Moment, getSetSecond, true);
 
 // Millisecond
 import { getSetMillisecond } from '../units/millisecond';
-proto.millisecond = proto.milliseconds = getSetMillisecond;
+proto.millisecond = proto.milliseconds = wrap(Moment, getSetMillisecond, true);
 
 // Offset
 import {
@@ -123,10 +120,10 @@ import {
     isUtcOffset,
     isUtc
 } from '../units/offset';
-proto.utcOffset            = getSetOffset;
-proto.utc                  = setOffsetToUTC;
-proto.local                = setOffsetToLocal;
-proto.parseZone            = setOffsetToParsedOffset;
+proto.utcOffset            = wrap(Moment, getSetOffset, true);
+proto.utc                  = wrap(Moment, setOffsetToUTC);
+proto.local                = wrap(Moment, setOffsetToLocal);
+proto.parseZone            = wrap(Moment, setOffsetToParsedOffset);
 proto.hasAlignedHourOffset = hasAlignedHourOffset;
 proto.isDST                = isDaylightSavingTime;
 proto.isLocal              = isLocal;
@@ -141,10 +138,32 @@ proto.zoneName = getZoneName;
 
 // Deprecations
 import { deprecate } from '../utils/deprecate';
-proto.dates  = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);
-proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);
-proto.years  = deprecate('years accessor is deprecated. Use year instead', getSetYear);
-proto.zone   = deprecate('moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', getSetZone);
-proto.isDSTShifted = deprecate('isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', isDaylightSavingTimeShifted);
+proto.clone = deprecate(
+    'clone does nothing in Moment v3.x because the API is now immutable. Use moment(instance) to make a copy.',
+    function clone() { return this; });
+proto.dates = deprecate(
+    'dates accessor is deprecated. Use date instead.',
+    wrap(Moment, getSetDayOfMonth, true));
+proto.lang = deprecate(
+    'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',
+    wrap(Moment, lang));
+proto.max = deprecate(
+    'moment().max() is deprecated. Use moment.min() instead (notice lack of parentheses).',
+    prototypeMax);
+proto.min = deprecate(
+    'moment().min() is deprecated. Use moment.max() instead (notice lack of parentheses).',
+    prototypeMin);
+proto.months = deprecate(
+    'months accessor is deprecated. Use month instead',
+    wrap(Moment, getSetMonth, true));
+proto.years = deprecate(
+    'years accessor is deprecated. Use year instead',
+    wrap(Moment, getSetYear, true));
+proto.zone = deprecate(
+    'moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/',
+    wrap(Moment, getSetZone, true));
+proto.isDSTShifted = deprecate(
+    'isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information',
+    isDaylightSavingTimeShifted);
 
 export default proto;
diff --git a/src/lib/utils/wrap.js b/src/lib/utils/wrap.js
new file mode 100644 (file)
index 0000000..0bbdb37
--- /dev/null
@@ -0,0 +1,11 @@
+export default function wrap(Type, fn, dontCloneWithNoArgs) {
+    return function() {
+        var m;
+        if (dontCloneWithNoArgs && !arguments.length) {
+            m = this;
+        } else {
+            m = new Type(this);
+        }
+        return fn.apply(m, arguments);
+    };
+}
index 4d5f3be7e5abbd21b356c15b9a9a06d577bd8c54..d810e2a6a9a577c29272f620fa10006504764462 100644 (file)
@@ -74,7 +74,7 @@ moment.updateLocale          = updateLocale;
 moment.locales               = locales;
 moment.weekdaysShort         = weekdaysShort;
 moment.normalizeUnits        = normalizeUnits;
-moment.relativeTimeRounding = relativeTimeRounding;
+moment.relativeTimeRounding  = relativeTimeRounding;
 moment.relativeTimeThreshold = relativeTimeThreshold;
 moment.calendarFormat        = getCalendarFormat;
 moment.prototype             = fn;