|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 |
- # jsprim: utilities for primitive JavaScript types
-
- This module provides miscellaneous facilities for working with strings,
- numbers, dates, and objects and arrays of these basic types.
-
-
- ### deepCopy(obj)
-
- Creates a deep copy of a primitive type, object, or array of primitive types.
-
-
- ### deepEqual(obj1, obj2)
-
- Returns whether two objects are equal.
-
-
- ### isEmpty(obj)
-
- Returns true if the given object has no properties and false otherwise. This
- is O(1) (unlike `Object.keys(obj).length === 0`, which is O(N)).
-
- ### hasKey(obj, key)
-
- Returns true if the given object has an enumerable, non-inherited property
- called `key`. [For information on enumerability and ownership of properties, see
- the MDN
- documentation.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties)
-
- ### forEachKey(obj, callback)
-
- Like Array.forEach, but iterates enumerable, owned properties of an object
- rather than elements of an array. Equivalent to:
-
- for (var key in obj) {
- if (Object.prototype.hasOwnProperty.call(obj, key)) {
- callback(key, obj[key]);
- }
- }
-
-
- ### flattenObject(obj, depth)
-
- Flattens an object up to a given level of nesting, returning an array of arrays
- of length "depth + 1", where the first "depth" elements correspond to flattened
- columns and the last element contains the remaining object . For example:
-
- flattenObject({
- 'I': {
- 'A': {
- 'i': {
- 'datum1': [ 1, 2 ],
- 'datum2': [ 3, 4 ]
- },
- 'ii': {
- 'datum1': [ 3, 4 ]
- }
- },
- 'B': {
- 'i': {
- 'datum1': [ 5, 6 ]
- },
- 'ii': {
- 'datum1': [ 7, 8 ],
- 'datum2': [ 3, 4 ],
- },
- 'iii': {
- }
- }
- },
- 'II': {
- 'A': {
- 'i': {
- 'datum1': [ 1, 2 ],
- 'datum2': [ 3, 4 ]
- }
- }
- }
- }, 3)
-
- becomes:
-
- [
- [ 'I', 'A', 'i', { 'datum1': [ 1, 2 ], 'datum2': [ 3, 4 ] } ],
- [ 'I', 'A', 'ii', { 'datum1': [ 3, 4 ] } ],
- [ 'I', 'B', 'i', { 'datum1': [ 5, 6 ] } ],
- [ 'I', 'B', 'ii', { 'datum1': [ 7, 8 ], 'datum2': [ 3, 4 ] } ],
- [ 'I', 'B', 'iii', {} ],
- [ 'II', 'A', 'i', { 'datum1': [ 1, 2 ], 'datum2': [ 3, 4 ] } ]
- ]
-
- This function is strict: "depth" must be a non-negative integer and "obj" must
- be a non-null object with at least "depth" levels of nesting under all keys.
-
-
- ### flattenIter(obj, depth, func)
-
- This is similar to `flattenObject` except that instead of returning an array,
- this function invokes `func(entry)` for each `entry` in the array that
- `flattenObject` would return. `flattenIter(obj, depth, func)` is logically
- equivalent to `flattenObject(obj, depth).forEach(func)`. Importantly, this
- version never constructs the full array. Its memory usage is O(depth) rather
- than O(n) (where `n` is the number of flattened elements).
-
- There's another difference between `flattenObject` and `flattenIter` that's
- related to the special case where `depth === 0`. In this case, `flattenObject`
- omits the array wrapping `obj` (which is regrettable).
-
-
- ### pluck(obj, key)
-
- Fetch nested property "key" from object "obj", traversing objects as needed.
- For example, `pluck(obj, "foo.bar.baz")` is roughly equivalent to
- `obj.foo.bar.baz`, except that:
-
- 1. If traversal fails, the resulting value is undefined, and no error is
- thrown. For example, `pluck({}, "foo.bar")` is just undefined.
- 2. If "obj" has property "key" directly (without traversing), the
- corresponding property is returned. For example,
- `pluck({ 'foo.bar': 1 }, 'foo.bar')` is 1, not undefined. This is also
- true recursively, so `pluck({ 'a': { 'foo.bar': 1 } }, 'a.foo.bar')` is
- also 1, not undefined.
-
-
- ### randElt(array)
-
- Returns an element from "array" selected uniformly at random. If "array" is
- empty, throws an Error.
-
-
- ### startsWith(str, prefix)
-
- Returns true if the given string starts with the given prefix and false
- otherwise.
-
-
- ### endsWith(str, suffix)
-
- Returns true if the given string ends with the given suffix and false
- otherwise.
-
-
- ### parseInteger(str, options)
-
- Parses the contents of `str` (a string) as an integer. On success, the integer
- value is returned (as a number). On failure, an error is **returned** describing
- why parsing failed.
-
- By default, leading and trailing whitespace characters are not allowed, nor are
- trailing characters that are not part of the numeric representation. This
- behaviour can be toggled by using the options below. The empty string (`''`) is
- not considered valid input. If the return value cannot be precisely represented
- as a number (i.e., is smaller than `Number.MIN_SAFE_INTEGER` or larger than
- `Number.MAX_SAFE_INTEGER`), an error is returned. Additionally, the string
- `'-0'` will be parsed as the integer `0`, instead of as the IEEE floating point
- value `-0`.
-
- This function accepts both upper and lowercase characters for digits, similar to
- `parseInt()`, `Number()`, and [strtol(3C)](https://illumos.org/man/3C/strtol).
-
- The following may be specified in `options`:
-
- Option | Type | Default | Meaning
- ------------------ | ------- | ------- | ---------------------------
- base | number | 10 | numeric base (radix) to use, in the range 2 to 36
- allowSign | boolean | true | whether to interpret any leading `+` (positive) and `-` (negative) characters
- allowImprecise | boolean | false | whether to accept values that may have lost precision (past `MAX_SAFE_INTEGER` or below `MIN_SAFE_INTEGER`)
- allowPrefix | boolean | false | whether to interpret the prefixes `0b` (base 2), `0o` (base 8), `0t` (base 10), or `0x` (base 16)
- allowTrailing | boolean | false | whether to ignore trailing characters
- trimWhitespace | boolean | false | whether to trim any leading or trailing whitespace/line terminators
- leadingZeroIsOctal | boolean | false | whether a leading zero indicates octal
-
- Note that if `base` is unspecified, and `allowPrefix` or `leadingZeroIsOctal`
- are, then the leading characters can change the default base from 10. If `base`
- is explicitly specified and `allowPrefix` is true, then the prefix will only be
- accepted if it matches the specified base. `base` and `leadingZeroIsOctal`
- cannot be used together.
-
- **Context:** It's tricky to parse integers with JavaScript's built-in facilities
- for several reasons:
-
- - `parseInt()` and `Number()` by default allow the base to be specified in the
- input string by a prefix (e.g., `0x` for hex).
- - `parseInt()` allows trailing nonnumeric characters.
- - `Number(str)` returns 0 when `str` is the empty string (`''`).
- - Both functions return incorrect values when the input string represents a
- valid integer outside the range of integers that can be represented precisely.
- Specifically, `parseInt('9007199254740993')` returns 9007199254740992.
- - Both functions always accept `-` and `+` signs before the digit.
- - Some older JavaScript engines always interpret a leading 0 as indicating
- octal, which can be surprising when parsing input from users who expect a
- leading zero to be insignificant.
-
- While each of these may be desirable in some contexts, there are also times when
- none of them are wanted. `parseInteger()` grants greater control over what
- input's permissible.
-
- ### iso8601(date)
-
- Converts a Date object to an ISO8601 date string of the form
- "YYYY-MM-DDTHH:MM:SS.sssZ". This format is not customizable.
-
-
- ### parseDateTime(str)
-
- Parses a date expressed as a string, as either a number of milliseconds since
- the epoch or any string format that Date accepts, giving preference to the
- former where these two sets overlap (e.g., strings containing small numbers).
-
-
- ### hrtimeDiff(timeA, timeB)
-
- Given two hrtime readings (as from Node's `process.hrtime()`), where timeA is
- later than timeB, compute the difference and return that as an hrtime. It is
- illegal to invoke this for a pair of times where timeB is newer than timeA.
-
- ### hrtimeAdd(timeA, timeB)
-
- Add two hrtime intervals (as from Node's `process.hrtime()`), returning a new
- hrtime interval array. This function does not modify either input argument.
-
-
- ### hrtimeAccum(timeA, timeB)
-
- Add two hrtime intervals (as from Node's `process.hrtime()`), storing the
- result in `timeA`. This function overwrites (and returns) the first argument
- passed in.
-
-
- ### hrtimeNanosec(timeA), hrtimeMicrosec(timeA), hrtimeMillisec(timeA)
-
- This suite of functions converts a hrtime interval (as from Node's
- `process.hrtime()`) into a scalar number of nanoseconds, microseconds or
- milliseconds. Results are truncated, as with `Math.floor()`.
-
-
- ### validateJsonObject(schema, object)
-
- Uses JSON validation (via JSV) to validate the given object against the given
- schema. On success, returns null. On failure, *returns* (does not throw) a
- useful Error object.
-
-
- ### extraProperties(object, allowed)
-
- Check an object for unexpected properties. Accepts the object to check, and an
- array of allowed property name strings. If extra properties are detected, an
- array of extra property names is returned. If no properties other than those
- in the allowed list are present on the object, the returned array will be of
- zero length.
-
- ### mergeObjects(provided, overrides, defaults)
-
- Merge properties from objects "provided", "overrides", and "defaults". The
- intended use case is for functions that accept named arguments in an "args"
- object, but want to provide some default values and override other values. In
- that case, "provided" is what the caller specified, "overrides" are what the
- function wants to override, and "defaults" contains default values.
-
- The function starts with the values in "defaults", overrides them with the
- values in "provided", and then overrides those with the values in "overrides".
- For convenience, any of these objects may be falsey, in which case they will be
- ignored. The input objects are never modified, but properties in the returned
- object are not deep-copied.
-
- For example:
-
- mergeObjects(undefined, { 'objectMode': true }, { 'highWaterMark': 0 })
-
- returns:
-
- { 'objectMode': true, 'highWaterMark': 0 }
-
- For another example:
-
- mergeObjects(
- { 'highWaterMark': 16, 'objectMode': 7 }, /* from caller */
- { 'objectMode': true }, /* overrides */
- { 'highWaterMark': 0 }); /* default */
-
- returns:
-
- { 'objectMode': true, 'highWaterMark': 16 }
-
-
- # Contributing
-
- See separate [contribution guidelines](CONTRIBUTING.md).
|