/** * Copyright (c) 2013-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * */ 'use strict'; // eslint-disable-line strict /** * Traverses properties on objects and arrays. If an intermediate property is * either null or undefined, it is instead returned. The purpose of this method * is to simplify extracting properties from a chain of maybe-typed properties. * * === EXAMPLE === * * Consider the following type: * * const props: { * user: ?{ * name: string, * friends: ?Array, * } * }; * * Getting to the friends of my first friend would resemble: * * props.user && * props.user.friends && * props.user.friends[0] && * props.user.friends[0].friends * * Instead, `idx` allows us to safely write: * * idx(props, _ => _.user.friends[0].friends) * * The second argument must be a function that returns one or more nested member * expressions. Any other expression has undefined behavior. * * === NOTE === * * The code below exists for the purpose of illustrating expected behavior and * is not meant to be executed. The `idx` function is used in conjunction with a * Babel transform that replaces it with better performing code: * * props.user == null ? props.user : * props.user.friends == null ? props.user.friends : * props.user.friends[0] == null ? props.user.friends[0] : * props.user.friends[0].friends * * All this machinery exists due to the fact that an existential operator does * not currently exist in JavaScript. */ function idx(input, accessor) { try { return accessor(input); } catch (error) { if (error instanceof TypeError) { if (nullPattern.test(error)) { return null; } else if (undefinedPattern.test(error)) { return undefined; } } throw error; } } /** * Some actual error messages for null: * * TypeError: Cannot read property 'bar' of null * TypeError: Cannot convert null value to object * TypeError: foo is null * TypeError: null has no properties * TypeError: null is not an object (evaluating 'foo.bar') * TypeError: null is not an object (evaluating '(" undefined ", null).bar') */ var nullPattern = /^null | null$|^[^(]* null /; var undefinedPattern = /^undefined | undefined$|^[^(]* undefined /; idx.default = idx; module.exports = idx;