@samitouri / QOS-React-2 / commits / bdf2a9bb12
Fork 0

The library for web and native user interfaces.

Use `invariant` in `react/utils`

Just some therapeutic cleanup.

Tim Yung committed Jul 24, 2013 at 17:19 UTC bdf2a9bb124b8fc34120949b322202497741f239
10 files changed +147 -221
src/utils/OrderedMap.js
-2
@@ -85,8 +85,6 @@ function OrderedMapImpl(normalizedObj, computedLength) {
85 * Validates a "public" key - that is, one that the public facing API supplies.
86 * The key is then normalized for internal storage. In order to be considered
87 * valid, all keys must be non-empty, defined, non-null strings or numbers.
88 - * Since this already costs a function invocation, will avoid additional call to
89 - * `throwIf`.
88 *
89 * @param {string?} key Validates that the key is suitable for use in a
90 * `OrderedMap`.
src/utils/Transaction.js
+37 -38
@@ -18,23 +18,7 @@
18
19 "use strict";
20
21 -var throwIf = require('throwIf');
22 -
23 -var DUAL_TRANSACTION = 'DUAL_TRANSACTION';
24 -var MISSING_TRANSACTION = 'MISSING_TRANSACTION';
25 -if (__DEV__) {
26 - DUAL_TRANSACTION =
27 - 'Cannot initialize transaction when there is already an outstanding ' +
28 - 'transaction. Common causes of this are trying to render a component ' +
29 - 'when you are already rendering a component or attempting a state ' +
30 - 'transition while in a render function. Another possibility is that ' +
31 - 'you are rendering new content (or state transitioning) in a ' +
32 - 'componentDidRender callback. If this is not the case, please report the ' +
33 - 'issue immediately.';
34 -
35 - MISSING_TRANSACTION =
36 - 'Cannot close transaction when there is none open.';
37 -}
21 +var invariant = require('invariant');
22
23 /**
24 * `Transaction` creates a black box that is able to wrap any method such that
@@ -156,26 +140,33 @@ var Mixin = {
140 * @return Return value from `method`.
141 */
142 perform: function(method, scope, a, b, c, d, e, f) {
159 - throwIf(this.isInTransaction(), DUAL_TRANSACTION);
143 + invariant(
144 + !this.isInTransaction(),
145 + 'Transaction.perform(...): Cannot initialize a transaction when there ' +
146 + 'is already an outstanding transaction.'
147 + );
148 var memberStart = Date.now();
161 - var err = null;
149 + var errorToThrow = null;
150 var ret;
151 try {
152 this.initializeAll();
153 ret = method.call(scope, a, b, c, d, e, f);
166 - } catch (ie_requires_catch) {
167 - err = ie_requires_catch;
154 + } catch (error) {
155 + // IE8 requires `catch` in order to use `finally`.
156 + errorToThrow = error;
157 } finally {
158 var memberEnd = Date.now();
159 this.methodInvocationTime += (memberEnd - memberStart);
160 try {
161 this.closeAll();
173 - } catch (closeAllErr) {
174 - err = err || closeAllErr;
162 + } catch (closeError) {
163 + // If `method` throws, prefer to show that stack trace over any thrown
164 + // by invoking `closeAll`.
165 + errorToThrow = errorToThrow || closeError;
166 }
167 }
177 - if (err) {
178 - throw err;
168 + if (errorToThrow) {
169 + throw errorToThrow;
170 }
171 return ret;
172 },
@@ -184,15 +175,17 @@ var Mixin = {
175 this._isInTransaction = true;
176 var transactionWrappers = this.transactionWrappers;
177 var wrapperInitTimes = this.timingMetrics.wrapperInitTimes;
187 - var err = null;
178 + var errorToThrow = null;
179 for (var i = 0; i < transactionWrappers.length; i++) {
180 var initStart = Date.now();
181 var wrapper = transactionWrappers[i];
182 try {
192 - this.wrapperInitData[i] =
193 - wrapper.initialize ? wrapper.initialize.call(this) : null;
194 - } catch (initErr) {
195 - err = err || initErr; // Remember the first error.
183 + this.wrapperInitData[i] = wrapper.initialize ?
184 + wrapper.initialize.call(this) :
185 + null;
186 + } catch (initError) {
187 + // Prefer to show the stack trace of the first error.
188 + errorToThrow = errorToThrow || initError;
189 this.wrapperInitData[i] = Transaction.OBSERVED_ERROR;
190 } finally {
191 var curInitTime = wrapperInitTimes[i];
@@ -200,8 +193,8 @@ var Mixin = {
193 wrapperInitTimes[i] = (curInitTime || 0) + (initEnd - initStart);
194 }
195 }
203 - if (err) {
204 - throw err;
196 + if (errorToThrow) {
197 + throw errorToThrow;
198 }
199 },
200
@@ -212,10 +205,13 @@ var Mixin = {
205 * invoked).
206 */
207 closeAll: function() {
215 - throwIf(!this.isInTransaction(), MISSING_TRANSACTION);
208 + invariant(
209 + this.isInTransaction(),
210 + 'Transaction.closeAll(): Cannot close transaction when none are open.'
211 + );
212 var transactionWrappers = this.transactionWrappers;
213 var wrapperCloseTimes = this.timingMetrics.wrapperCloseTimes;
218 - var err = null;
214 + var errorToThrow = null;
215 for (var i = 0; i < transactionWrappers.length; i++) {
216 var wrapper = transactionWrappers[i];
217 var closeStart = Date.now();
@@ -224,8 +220,9 @@ var Mixin = {
220 if (initData !== Transaction.OBSERVED_ERROR) {
221 wrapper.close && wrapper.close.call(this, initData);
222 }
227 - } catch (closeErr) {
228 - err = err || closeErr; // Remember the first error.
223 + } catch (closeError) {
224 + // Prefer to show the stack trace of the first error.
225 + errorToThrow = errorToThrow || closeError;
226 } finally {
227 var closeEnd = Date.now();
228 var curCloseTime = wrapperCloseTimes[i];
@@ -234,14 +231,16 @@ var Mixin = {
231 }
232 this.wrapperInitData.length = 0;
233 this._isInTransaction = false;
237 - if (err) {
238 - throw err;
234 + if (errorToThrow) {
235 + throw errorToThrow;
236 }
237 }
238 };
239
240 var Transaction = {
241 +
242 Mixin: Mixin,
243 +
244 /**
245 * Token to look for to determine if an error occured.
246 */
src/utils/accumulate.js
+22 -38
@@ -18,50 +18,34 @@
18
19 "use strict";
20
21 -var throwIf = require('throwIf');
22 -
23 -var INVALID_ARGS = 'INVALID_ACCUM_ARGS';
24 -
25 -if (__DEV__) {
26 - INVALID_ARGS =
27 - 'accumulate requires non empty (non-null, defined) next ' +
28 - 'values. All arrays accumulated must not contain any empty items.';
29 -}
21 +var invariant = require('invariant');
22
23 /**
32 - * Accumulates items that must never be empty, into a result in a manner that
33 - * conserves memory - avoiding allocation of arrays until they are needed. The
34 - * accumulation may start and/or end up being a single element or an array
35 - * depending on the total count (if greater than one, an array is allocated).
36 - * Handles most common case first (starting with an empty current value and
37 - * acquiring one).
38 - * @return {Accumulation} An accumulation which is either a single item or an
39 - * Array of items.
24 + * Accumulates items that must not be null or undefined.
25 + *
26 + * This is used to conserve memory by avoiding array allocations.
27 + *
28 + * @return {*|array<*>} An accumulation of items.
29 */
41 -function accumulate(cur, next) {
42 - var curValIsEmpty = cur == null; // Will test for emptiness (null/undef)
43 - var nextValIsEmpty = next === null;
44 - if (__DEV__) {
45 - throwIf(nextValIsEmpty, INVALID_ARGS);
46 - }
47 - if (nextValIsEmpty) {
48 - return cur;
30 +function accumulate(current, next) {
31 + invariant(
32 + next != null,
33 + 'accumulate(...): Accumulated items must be not be null or undefined.'
34 + );
35 + if (current == null) {
36 + return next;
37 } else {
50 - if (curValIsEmpty) {
51 - return next;
38 + // Both are not empty. Warning: Never call x.concat(y) when you are not
39 + // certain that x is an Array (x could be a string with concat method).
40 + var currentIsArray = Array.isArray(current);
41 + var nextIsArray = Array.isArray(next);
42 + if (currentIsArray) {
43 + return current.concat(next);
44 } else {
53 - // Both are not empty. Warning: Never call x.concat(y) when you are not
54 - // certain that x is an Array (x could be a string with concat method).
55 - var curIsArray = Array.isArray(cur);
56 - var nextIsArray = Array.isArray(next);
57 - if (curIsArray) {
58 - return cur.concat(next);
45 + if (nextIsArray) {
46 + return [current].concat(next);
47 } else {
60 - if (nextIsArray) {
61 - return [cur].concat(next);
62 - } else {
63 - return [cur, next];
64 - }
48 + return [current, next];
49 }
50 }
51 }
src/utils/escapeTextForBrowser.js
+15 -16
@@ -14,19 +14,12 @@
14 * limitations under the License.
15 *
16 * @providesModule escapeTextForBrowser
17 + * @typechecks static-only
18 */
19
20 "use strict";
21
21 -var throwIf = require('throwIf');
22 -
23 -var ESCAPE_TYPE_ERR;
24 -
25 -if (__DEV__) {
26 - ESCAPE_TYPE_ERR =
27 - 'The React core has attempted to escape content that is of a ' +
28 - 'mysterious type (object etc) Escaping only works on numbers and strings';
29 -}
22 +var invariant = require('invariant');
23
24 var ESCAPE_LOOKUP = {
25 "&": "&amp;",
@@ -41,13 +34,19 @@ function escaper(match) {
34 return ESCAPE_LOOKUP[match];
35 }
36
44 -var escapeTextForBrowser = function (text) {
37 +/**
38 + * Escapes text to prevent scripting attacks.
39 + *
40 + * @param {number|string} text Text value to escape.
41 + * @return {string} An escaped string.
42 + */
43 +function escapeTextForBrowser(text) {
44 var type = typeof text;
46 - var invalid = type === 'object';
47 - if (__DEV__) {
48 - throwIf(invalid, ESCAPE_TYPE_ERR);
49 - }
50 - if (text === '' || invalid) {
45 + invariant(
46 + type !== 'object',
47 + 'escapeTextForBrowser(...): Attempted to escape an object.'
48 + );
49 + if (text === '') {
50 return '';
51 } else {
52 if (type === 'string') {
@@ -56,6 +55,6 @@ var escapeTextForBrowser = function (text) {
55 return (''+text).replace(/[&><"'\/]/g, escaper);
56 }
57 }
59 -};
58 +}
59
60 module.exports = escapeTextForBrowser;
src/utils/flattenChildren.js
+9 -9
@@ -18,7 +18,7 @@
18
19 "use strict";
20
21 -var throwIf = require('throwIf');
21 +var invariant = require('invariant');
22 var traverseAllChildren = require('traverseAllChildren');
23
24 /**
@@ -27,14 +27,14 @@ var traverseAllChildren = require('traverseAllChildren');
27 * @param {!string} name String name of key path to child.
28 */
29 function flattenSingleChildIntoContext(traverseContext, child, name) {
30 - // We found a component instance
30 + // We found a component instance.
31 var result = traverseContext;
32 - if (__DEV__) {
33 - throwIf(
34 - result.hasOwnProperty(name),
35 - traverseAllChildren.DUPLICATE_KEY_ERROR
36 - );
37 - }
32 + invariant(
33 + !result.hasOwnProperty(name),
34 + 'flattenChildren(...): Encountered two children with the same key, `%s`. ' +
35 + 'Children keys must be unique.',
36 + name
37 + );
38 result[name] = child;
39 }
40
@@ -43,7 +43,7 @@ function flattenSingleChildIntoContext(traverseContext, child, name) {
43 * @return {!object} flattened children keyed by name.
44 */
45 function flattenChildren(children) {
46 - if (children === null || children === undefined) {
46 + if (children == null) {
47 return children;
48 }
49 var result = {};
src/utils/keyMirror.js
+20 -18
@@ -14,36 +14,38 @@
14 * limitations under the License.
15 *
16 * @providesModule keyMirror
17 + * @typechecks static-only
18 */
19
20 "use strict";
21
21 -var throwIf = require('throwIf');
22 -
23 -var NOT_OBJECT_ERROR = 'NOT_OBJECT_ERROR';
24 -if (__DEV__) {
25 - NOT_OBJECT_ERROR = 'keyMirror only works on objects';
26 -}
22 +var invariant = require('invariant');
23
24 /**
29 - * Utility for constructing enums with keys being equal to the associated
30 - * values, even when using advanced key crushing. This is useful for debugging,
31 - * but also for using the values themselves as lookups into the enum.
32 - * Example:
33 - * var COLORS = keyMirror({blue: null, red: null});
34 - * var myColor = COLORS.blue;
35 - * var isColorValid = !!COLORS[myColor]
25 + * Constructs an enumeration with keys equal to their value.
26 + *
27 + * For example:
28 + *
29 + * var COLORS = keyMirror({blue: null, red: null});
30 + * var myColor = COLORS.blue;
31 + * var isColorValid = !!COLORS[myColor];
32 + *
33 * The last line could not be performed if the values of the generated enum were
34 * not equal to their keys.
38 - * Input: {key1: val1, key2: val2}
39 - * Output: {key1: key1, key2: key2}
35 + *
36 + * Input: {key1: val1, key2: val2}
37 + * Output: {key1: key1, key2: key2}
38 + *
39 + * @param {object} obj
40 + * @return {object}
41 */
42 var keyMirror = function(obj) {
43 var ret = {};
44 var key;
44 -
45 - throwIf(!(obj instanceof Object) || Array.isArray(obj), NOT_OBJECT_ERROR);
46 -
45 + invariant(
46 + obj instanceof Object && !Array.isArray(obj),
47 + 'keyMirror(...): Argument must be an object.'
48 + );
49 for (key in obj) {
50 if (!obj.hasOwnProperty(key)) {
51 continue;
src/utils/mapAllChildren.js
+8 -8
@@ -20,7 +20,7 @@
20
21 var PooledClass = require('PooledClass');
22
23 -var throwIf = require('throwIf');
23 +var invariant = require('invariant');
24 var traverseAllChildren = require('traverseAllChildren');
25
26 var threeArgumentPooler = PooledClass.threeArgumentPooler;
@@ -50,13 +50,13 @@ function mapSingleChildIntoContext(traverseContext, child, name, i) {
50 var mapFunction = mapBookKeeping.mapFunction;
51 var mapContext = mapBookKeeping.mapContext;
52 var mappedChild = mapFunction.call(mapContext, child, name, i);
53 - // We found a component instance
54 - if (__DEV__) {
55 - throwIf(
56 - mapResult.hasOwnProperty(name),
57 - traverseAllChildren.DUPLICATE_KEY_ERROR
58 - );
59 - }
53 + // We found a component instance.
54 + invariant(
55 + !mapResult.hasOwnProperty(name),
56 + 'mapAllChildren(...): Encountered two children with the same key, `%s`. ' +
57 + 'Children keys must be unique.',
58 + name
59 + );
60 mapResult[name] = mappedChild;
61 }
62
src/utils/mergeDeepInto.js
+6 -20
@@ -21,9 +21,8 @@
21
22 "use strict";
23
24 -var keyMirror = require('keyMirror');
24 +var invariant = require('invariant');
25 var mergeHelpers = require('mergeHelpers');
26 -var throwIf = require('throwIf');
26
27 var ArrayStrategies = mergeHelpers.ArrayStrategies;
28 var checkArrayStrategy = mergeHelpers.checkArrayStrategy;
@@ -33,20 +32,6 @@ var checkMergeObjectArgs = mergeHelpers.checkMergeObjectArgs;
32 var isTerminal = mergeHelpers.isTerminal;
33 var normalizeMergeArg = mergeHelpers.normalizeMergeArg;
34
36 -var ERRORS = keyMirror({
37 - RUN_TIME_ARRAY_MERGE_FAIL: null
38 -});
39 -
40 -if (__DEV__) {
41 - ERRORS = {
42 - RUN_TIME_ARRAY_MERGE_FAIL:
43 - "The caller has not supplied an ArrayStrategy. This is supported as " +
44 - "long as the data structures being merged do not contain two Arrays " +
45 - "that must be merged together, which is exactly what has just " +
46 - "happened. Change the call site to supply an Array merge resolver."
47 - };
48 -}
49 -
35 /**
36 * Every deep merge function must handle merging in each of the following cases
37 * at every level. We may refer to letters below in implementations. For each
@@ -161,9 +146,10 @@ var mergeSingleFieldDeep = function(one, two, key, arrayStrategy, level) {
146 if (twoValIsTerminal) { // [E]
147 one[key] = twoVal;
148 } else if (twoValIsArray) { // [F]
164 - throwIf(
165 - !ArrayStrategies[arrayStrategy],
166 - ERRORS.RUN_TIME_ARRAY_MERGE_FAIL
149 + invariant(
150 + ArrayStrategies[arrayStrategy],
151 + 'mergeDeepInto(...): Attempted to merge two arrays, but a valid ' +
152 + 'ArrayStrategy was not specified.'
153 );
154 // Else: At this point, the only other valid option is `IndexByIndex`
155 if (arrayStrategy === ArrayStrategies.Clobber) {
@@ -234,7 +220,7 @@ var mergeSingleFieldDeep = function(one, two, key, arrayStrategy, level) {
220 */
221 var mergeDeepInto = function(one, twoParam, arrayStrategy) {
222 var two = normalizeMergeArg(twoParam);
237 - checkArrayStrategy(arrayStrategy); // Will be checked twice, for now
223 + checkArrayStrategy(arrayStrategy); // Will be checked twice, for now.
224 mergeDeepIntoObjects(one, two, arrayStrategy, 0);
225 };
226
src/utils/mergeHelpers.js
+24 -49
@@ -20,8 +20,8 @@
20
21 "use strict";
22
23 +var invariant = require('invariant');
24 var keyMirror = require('keyMirror');
24 -var throwIf = require('throwIf');
25
26 /**
27 * Maximum number of levels to traverse. Will catch circular structures.
@@ -29,41 +29,6 @@ var throwIf = require('throwIf');
29 */
30 var MAX_MERGE_DEPTH = 36;
31
32 -var ERRORS = keyMirror({
33 - MERGE_ARRAY_FAIL: null,
34 - MERGE_CORE_FAILURE: null,
35 - MERGE_TYPE_USAGE_FAILURE: null,
36 - MERGE_DEEP_MAX_LEVELS: null,
37 - MERGE_DEEP_NO_ARR_STRATEGY: null
38 -});
39 -
40 -if (__DEV__) {
41 - ERRORS = {
42 - MERGE_ARRAY_FAIL:
43 - 'Unsupported type passed to a merge function. You may have passed a ' +
44 - 'structure that contains an array and the merge function does not know ' +
45 - 'how to merge arrays. ',
46 -
47 - MERGE_CORE_FAILURE:
48 - 'Critical assumptions about the merge functions have been violated. ' +
49 - 'This is the fault of the merge functions themselves, not necessarily ' +
50 - 'the callers.',
51 -
52 - MERGE_TYPE_USAGE_FAILURE:
53 - 'Calling merge function with invalid types. You may call merge ' +
54 - 'functions (non-array non-terminal) OR (null/undefined) arguments. ' +
55 - 'mergeInto functions have the same requirements but with an added ' +
56 - 'restriction that the first parameter must not be null/undefined.',
57 -
58 - MERGE_DEEP_MAX_LEVELS:
59 - 'Maximum deep merge depth exceeded. You may attempting to merge ' +
60 - 'circular structures in an unsupported way.',
61 - MERGE_DEEP_NO_ARR_STRATEGY:
62 - 'You must provide an array strategy to deep merge functions to ' +
63 - 'instruct the deep merge how to resolve merging two arrays.'
64 - };
65 -}
66 -
32 /**
33 * We won't worry about edge cases like new String('x') or new Boolean(true).
34 * Functions are considered terminals, and arrays are not.
@@ -99,9 +64,11 @@ var mergeHelpers = {
64 * @param {*} two Array to merge from.
65 */
66 checkMergeArrayArgs: function(one, two) {
102 - throwIf(
103 - !Array.isArray(one) || !Array.isArray(two),
104 - ERRORS.MERGE_CORE_FAILURE
67 + invariant(
68 + Array.isArray(one) && Array.isArray(two),
69 + 'Critical assumptions about the merge functions have been violated. ' +
70 + 'This is the fault of the merge functions themselves, not necessarily ' +
71 + 'the callers.'
72 );
73 },
74
@@ -118,7 +85,12 @@ var mergeHelpers = {
85 * @param {*} arg
86 */
87 checkMergeObjectArg: function(arg) {
121 - throwIf(isTerminal(arg) || Array.isArray(arg), ERRORS.MERGE_CORE_FAILURE);
88 + invariant(
89 + !isTerminal(arg) && !Array.isArray(arg),
90 + 'Critical assumptions about the merge functions have been violated. ' +
91 + 'This is the fault of the merge functions themselves, not necessarily ' +
92 + 'the callers.'
93 + );
94 },
95
96 /**
@@ -128,19 +100,23 @@ var mergeHelpers = {
100 * @param {number} Level of recursion to validate against maximum.
101 */
102 checkMergeLevel: function(level) {
131 - throwIf(level >= MAX_MERGE_DEPTH, ERRORS.MERGE_DEEP_MAX_LEVELS);
103 + invariant(
104 + level < MAX_MERGE_DEPTH,
105 + 'Maximum deep merge depth exceeded. You may be attempting to merge ' +
106 + 'circular structures in an unsupported way.'
107 + );
108 },
109
110 /**
135 - * Checks that a merge was not given a circular object or an object that had
136 - * too great of depth.
111 + * Checks that the supplied merge strategy is valid.
112 *
138 - * @param {number} Level of recursion to validate against maximum.
113 + * @param {string} Array merge strategy.
114 */
115 checkArrayStrategy: function(strategy) {
141 - throwIf(
142 - strategy !== undefined && !(strategy in mergeHelpers.ArrayStrategies),
143 - ERRORS.MERGE_DEEP_NO_ARR_STRATEGY
116 + invariant(
117 + strategy === undefined || strategy in mergeHelpers.ArrayStrategies,
118 + 'You must provide an array strategy to deep merge functions to ' +
119 + 'instruct the deep merge how to resolve merging two arrays.'
120 );
121 },
122
@@ -154,9 +130,8 @@ var mergeHelpers = {
130 ArrayStrategies: keyMirror({
131 Clobber: true,
132 IndexByIndex: true
157 - }),
133 + })
134
159 - ERRORS: ERRORS
135 };
136
137 module.exports = mergeHelpers;
src/utils/traverseAllChildren.js
+6 -23
@@ -21,22 +21,7 @@
21 var ReactComponent = require('ReactComponent');
22 var ReactTextComponent = require('ReactTextComponent');
23
24 -var throwIf = require('throwIf');
25 -
26 -/**
27 - * @polyFill Array.isArray
28 - */
29 -var DUPLICATE_KEY_ERROR = 'DUPLICATE_KEY_ERROR';
30 -var INVALID_CHILD = 'INVALID_CHILD';
31 -if (__DEV__) {
32 - INVALID_CHILD =
33 - 'You may not pass a child of that type to a React component. It ' +
34 - 'is a common mistake to try to pass a standard browser DOM element ' +
35 - 'as a child of a React component.';
36 - DUPLICATE_KEY_ERROR =
37 - 'You have two children with identical keys. Make sure that you set the ' +
38 - '"key" property to a unique value such as a row ID.';
39 -}
24 +var invariant = require('invariant');
25
26 /**
27 * TODO: Test that:
@@ -88,7 +73,11 @@ var traverseAllChildrenImpl =
73 subtreeCount = 1;
74 } else {
75 if (type === 'object') {
91 - throwIf(children && children.nodeType === 1, INVALID_CHILD);
76 + invariant(
77 + children || children.nodeType !== 1,
78 + 'traverseAllChildren(...): Encountered an invalid child; DOM ' +
79 + 'elements are not valid children of React components.'
80 + );
81 for (var key in children) {
82 if (children.hasOwnProperty(key)) {
83 subtreeCount += traverseAllChildrenImpl(
@@ -135,10 +124,4 @@ function traverseAllChildren(children, callback, traverseContext) {
124 }
125 }
126
138 -/**
139 - * Export the error code for use in other walking/mapping code.
140 - */
141 -traverseAllChildren.DUPLICATE_KEY_ERROR = DUPLICATE_KEY_ERROR;
142 -
143 -
127 module.exports = traverseAllChildren;