Bug 1098585 - Get rid of __iterator__ in calendar/. r=MakeMyDay
authorPhilipp Kewisch <mozilla@kewis.ch>
Tue, 21 Jun 2016 01:00:08 +0200
changeset 19525 c8afe5b01783f9595206abf4d51610f2c78a8a37
parent 19524 9bad6d3d6def25a8d1ff4f6a334006be42f9dfb6
child 19526 8d1ed8f5d2e80356a4baadfc0402e93bb06b2c8c
push id12030
push usermozilla@jorgk.com
push dateSun, 26 Jun 2016 07:57:39 +0000
treeherdercomm-central@c8afe5b01783 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersMakeMyDay
bugs1098585
Bug 1098585 - Get rid of __iterator__ in calendar/. r=MakeMyDay
calendar/base/backend/icaljs/calICSService.js
calendar/base/modules/calHashedArray.jsm
calendar/base/modules/calIteratorUtils.jsm
calendar/base/modules/calItipUtils.jsm
calendar/base/src/calAlarm.js
calendar/base/src/calIcsParser.js
calendar/base/src/calIcsSerializer.js
calendar/base/src/calItemBase.js
calendar/base/src/calItipItem.js
calendar/base/src/calTimezoneService.js
calendar/base/src/calUtils.js
calendar/providers/caldav/calDavCalendar.js
calendar/providers/gdata/modules/gdataUtils.jsm
calendar/providers/memory/calMemoryCalendar.js
calendar/providers/wcap/calWcapCalendarItems.js
calendar/providers/wcap/calWcapSession.js
--- a/calendar/base/backend/icaljs/calICSService.js
+++ b/calendar/base/backend/icaljs/calICSService.js
@@ -172,43 +172,39 @@ calIcalProperty.prototype = {
     clearXParameters: function() {
         cal.WARN("calIICSService::clearXParameters is no longer implemented, " +
                  "please use removeParameter");
     },
 
     paramIterator: null,
     getFirstParameterName: function() {
         let innerObject = this.innerObject;
-        this.paramIterator = (function() {
+        this.paramIterator = (function*() {
             let propname = innerObject.name.toLowerCase();
             let defaultType = innerObject.getDefaultType();
             if (defaultType != innerObject.type) {
                 yield "VALUE";
             }
 
             let paramNames = Object.keys(innerObject.jCal[1] || {});
             for (let name of paramNames) {
                 yield name.toUpperCase();
             }
         })();
         return this.getNextParameterName();
     },
 
     getNextParameterName: function() {
         if (this.paramIterator) {
-            try {
-                return this.paramIterator.next();
-            } catch (e) {
-                if (e instanceof StopIteration) {
-                    this.paramIterator = null;
-                    return null;
-                } else {
-                    throw e;
-                }
+            let next = this.paramIterator.next();
+            if (next.done) {
+                this.paramIterator = null;
             }
+
+            return next.value;
         } else {
             return this.getFirstParameterName();
         }
     }
 };
 
 function calIcalComponent(innerObject) {
     this.innerObject = innerObject || new ICAL.Component();
@@ -239,38 +235,34 @@ calIcalComponent.prototype = {
     componentIterator: null,
     getFirstSubcomponent: function(kind) {
         if (kind == "ANY") {
             kind = null;
         } else if (kind) {
             kind = kind.toLowerCase();
         }
         let innerObject = this.innerObject;
-        this.componentIterator = (function() {
+        this.componentIterator = (function*() {
             let comps = innerObject.getAllSubcomponents(kind);
             if (comps) {
                 for (let comp of comps) {
                     yield new calIcalComponent(comp);
                 }
             }
         })();
         return this.getNextSubcomponent(kind)
     },
     getNextSubcomponent: function(kind) {
         if (this.componentIterator) {
-            try {
-                return this.componentIterator.next();
-            } catch (e) {
-                if (e instanceof StopIteration) {
-                    this.componentIterator = null;
-                    return null;
-                } else {
-                    throw e;
-                }
+            let next = this.componentIterator.next();
+            if (next.done) {
+                this.componentIterator = null;
             }
+
+            return next.value;
         } else {
             return this.getFirstSubcomponent(kind);
         }
     },
 
     get componentType() { return this.innerObject.name.toUpperCase(); },
 
     get uid() { return this.innerObject.getFirstPropertyValue("uid"); },
@@ -363,17 +355,17 @@ calIcalComponent.prototype = {
     propertyIterator: null,
     getFirstProperty: function getFirstProperty(kind) {
         if (kind == "ANY") {
             kind = null;
         } else if (kind) {
             kind = kind.toLowerCase();
         }
         let innerObject = this.innerObject;
-        this.propertyIterator = (function() {
+        this.propertyIterator = (function*() {
             let props = innerObject.getAllProperties(kind);
             if (!props) {
                 return;
             }
             for (var prop of props) {
                 let hell = prop.getValues();
                 if (hell.length > 1) {
                     // Uh oh, multiple property values. Our code expects each as one
@@ -391,26 +383,22 @@ calIcalComponent.prototype = {
             }
         })();
 
         return this.getNextProperty(kind);
     },
 
     getNextProperty: function getNextProperty(kind) {
         if (this.propertyIterator) {
-            try {
-                return this.propertyIterator.next();
-            } catch (e) {
-                if (e instanceof StopIteration) {
-                    this.propertyIterator = null;
-                    return null;
-                } else {
-                    throw e;
-                }
+            let next = this.propertyIterator.next();
+            if (next.done) {
+                this.propertyIterator = null;
             }
+
+            return next.value;
         } else {
             return this.getFirstProperty(kind);
         }
     },
 
     _getNextParentVCalendar: function() {
         let that = this;
         while (that && that.componentType != "VCALENDAR") {
--- a/calendar/base/modules/calHashedArray.jsm
+++ b/calendar/base/modules/calHashedArray.jsm
@@ -201,18 +201,18 @@ cal.HashedArray.prototype = {
             this.reindex(this.mFirstDirty);
             this.mFirstDirty = -1;
         }
     },
 
     /**
      * Iterator to allow iterating the hashed array object.
      */
-    __iterator__: function iterator(useKeys) {
-        return new Iterator(this.mArray, useKeys);
+    [Symbol.iterator]: function* iterator() {
+        yield* this.mArray;
     }
 };
 
 /**
  * Sorted hashed array. The array always stays sorted.
  *
  * Performance Considerations:
  *  - Accessing items is fast
--- a/calendar/base/modules/calIteratorUtils.jsm
+++ b/calendar/base/modules/calIteratorUtils.jsm
@@ -9,31 +9,26 @@ Components.utils.import("resource://gre/
 this.EXPORTED_SYMBOLS = ["cal"]; // even though it's defined in calUtils.jsm, import needs this
 
 /**
  * Iterates an array of items, i.e. the passed item including all
  * overridden instances of a recurring series.
  *
  * @param items array of items
  */
-cal.itemIterator = function cal_itemIterator(items) {
-    return {
-        __iterator__: function itemIterator(aWantKeys) {
-            cal.ASSERT(aWantKeys, "Please use for() on the item iterator");
-            for (let item of items) {
-                yield item;
-                let rec = item.recurrenceInfo;
-                if (rec) {
-                    for (let exid of rec.getExceptionIds({})) {
-                        yield rec.getExceptionFor(exid);
-                    }
-                }
+cal.itemIterator = function* cal_itemIterator(items) {
+    for (let item of items) {
+        yield item;
+        let rec = item.recurrenceInfo;
+        if (rec) {
+            for (let exid of rec.getExceptionIds({})) {
+                yield rec.getExceptionFor(exid);
             }
         }
-    };
+    }
 };
 
 /**
  * Runs the body() function once for each item in the iterator using the event
  * queue to make sure other actions could run inbetween. When all iterations are
  * done (and also when cal.forEach.BREAK is returned), calls the completed()
  * function if passed.
  *
@@ -45,59 +40,48 @@ cal.itemIterator = function cal_itemIter
  * for each loop, use the optional completed() function.
  *
  * @param iter          The Iterator or the plain Object to go through in this
  *                      loop.
  * @param body          The function called for each iteration. Its parameter is
  *                          the single item from the iterator.
  * @param completed     [optional] The function called after the loop completes.
  */
-cal.forEach = function cal_forEach(iter, body, completed) {
+cal.forEach = function cal_forEach(iterable, body, completed) {
     // This should be a const one day, lets keep it a pref for now though until we
     // find a sane value.
     let LATENCY = Preferences.get("calendar.threading.latency", 250);
 
-    let ourIter = iter;
-    if (!(iter instanceof Iterator)) {
-        // If its not an iterator, we need to use a generator to make sure
-        // calling this function feels right.
-        // FIXME: Dispatcher needs StopIteration, so we use legacy generator
-        // here for now.  Should be replaced with ES6 generator in the future,
-        // when removing Iterator from caller.
-        ourIter = (function() {
-            for (let key in iter) {
-              yield iter[key];
-            }
-        })();
+    if (typeof iterable == "object" && !iterable[Symbol.iterator]) {
+        iterable = Object.entries(iterable);
     }
 
+    let ourIter = iterable[Symbol.iterator]();
     let currentThread = Services.tm.currentThread;
 
     // This is our dispatcher, it will be used for the iterations
     let dispatcher = {
         run: function run() {
-            try {
-                let startTime = (new Date()).getTime();
-                while (((new Date()).getTime()  - startTime) < LATENCY) {
-                    let next = ourIter.next();
-                    let rc = body(next);
+            let startTime = (new Date()).getTime();
+            while (((new Date()).getTime() - startTime) < LATENCY) {
+                let next = ourIter.next();
+                let done = next.done;
+
+                if (!done) {
+                    let rc = body(next.value);
                     if (rc == cal.forEach.BREAK) {
-                        throw StopIteration;
+                        done = true;
                     }
                 }
-            } catch (e) {
-                if (e instanceof StopIteration) {
-                    // Iterating is done, return early to avoid resubmitting to the
-                    // event queue again. If there is a completed function, run it.
+
+                if (done) {
                     if (completed) {
                         completed();
                     }
                     return;
-                } else {
-                    throw e;
                 }
             }
 
             currentThread.dispatch(this, currentThread.DISPATCH_NORMAL);
         }
     };
 
     currentThread.dispatch(dispatcher, currentThread.DISPATCH_NORMAL);
@@ -115,135 +99,95 @@ cal.ical = {
      *  Yields all subcomponents in all calendars in the passed component.
      *  - If the passed component is an XROOT (contains multiple calendars),
      *    then go through all VCALENDARs in it and get their subcomponents.
      *  - If the passed component is a VCALENDAR, iterate through its direct
      *    subcomponents.
      *  - Otherwise assume the passed component is the item itself and yield
      *    only the passed component.
      *
-     * This iterator can only be used in a for() block:
-     *   for (let component in cal.ical.calendarComponentIterator(aComp)) { ... }
+     * This iterator can only be used in a for..of block:
+     *   for (let component of cal.ical.calendarComponentIterator(aComp)) { ... }
      *
      *  @param aComponent       The component to iterate given the above rules.
      *  @param aCompType        The type of item to iterate.
      *  @return                 The iterator that yields all items.
      */
-    calendarComponentIterator: function cal_ical_calendarComponentIterator(aComponent, aCompType) {
+    calendarComponentIterator: function* cal_ical_calendarComponentIterator(aComponent, aCompType) {
         let compType = (aCompType || "ANY");
         if (aComponent && aComponent.componentType == "VCALENDAR") {
-            return cal.ical.subcomponentIterator(aComponent, compType);
+            yield* cal.ical.subcomponentIterator(aComponent, compType);
         } else if (aComponent && aComponent.componentType == "XROOT") {
-            return {
-                __iterator__: function calVCALENDARIterator(aWantKeys) {
-                    cal.ASSERT(aWantKeys, "Please use for() on the calendar component iterator");
-                    for (let calComp in cal.ical.subcomponentIterator(aComponent, "VCALENDAR")) {
-                        for (let itemComp in cal.ical.subcomponentIterator(calComp, compType)) {
-                            yield itemComp;
-                        }
-                    }
-                }
-            };
+            for (let calComp of cal.ical.subcomponentIterator(aComponent, "VCALENDAR")) {
+                yield* cal.ical.subcomponentIterator(calComp, compType);
+            }
         } else if (aComponent && (compType == "ANY" || compType == aComponent.componentType)) {
-            return {
-                __iterator__: function singleItemIterator(aWantKeys) {
-                    cal.ASSERT(aWantKeys, "Please use for() on the calendar component iterator");
-                    yield aComponent;
-                }
-            }
+            yield aComponent;
         } else {
-            return Iterator({});
+            return null;
         }
     },
 
     /**
      * Use to iterate through all subcomponents of a calIIcalComponent. This
      * iterators depth is 1, this means no sub-sub-components will be iterated.
      *
      * This iterator can only be used in a for() block:
      *   for (let component in cal.ical.subcomponentIterator(aComp)) { ... }
      *
      * @param aComponent        The component who's subcomponents to iterate.
      * @param aSubcomp          (optional) the specific subcomponent to
      *                            enumerate. If not given, "ANY" will be used.
      * @return                  An iterator object to iterate the properties.
      */
-    subcomponentIterator: function cal_ical_subcomponentIterator(aComponent, aSubcomp) {
-        return {
-            __iterator__: function icalSubcompIterator(aWantKeys) {
-                cal.ASSERT(aWantKeys, "Please use for() on the subcomponent iterator");
-                let subcompName = (aSubcomp || "ANY");
-                for (let subcomp = aComponent.getFirstSubcomponent(subcompName);
-                     subcomp;
-                     subcomp = aComponent.getNextSubcomponent(subcompName)) {
-                    yield subcomp;
-                }
-            }
-        };
+    subcomponentIterator: function* cal_ical_subcomponentIterator(aComponent, aSubcomp) {
+        let subcompName = (aSubcomp || "ANY");
+        for (let subcomp = aComponent.getFirstSubcomponent(subcompName);
+             subcomp;
+             subcomp = aComponent.getNextSubcomponent(subcompName)) {
+            yield subcomp;
+        }
     },
 
     /**
      * Use to iterate through all properties of a calIIcalComponent.
      * This iterator can only be used in a for() block:
      *   for (let property in cal.ical.propertyIterator(aComp)) { ... }
      *
      * @param aComponent        The component to iterate.
      * @param aProperty         (optional) the specific property to enumerate.
      *                            If not given, "ANY" will be used.
      * @return                  An iterator object to iterate the properties.
      */
-    propertyIterator: function cal_ical_propertyIterator(aComponent, aProperty) {
-        return {
-            __iterator__: function icalPropertyIterator(aWantKeys) {
-                cal.ASSERT(aWantKeys, "Please use for() on the property iterator");
-                let propertyName = (aProperty || "ANY");
-                for (let prop = aComponent.getFirstProperty(propertyName);
-                     prop;
-                     prop = aComponent.getNextProperty(propertyName)) {
-                    yield prop;
-                }
-            }
-        };
+    propertyIterator: function* cal_ical_propertyIterator(aComponent, aProperty) {
+        let propertyName = (aProperty || "ANY");
+        for (let prop = aComponent.getFirstProperty(propertyName);
+             prop;
+             prop = aComponent.getNextProperty(propertyName)) {
+            yield prop;
+        }
     },
 
     /**
      * Use to iterate through all parameters of a calIIcalProperty.
      * This iterator behaves similar to the object iterator. Possible uses:
      *   for (let paramName in cal.ical.paramIterator(prop)) { ... }
      * or:
      *   for (let [paramName, paramValue] of cal.ical.paramIterator(prop)) { ... }
      *
      * @param aProperty         The property to iterate.
      * @return                  An iterator object to iterate the properties.
      */
-    paramIterator: function cal_ical_paramIterator(aProperty) {
-        return {
-            __iterator__: function icalParamIterator(aWantKeys) {
-                let paramSet = new Set();
-                for (let paramName = aProperty.getFirstParameterName();
-                     paramName;
-                     paramName = aProperty.getNextParameterName()) {
-                    // Workaround to avoid infinite loop when the property
-                    // contains duplicate parameters (bug 875739 for libical)
-                    if (!paramSet.has(paramName)) {
-                        yield (aWantKeys ? paramName :
-                                           [paramName, aProperty.getParameter(paramName)]);
-                        paramSet.add(paramName);
-                    }
-                }
-            },
-            [Symbol.iterator]: function* icalParamIterator() {
-                let paramSet = new Set();
-                for (let paramName = aProperty.getFirstParameterName();
-                     paramName;
-                     paramName = aProperty.getNextParameterName()) {
-                    // Workaround to avoid infinite loop when the property
-                    // contains duplicate parameters (bug 875739 for libical)
-                    if (!paramSet.has(paramName)) {
-                        yield [paramName, aProperty.getParameter(paramName)];
-                        paramSet.add(paramName);
-                    }
-                }
+    paramIterator: function* cal_ical_paramIterator(aProperty) {
+        let paramSet = new Set();
+        for (let paramName = aProperty.getFirstParameterName();
+             paramName;
+             paramName = aProperty.getNextParameterName()) {
+            // Workaround to avoid infinite loop when the property
+            // contains duplicate parameters (bug 875739 for libical)
+            if (!paramSet.has(paramName)) {
+                yield [paramName, aProperty.getParameter(paramName)];
+                paramSet.add(paramName);
             }
-        };
+        }
     }
 };
 
--- a/calendar/base/modules/calItipUtils.jsm
+++ b/calendar/base/modules/calItipUtils.jsm
@@ -810,18 +810,18 @@ cal.itip = {
                 RDATE: true,
                 RRULE: true,
                 EXDATE: true,
                 STATUS: true,
                 LOCATION: true
             };
 
             let propStrings = [];
-            for (let item in cal.itemIterator([aItem])) {
-                for (let prop in cal.ical.propertyIterator(item.icalComponent)) {
+            for (let item of cal.itemIterator([aItem])) {
+                for (let prop of cal.ical.propertyIterator(item.icalComponent)) {
                     if (prop.propertyName in majorProps) {
                         propStrings.push(item.recurrenceId + "#" + prop.icalString);
                     }
                 }
             }
             propStrings.sort();
             return propStrings.join("");
         };
--- a/calendar/base/src/calAlarm.js
+++ b/calendar/base/src/calAlarm.js
@@ -532,25 +532,25 @@ calAlarm.prototype = {
             throw Components.results.NS_ERROR_INVALID_ARG;
         } else {
             this.repeatOffset = null;
             this.repeat = 0;
         }
 
         // Set up attendees
         this.clearAttendees();
-        for (let attendeeProp in cal.ical.propertyIterator(aComp, "ATTENDEE")) {
+        for (let attendeeProp of cal.ical.propertyIterator(aComp, "ATTENDEE")) {
             let attendee = cal.createAttendee();
             attendee.icalProperty = attendeeProp;
             this.addAttendee(attendee);
         }
 
         // Set up attachments
         this.clearAttachments();
-        for (let attachProp in cal.ical.propertyIterator(aComp, "ATTACH")) {
+        for (let attachProp of cal.ical.propertyIterator(aComp, "ATTACH")) {
             let attach = cal.createAttachment();
             attach.icalProperty = attachProp;
             this.addAttachment(attach);
         }
 
         // Set up summary
         this.summary = (summaryProp ? summaryProp.value : null);
 
@@ -561,25 +561,24 @@ calAlarm.prototype = {
         // the default for an X-Prop is TEXT and in older versions we didn't set
         // VALUE=DATE-TIME.
         this.lastAck = (lastAckProp ? cal.createDateTime(lastAckProp.valueAsIcalString) : null);
 
         this.mProperties = new calPropertyBag();
         this.mPropertyParams = {};
 
         // Other properties
-        for (let prop in cal.ical.propertyIterator(aComp)) {
+        for (let prop of cal.ical.propertyIterator(aComp)) {
             if (!this.promotedProps[prop.propertyName]) {
                 this.setProperty(prop.propertyName, prop.value);
 
-                for (let paramName in cal.ical.paramIterator(prop)) {
+                for (let [paramName, param] of cal.ical.paramIterator(prop)) {
                     if (!(prop.propertyName in this.mPropertyParams)) {
                         this.mPropertyParams[prop.propertyName] = {};
                     }
-                    let param = prop.getParameter(paramName);
                     this.mPropertyParams[prop.propertyName][paramName] = param;
                 }
             }
         }
         return aComp;
     },
 
     hasProperty: function cA_hasProperty(aName) {
--- a/calendar/base/src/calIcsParser.js
+++ b/calendar/base/src/calIcsParser.js
@@ -44,23 +44,23 @@ calIcsParser.prototype = {
                       rootComp + "\nStack: \n" + cal.STACK(10));
         }
 
         let self = this;
         let state = new parserState(this, aAsyncParsing);
 
         while (calComp) {
             // Get unknown properties from the VCALENDAR
-            for (let prop in cal.ical.propertyIterator(calComp)) {
+            for (let prop of cal.ical.propertyIterator(calComp)) {
                 if (prop.propertyName != "VERSION" && prop.propertyName != "PRODID") {
                     this.mProperties.push(prop);
                 }
             }
 
-            for (let subComp in cal.ical.subcomponentIterator(calComp)) {
+            for (let subComp of cal.ical.subcomponentIterator(calComp)) {
                 state.submit(subComp);
             }
             calComp = rootComp.getNextSubcomponent("VCALENDAR");
         }
 
         state.join(function() {
             let fakedParents = {};
             // tag "exceptions", i.e. items with rid:
--- a/calendar/base/src/calIcsSerializer.js
+++ b/calendar/base/src/calIcsSerializer.js
@@ -69,15 +69,15 @@ calIcsSerializer.prototype = {
 
         for (let prop of this.mProperties) {
             calComp.addProperty(prop);
         }
         for (let comp of this.mComponents) {
             calComp.addSubcomponent(comp);
         }
 
-        for (let item in cal.itemIterator(this.mItems)) {
+        for (let item of cal.itemIterator(this.mItems)) {
             calComp.addSubcomponent(item.icalComponent);
         }
 
         return calComp;
     }
 };
--- a/calendar/base/src/calItemBase.js
+++ b/calendar/base/src/calItemBase.js
@@ -821,54 +821,54 @@ calItemBase.prototype = {
         // re-initializing from scratch -- no light proxy anymore:
         this.mIsProxy = false;
         this.mProperties = new calPropertyBag();
         this.mPropertyParams = {};
 
         this.mapPropsFromICS(icalcomp, this.icsBasePropMap);
 
         this.mAttendees = []; // don't inherit anything from parent
-        for (let attprop in cal.ical.propertyIterator(icalcomp, "ATTENDEE")) {
+        for (let attprop of cal.ical.propertyIterator(icalcomp, "ATTENDEE")) {
             let att = new calAttendee();
             att.icalProperty = attprop;
             this.addAttendee(att);
         }
 
         this.mAttachments = []; // don't inherit anything from parent
-        for (let attprop in cal.ical.propertyIterator(icalcomp, "ATTACH")) {
+        for (let attprop of cal.ical.propertyIterator(icalcomp, "ATTACH")) {
             let att = new calAttachment();
             att.icalProperty = attprop;
             this.addAttachment(att);
         }
 
         this.mRelations = []; // don't inherit anything from parent
-        for (let relprop in cal.ical.propertyIterator(icalcomp, "RELATED-TO")) {
+        for (let relprop of cal.ical.propertyIterator(icalcomp, "RELATED-TO")) {
             let rel = new calRelation();
             rel.icalProperty = relprop;
             this.addRelation(rel);
         }
 
         let org = null;
         let orgprop = icalcomp.getFirstProperty("ORGANIZER");
         if (orgprop) {
             org = new calAttendee();
             org.icalProperty = orgprop;
             org.isOrganizer = true;
         }
         this.mOrganizer = org;
 
         this.mCategories = [];
-        for (let catprop in cal.ical.propertyIterator(icalcomp, "CATEGORIES")) {
+        for (let catprop of cal.ical.propertyIterator(icalcomp, "CATEGORIES")) {
             this.mCategories.push(catprop.value);
         }
 
         // find recurrence properties
         let rec = null;
         if (!this.recurrenceId) {
-            for (let recprop in cal.ical.propertyIterator(icalcomp)) {
+            for (let recprop of cal.ical.propertyIterator(icalcomp)) {
                 let ritem = null;
                 switch (recprop.propertyName) {
                     case "RRULE":
                     case "EXRULE":
                         ritem = cal.createRecurrenceRule();
                         break;
                     case "RDATE":
                     case "EXDATE":
@@ -883,17 +883,17 @@ calItemBase.prototype = {
                     rec = cal.createRecurrenceInfo(this);
                 }
                 rec.appendRecurrenceItem(ritem);
             }
         }
         this.mRecurrenceInfo = rec;
 
         this.mAlarms = []; // don't inherit anything from parent
-        for (let alarmComp in cal.ical.subcomponentIterator(icalcomp, "VALARM")) {
+        for (let alarmComp of cal.ical.subcomponentIterator(icalcomp, "VALARM")) {
             let alarm = cal.createAlarm();
             try {
                 alarm.icalComponent = alarmComp;
                 this.addAlarm(alarm, true);
             } catch (e) {
                 cal.ERROR("Invalid alarm for item: " +
                           this.id + " (" +
                           alarmComp.serializeToICS() + ")" +
@@ -913,17 +913,17 @@ calItemBase.prototype = {
     /**
      * Import all properties not in the promoted map into this item's extended
      * properties bag.
      *
      * @param icalcomp      The ical component to read.
      * @param promoted      The map of promoted properties.
      */
     importUnpromotedProperties: function cIB_importUnpromotedProperties(icalcomp, promoted) {
-        for (let prop in cal.ical.propertyIterator(icalcomp)) {
+        for (let prop of cal.ical.propertyIterator(icalcomp)) {
             let propName = prop.propertyName;
             if (!promoted[propName]) {
                 this.setProperty(propName, prop.value);
                 for (let [paramName, paramValue] of cal.ical.paramIterator(prop)) {
                     if (!(propName in this.mPropertyParams)) {
                         this.mPropertyParams[propName] = {};
                     }
                     this.mPropertyParams[propName][paramName] = paramValue;
--- a/calendar/base/src/calItipItem.js
+++ b/calendar/base/src/calItipItem.js
@@ -121,17 +121,17 @@ calItipItem.prototype = {
                     att.deleteProperty("RECEIVED-SEQUENCE");
                     att.deleteProperty("RECEIVED-DTSTAMP");
                 });
             item.setProperty("DTSTAMP", stamp);
             item.setProperty("LAST-MODIFIED", lastModified); // need to be last to undirty the item
         }
 
         this.mItemList = [];
-        for (let item in cal.itemIterator(parser.getItems({}))) {
+        for (let item of cal.itemIterator(parser.getItems({}))) {
             cleanItem(item);
             // only push non-faked master items or
             // the overridden instances of faked master items
             // to the list:
             if (item == item.parentItem) {
                 if (!item.hasProperty("X-MOZ-FAKED-MASTER")) {
                     this.mItemList.push(item);
                 }
--- a/calendar/base/src/calTimezoneService.js
+++ b/calendar/base/src/calTimezoneService.js
@@ -458,17 +458,17 @@ function guessSystemTimezone() {
     function findCurrentTimePeriod(tz, subComp, standardOrDaylight,
                                    isForNextTransitionDate) {
         // Iterate through 'STANDARD' declarations or 'DAYLIGHT' declarations
         // (periods in history with different settings.
         //  e.g., US changes daylight start in 2007 (from April to March).)
         // Each period is marked by a DTSTART.
         // Find the currently applicable period: has most recent DTSTART
         // not later than today and no UNTIL, or UNTIL is greater than today.
-        for (let period in cal.ical.subcomponentIterator(subComp, standardOrDaylight)) {
+        for (let period of cal.ical.subcomponentIterator(subComp, standardOrDaylight)) {
             periodStartCalDate.icalString = getIcalString(period, "DTSTART");
             periodStartCalDate.timezone = tz;
             if (oneYrUTC.nativeTime < periodStartCalDate.nativeTime) {
                 continue; // period starts too far in future
             }
             // Must examine UNTIL date (not next daylight start) because
             // some zones (e.g., Arizona, Hawaii) may stop using daylight
             // time, so there might not be a next daylight start.
--- a/calendar/base/src/calUtils.js
+++ b/calendar/base/src/calUtils.js
@@ -1695,25 +1695,25 @@ function compareItemContent(aFirstItem, 
         }
         return hash;
     }
 
     // This doesn't have to be super correct rfc5545, it just needs to be
     // in the same order
     function normalizeComponent(comp) {
         let props = [];
-        for (let prop in cal.ical.propertyIterator(comp)) {
+        for (let prop of cal.ical.propertyIterator(comp)) {
             if (!(prop.propertyName in ignoreProps)) {
                 props.push(normalizeProperty(prop));
             }
         }
         props = props.sort();
 
         let comps = [];
-        for (let subcomp in cal.ical.subcomponentIterator(comp)) {
+        for (let subcomp of cal.ical.subcomponentIterator(comp)) {
             comps.push(normalizeComponent(subcomp));
         }
         comps = comps.sort();
 
         return comp.componentType + props.join("\r\n") + comps.join("\r\n");
     }
 
     function normalizeProperty(prop) {
--- a/calendar/providers/caldav/calDavCalendar.js
+++ b/calendar/providers/caldav/calDavCalendar.js
@@ -2489,17 +2489,17 @@ calDavCalendar.prototype = {
                 if (status.substr(0,3) != "2.0") {
                     cal.LOG("CalDAV: Got status " + status + " in response to " +
                             "freebusy query for" + thisCalendar.name);
                 }
 
                 let caldata = caldavXPathFirst(fbResult, "/C:schedule-response/C:response/C:calendar-data/text()");
                 try {
                     let calComp = cal.getIcsService().parseICS(caldata, null);
-                    for (let fbComp in cal.ical.calendarComponentIterator(calComp)) {
+                    for (let fbComp of cal.ical.calendarComponentIterator(calComp)) {
                         let interval;
 
                         let replyRangeStart = fbComp.startTime;
                         if (replyRangeStart && (aRangeStart.compare(replyRangeStart) == -1)) {
                             interval = new cal.FreeBusyInterval(aCalId,
                                                                 calIFreeBusyInterval.UNKNOWN,
                                                                 aRangeStart,
                                                                 replyRangeStart);
@@ -2509,17 +2509,17 @@ calDavCalendar.prototype = {
                         if (replyRangeEnd && (aRangeEnd.compare(replyRangeEnd) == 1)) {
                             interval = new cal.FreeBusyInterval(aCalId,
                                                                 calIFreeBusyInterval.UNKNOWN,
                                                                 replyRangeEnd,
                                                                 aRangeEnd);
                             periodsToReturn.push(interval);
                         }
 
-                        for (let fbProp in cal.ical.propertyIterator(fbComp, "FREEBUSY")) {
+                        for (let fbProp of cal.ical.propertyIterator(fbComp, "FREEBUSY")) {
                             let fbType = fbProp.getParameter("FBTYPE");
                             if (fbType) {
                                 fbType = fbTypeMap[fbType];
                             } else {
                                 fbType = calIFreeBusyInterval.BUSY;
                             }
                             let parts = fbProp.value.split("/");
                             let begin = cal.createDateTime(parts[0]);
--- a/calendar/providers/gdata/modules/gdataUtils.jsm
+++ b/calendar/providers/gdata/modules/gdataUtils.jsm
@@ -581,17 +581,17 @@ function setupRecurrence(aItem, aRecurre
     try {
         let vevent = "BEGIN:VEVENT\r\n" + aRecurrence.join("\r\n") + "\r\nEND:VEVENT";
         rootComp = cal.getIcsService().parseICS(vevent, null);
     } catch (e) {
         cal.ERROR("[calGoogleCalendar] Unable to parse recurrence item: " + vevent);
     }
 
     let hasRecurringRules = false;
-    for (let prop in cal.ical.propertyIterator(rootComp)) {
+    for (let prop of cal.ical.propertyIterator(rootComp)) {
        switch (prop.propertyName) {
             case "RDATE":
             case "EXDATE":
                 let recItem = Components.classes["@mozilla.org/calendar/recurrence-date;1"]
                               .createInstance(Components.interfaces.calIRecurrenceDate);
                 try {
                     recItem.icalProperty = prop;
                     aItem.recurrenceInfo.appendRecurrenceItem(recItem);
--- a/calendar/providers/memory/calMemoryCalendar.js
+++ b/calendar/providers/memory/calMemoryCalendar.js
@@ -419,17 +419,17 @@ calMemoryCalendar.prototype = {
         aRangeEnd = cal.ensureDateTime(aRangeEnd);
 
 
         let offline_filter = aItemFilter &
             (calICalendar.ITEM_FILTER_OFFLINE_DELETED |
              calICalendar.ITEM_FILTER_OFFLINE_CREATED |
              calICalendar.ITEM_FILTER_OFFLINE_MODIFIED);
 
-        cal.forEach(this.mItems, (item) => {
+        cal.forEach(this.mItems, ([id, item]) => {
             let isEvent_ = cal.isEvent(item);
             if (isEvent_) {
                 if (!wantEvents) {
                     return cal.forEach.CONTINUE;
                 }
             } else if (!wantTodos) {
                 return cal.forEach.CONTINUE;
             }
--- a/calendar/providers/wcap/calWcapCalendarItems.js
+++ b/calendar/providers/wcap/calWcapCalendarItems.js
@@ -844,17 +844,17 @@ calWcapCalendar.prototype.parseItems = f
         case calICalendar.ITEM_FILTER_TYPE_EVENT:
             componentType = "VEVENT";
             break;
     }
 
     let recurrenceBound = this.session.recurrenceBound;
 
     let count = 0;
-    for (let subComp in cal.ical.calendarComponentIterator(icalRootComp, componentType)) {
+    for (let subComp of cal.ical.calendarComponentIterator(icalRootComp, componentType)) {
 
         let organizer = subComp.getFirstProperty("ORGANIZER");
         if (organizer && organizer.getParameter("SENT-BY")) { // has SENT-BY
             // &emailorcalid=1 sets wrong email, workaround setting calid...
             let id = organizer.getParameter("X-S1CS-CALID");
             if (id) {
                 organizer.value = id;
             }
--- a/calendar/providers/wcap/calWcapSession.js
+++ b/calendar/providers/wcap/calWcapSession.js
@@ -686,17 +686,17 @@ calWcapSession.prototype = {
         this.m_serverTimezones = {};
         var this_ = this;
         this_.issueNetworkRequest_(
             request,
             function netResp(err, data) {
                 if (err) {
                     throw err;
                 }
-                for (let subComp in cal.ical.calendarComponentIterator(data, "VTIMEZONE")) {
+                for (let subComp of cal.ical.calendarComponentIterator(data, "VTIMEZONE")) {
                     try {
                         let tzid = subComp.getFirstProperty("TZID").value;
                         this_.m_serverTimezones[tzid] = new calWcapTimezone(this_, tzid, subComp);
                     } catch (exc) { // ignore but errors:
                         logError(exc, this_);
                     }
                 }
                 log("installed timezones.", this_);