@samitouri / QOS-React-2 / commits / 8d48610b7e
Fork 0

The library for web and native user interfaces.

Typecheck ImmutableObject

Just some therapeutic cleanup.

Tim Yung committed Jul 24, 2013 at 17:19 UTC 8d48610b7e6a9d31a5ea9044b180c73053d066b7
1 file changed +72 -69
src/utils/ImmutableObject.js
+72 -69
@@ -14,112 +14,111 @@
14 * limitations under the License.
15 *
16 * @providesModule ImmutableObject
17 + * @typechecks
18 */
19
20 "use strict";
21
21 -var keyMirror = require('keyMirror');
22 +var invariant = require('invariant');
23 var merge = require('merge');
24 var mergeInto = require('mergeInto');
25 var mergeHelpers = require('mergeHelpers');
25 -var throwIf = require('throwIf');
26
27 var checkMergeObjectArgs = mergeHelpers.checkMergeObjectArgs;
28 var isTerminal = mergeHelpers.isTerminal;
29
30 /**
31 - * Simple wrapper around javascript key/value objects that provide a dev time
32 - * guarantee of immutability (assuming all modules that may potentially mutate
33 - * include a "use strict" declaration). Retaining immutability requires CPU
34 - * cycles (in order to perform the freeze), but this computation can be avoided
35 - * in production. The fact that mutation attempts in __DEV__ will be caught,
36 - * allows us to reasonably assume that mutation on those objects won't even be
37 - * attempted in production. This means that an object being an instanceof
38 - * `ImmutableObject` implies that the object may never change.
39 - *
40 - * TODO: Require strict mode in source files that use ImmutableObject (lint
41 - * rule).
42 - *
43 - * @class ImmutableObject
31 + * Wrapper around JavaScript objects that provide a guarantee of immutability at
32 + * developer time when strict mode is used. The extra computations required to
33 + * enforce immutability is stripped out in production for performance reasons.
34 */
45 -
46 -var ERRORS;
35 var ImmutableObject;
36
49 -if (__DEV__) {
50 - ERRORS = {
51 - INVALID_MAP_SET_ARG: 'You have attempted to set fields on an object that ' +
52 - 'is not an instance of ImmutableObject'
53 - };
37 +function assertImmutableObject(immutableObject) {
38 + invariant(
39 + immutableObject instanceof ImmutableObject,
40 + 'ImmutableObject: Attempted to set fields on an object that is not an ' +
41 + 'instance of ImmutableObject.'
42 + );
43 +}
44
45 +if (__DEV__) {
46 /**
47 * Constructs an instance of `ImmutableObject`.
48 *
58 - * @param {!Object} initMap The initial set of properties.
49 + * @param {?object} initialProperties The initial set of properties.
50 * @constructor
51 */
61 - ImmutableObject = function(initMap) {
62 - mergeInto(this, initMap);
63 - deepFreeze(this, initMap);
52 + ImmutableObject = function ImmutableObject(initialProperties) {
53 + mergeInto(this, initialProperties);
54 + deepFreeze(this);
55 };
56
57 /**
67 - * Objects that are instances of `ImmutableObject` are assumed to be deep
68 - * frozen.
69 - * @param {!Object} o The object to deep freeze.
70 - * @return {!boolean} Whether or not deep freeze is needed.
58 + * Checks if an object should be deep frozen. Instances of `ImmutableObject`
59 + * are assumed to have already been deep frozen.
60 + *
61 + * @param {*} object The object to check.
62 + * @return {boolean} Whether or not deep freeze is needed.
63 */
72 - var shouldRecurseFreeze = function(o) {
73 - return (typeof o) === 'object' &&
74 - !(o instanceof ImmutableObject) && o !== null;
64 + var shouldRecurseFreeze = function(object) {
65 + return (
66 + typeof object === 'object' &&
67 + !(object instanceof ImmutableObject) &&
68 + object !== null
69 + );
70 };
71
72 /**
78 - * Freezes an object `o` deeply. Invokes `shouldRecurseFreeze` to determine if
79 - * further freezing is needed.
73 + * Freezes the supplied object deeply.
74 *
81 - * @param {!Object} o The object to freeze.
75 + * @param {*} object The object to freeze.
76 */
83 - var deepFreeze = function(o) {
84 - var prop;
85 - Object.freeze(o); // First freeze the object.
86 - for (prop in o) {
87 - var field = o[prop];
88 - if (o.hasOwnProperty(prop) && shouldRecurseFreeze(field)) {
77 + var deepFreeze = function(object) {
78 + Object.freeze(object); // First freeze the object.
79 + for (var prop in object) {
80 + var field = object[prop];
81 + if (object.hasOwnProperty(prop) && shouldRecurseFreeze(field)) {
82 deepFreeze(field);
83 }
84 }
85 };
86
87 /**
95 - * Returns a new ImmutableObject that is that is the same as the parameter
96 - * `immutableObject` but with the differences specified in `put`.
97 - * @param {!ImmutableObject} ImmutableObject The ImmutableObject object to set
98 - * fields on.
99 - * @param {!Object} put Subset of fields to merge into the returned result.
100 - * @return {!ImmutableObject} The result of merging in `put` fields.
88 + * Returns a new ImmutableObject that is identical to the supplied object but
89 + * with the supplied changes, `put`.
90 + *
91 + * @param {ImmutableObject} immutableObject Starting object.
92 + * @param {?object} put Fields to merge into the object.
93 + * @return {ImmutableObject} The result of merging in `put` fields.
94 */
95 ImmutableObject.set = function(immutableObject, put) {
103 - throwIf(
104 - !(immutableObject instanceof ImmutableObject),
105 - ERRORS.INVALID_MAP_SET_ARG
106 - );
96 + assertImmutableObject(immutableObject);
97 var totalNewFields = merge(immutableObject, put);
98 return new ImmutableObject(totalNewFields);
99 };
100
101 } else {
112 - ERRORS = keyMirror({INVALID_MAP_SET_ARG: null});
113 -
114 - ImmutableObject = function(initMap) {
115 - mergeInto(this, initMap);
102 + /**
103 + * Constructs an instance of `ImmutableObject`.
104 + *
105 + * @param {?object} initialProperties The initial set of properties.
106 + * @constructor
107 + */
108 + ImmutableObject = function ImmutableObject(initialProperties) {
109 + mergeInto(this, initialProperties);
110 };
111
112 + /**
113 + * Returns a new ImmutableObject that is identical to the supplied object but
114 + * with the supplied changes, `put`.
115 + *
116 + * @param {ImmutableObject} immutableObject Starting object.
117 + * @param {?object} put Fields to merge into the object.
118 + * @return {ImmutableObject} The result of merging in `put` fields.
119 + */
120 ImmutableObject.set = function(immutableObject, put) {
119 - throwIf(
120 - !(immutableObject instanceof ImmutableObject),
121 - ERRORS.INVALID_MAP_SET_ARG
122 - );
121 + assertImmutableObject(immutableObject);
122 var newMap = new ImmutableObject(immutableObject);
123 mergeInto(newMap, put);
124 return newMap;
@@ -127,8 +126,12 @@ if (__DEV__) {
126 }
127
128 /**
130 - * Sugar for `ImmutableObject.set(ImmutableObject, {fieldName: putField})`
131 - * @see ImmutableObject.set
129 + * Sugar for `ImmutableObject.set(ImmutableObject, {fieldName: putField})`.
130 + *
131 + * @param {ImmutableObject} immutableObject Object on which to set field.
132 + * @param {string} fieldName Name of the field to set.
133 + * @param {*} putField Value of the field to set.
134 + * @return {ImmutableObject} [description]
135 */
136 ImmutableObject.setField = function(immutableObject, fieldName, putField) {
137 var put = {};
@@ -137,15 +140,15 @@ ImmutableObject.setField = function(immutableObject, fieldName, putField) {
140 };
141
142 /**
140 - * Returns a new ImmutableObject that is that is the same as the parameter
141 - * `immutableObject` but with the differences specified in `put` recursively
142 - * applied.
143 + * Returns a new ImmutableObject that is identical to the supplied object but
144 + * with the supplied changes recursively applied.
145 + *
146 + * @param {ImmutableObject} immutableObject Object on which to set fields.
147 + * @param {object} put Fields to merge into the object.
148 + * @return {ImmutableObject} The result of merging in `put` fields.
149 */
150 ImmutableObject.setDeep = function(immutableObject, put) {
145 - throwIf(
146 - !(immutableObject instanceof ImmutableObject),
147 - ERRORS.INVALID_MAP_SET_ARG
148 - );
151 + assertImmutableObject(immutableObject);
152 return _setDeep(immutableObject, put);
153 };
154