Initial commit
[yaffs-website] / node_modules / jsprim / README.md
1 # jsprim: utilities for primitive JavaScript types
2
3 This module provides miscellaneous facilities for working with strings,
4 numbers, dates, and objects and arrays of these basic types.
5
6
7 ### deepCopy(obj)
8
9 Creates a deep copy of a primitive type, object, or array of primitive types.
10
11
12 ### deepEqual(obj1, obj2)
13
14 Returns whether two objects are equal.
15
16
17 ### isEmpty(obj)
18
19 Returns true if the given object has no properties and false otherwise.  This
20 is O(1) (unlike `Object.keys(obj).length === 0`, which is O(N)).
21
22 ### hasKey(obj, key)
23
24 Returns true if the given object has an enumerable, non-inherited property
25 called `key`.  [For information on enumerability and ownership of properties, see
26 the MDN
27 documentation.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties)
28
29 ### forEachKey(obj, callback)
30
31 Like Array.forEach, but iterates enumerable, owned properties of an object
32 rather than elements of an array.  Equivalent to:
33
34     for (var key in obj) {
35             if (Object.prototype.hasOwnProperty.call(obj, key)) {
36                     callback(key, obj[key]);
37             }
38     }
39
40
41 ### flattenObject(obj, depth)
42
43 Flattens an object up to a given level of nesting, returning an array of arrays
44 of length "depth + 1", where the first "depth" elements correspond to flattened
45 columns and the last element contains the remaining object .  For example:
46
47     flattenObject({
48         'I': {
49             'A': {
50                 'i': {
51                     'datum1': [ 1, 2 ],
52                     'datum2': [ 3, 4 ]
53                 },
54                 'ii': {
55                     'datum1': [ 3, 4 ]
56                 }
57             },
58             'B': {
59                 'i': {
60                     'datum1': [ 5, 6 ]
61                 },
62                 'ii': {
63                     'datum1': [ 7, 8 ],
64                     'datum2': [ 3, 4 ],
65                 },
66                 'iii': {
67                 }
68             }
69         },
70         'II': {
71             'A': {
72                 'i': {
73                     'datum1': [ 1, 2 ],
74                     'datum2': [ 3, 4 ]
75                 }
76             }
77         }
78     }, 3)
79
80 becomes:
81
82     [
83         [ 'I',  'A', 'i',   { 'datum1': [ 1, 2 ], 'datum2': [ 3, 4 ] } ],
84         [ 'I',  'A', 'ii',  { 'datum1': [ 3, 4 ] } ],
85         [ 'I',  'B', 'i',   { 'datum1': [ 5, 6 ] } ],
86         [ 'I',  'B', 'ii',  { 'datum1': [ 7, 8 ], 'datum2': [ 3, 4 ] } ],
87         [ 'I',  'B', 'iii', {} ],
88         [ 'II', 'A', 'i',   { 'datum1': [ 1, 2 ], 'datum2': [ 3, 4 ] } ]
89     ]
90
91 This function is strict: "depth" must be a non-negative integer and "obj" must
92 be a non-null object with at least "depth" levels of nesting under all keys.
93
94
95 ### flattenIter(obj, depth, func)
96
97 This is similar to `flattenObject` except that instead of returning an array,
98 this function invokes `func(entry)` for each `entry` in the array that
99 `flattenObject` would return.  `flattenIter(obj, depth, func)` is logically
100 equivalent to `flattenObject(obj, depth).forEach(func)`.  Importantly, this
101 version never constructs the full array.  Its memory usage is O(depth) rather
102 than O(n) (where `n` is the number of flattened elements).
103
104 There's another difference between `flattenObject` and `flattenIter` that's
105 related to the special case where `depth === 0`.  In this case, `flattenObject`
106 omits the array wrapping `obj` (which is regrettable).
107
108
109 ### pluck(obj, key)
110
111 Fetch nested property "key" from object "obj", traversing objects as needed.
112 For example, `pluck(obj, "foo.bar.baz")` is roughly equivalent to
113 `obj.foo.bar.baz`, except that:
114
115 1. If traversal fails, the resulting value is undefined, and no error is
116    thrown.  For example, `pluck({}, "foo.bar")` is just undefined.
117 2. If "obj" has property "key" directly (without traversing), the
118    corresponding property is returned.  For example,
119    `pluck({ 'foo.bar': 1 }, 'foo.bar')` is 1, not undefined.  This is also
120    true recursively, so `pluck({ 'a': { 'foo.bar': 1 } }, 'a.foo.bar')` is
121    also 1, not undefined.
122
123
124 ### randElt(array)
125
126 Returns an element from "array" selected uniformly at random.  If "array" is
127 empty, throws an Error.
128
129
130 ### startsWith(str, prefix)
131
132 Returns true if the given string starts with the given prefix and false
133 otherwise.
134
135
136 ### endsWith(str, suffix)
137
138 Returns true if the given string ends with the given suffix and false
139 otherwise.
140
141
142 ### iso8601(date)
143
144 Converts a Date object to an ISO8601 date string of the form
145 "YYYY-MM-DDTHH:MM:SS.sssZ".  This format is not customizable.
146
147
148 ### parseDateTime(str)
149
150 Parses a date expressed as a string, as either a number of milliseconds since
151 the epoch or any string format that Date accepts, giving preference to the
152 former where these two sets overlap (e.g., strings containing small numbers).
153
154
155 ### hrtimeDiff(timeA, timeB)
156
157 Given two hrtime readings (as from Node's `process.hrtime()`), where timeA is
158 later than timeB, compute the difference and return that as an hrtime.  It is
159 illegal to invoke this for a pair of times where timeB is newer than timeA.
160
161 ### hrtimeAdd(timeA, timeB)
162
163 Add two hrtime intervals (as from Node's `process.hrtime()`), returning a new
164 hrtime interval array.  This function does not modify either input argument.
165
166
167 ### hrtimeAccum(timeA, timeB)
168
169 Add two hrtime intervals (as from Node's `process.hrtime()`), storing the
170 result in `timeA`.  This function overwrites (and returns) the first argument
171 passed in.
172
173
174 ### hrtimeNanosec(timeA), hrtimeMicrosec(timeA), hrtimeMillisec(timeA)
175
176 This suite of functions converts a hrtime interval (as from Node's
177 `process.hrtime()`) into a scalar number of nanoseconds, microseconds or
178 milliseconds.  Results are truncated, as with `Math.floor()`.
179
180
181 ### validateJsonObject(schema, object)
182
183 Uses JSON validation (via JSV) to validate the given object against the given
184 schema.  On success, returns null.  On failure, *returns* (does not throw) a
185 useful Error object.
186
187
188 ### extraProperties(object, allowed)
189
190 Check an object for unexpected properties.  Accepts the object to check, and an
191 array of allowed property name strings.  If extra properties are detected, an
192 array of extra property names is returned.  If no properties other than those
193 in the allowed list are present on the object, the returned array will be of
194 zero length.
195
196 ### mergeObjects(provided, overrides, defaults)
197
198 Merge properties from objects "provided", "overrides", and "defaults".  The
199 intended use case is for functions that accept named arguments in an "args"
200 object, but want to provide some default values and override other values.  In
201 that case, "provided" is what the caller specified, "overrides" are what the
202 function wants to override, and "defaults" contains default values.
203
204 The function starts with the values in "defaults", overrides them with the
205 values in "provided", and then overrides those with the values in "overrides".
206 For convenience, any of these objects may be falsey, in which case they will be
207 ignored.  The input objects are never modified, but properties in the returned
208 object are not deep-copied.
209
210 For example:
211
212     mergeObjects(undefined, { 'objectMode': true }, { 'highWaterMark': 0 })
213
214 returns:
215
216     { 'objectMode': true, 'highWaterMark': 0 }
217
218 For another example:
219
220     mergeObjects(
221         { 'highWaterMark': 16, 'objectMode': 7 }, /* from caller */
222         { 'objectMode': true },                   /* overrides */
223         { 'highWaterMark': 0 });                  /* default */
224
225 returns:
226
227     { 'objectMode': true, 'highWaterMark': 16 }
228
229
230 # Contributing
231
232 Code should be "make check" clean.  This target assumes that
233 [jsl](http://github.com/davepacheco/javascriptlint) and
234 [jsstyle](http://github.com/davepacheco/jsstyle) are on your path.
235
236 New tests should generally accompany new functions and bug fixes.  The tests
237 should pass cleanly (run tests/basic.js).