"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/jsprim/lib/jsprim.js" (8 Mar 2017, 11299 Bytes) of package /windows/misc/atom-windows.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Javascript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /*
    2  * lib/jsprim.js: utilities for primitive JavaScript types
    3  */
    4 
    5 var mod_assert = require('assert');
    6 var mod_util = require('util');
    7 
    8 var mod_extsprintf = require('extsprintf');
    9 var mod_verror = require('verror');
   10 var mod_jsonschema = require('json-schema');
   11 
   12 /*
   13  * Public interface
   14  */
   15 exports.deepCopy = deepCopy;
   16 exports.deepEqual = deepEqual;
   17 exports.isEmpty = isEmpty;
   18 exports.hasKey = hasKey;
   19 exports.forEachKey = forEachKey;
   20 exports.pluck = pluck;
   21 exports.flattenObject = flattenObject;
   22 exports.flattenIter = flattenIter;
   23 exports.validateJsonObject = validateJsonObjectJS;
   24 exports.validateJsonObjectJS = validateJsonObjectJS;
   25 exports.randElt = randElt;
   26 exports.extraProperties = extraProperties;
   27 exports.mergeObjects = mergeObjects;
   28 
   29 exports.startsWith = startsWith;
   30 exports.endsWith = endsWith;
   31 
   32 exports.iso8601 = iso8601;
   33 exports.rfc1123 = rfc1123;
   34 exports.parseDateTime = parseDateTime;
   35 
   36 exports.hrtimediff = hrtimeDiff;
   37 exports.hrtimeDiff = hrtimeDiff;
   38 exports.hrtimeAccum = hrtimeAccum;
   39 exports.hrtimeAdd = hrtimeAdd;
   40 exports.hrtimeNanosec = hrtimeNanosec;
   41 exports.hrtimeMicrosec = hrtimeMicrosec;
   42 exports.hrtimeMillisec = hrtimeMillisec;
   43 
   44 
   45 /*
   46  * Deep copy an acyclic *basic* Javascript object.  This only handles basic
   47  * scalars (strings, numbers, booleans) and arbitrarily deep arrays and objects
   48  * containing these.  This does *not* handle instances of other classes.
   49  */
   50 function deepCopy(obj)
   51 {
   52     var ret, key;
   53     var marker = '__deepCopy';
   54 
   55     if (obj && obj[marker])
   56         throw (new Error('attempted deep copy of cyclic object'));
   57 
   58     if (obj && obj.constructor == Object) {
   59         ret = {};
   60         obj[marker] = true;
   61 
   62         for (key in obj) {
   63             if (key == marker)
   64                 continue;
   65 
   66             ret[key] = deepCopy(obj[key]);
   67         }
   68 
   69         delete (obj[marker]);
   70         return (ret);
   71     }
   72 
   73     if (obj && obj.constructor == Array) {
   74         ret = [];
   75         obj[marker] = true;
   76 
   77         for (key = 0; key < obj.length; key++)
   78             ret.push(deepCopy(obj[key]));
   79 
   80         delete (obj[marker]);
   81         return (ret);
   82     }
   83 
   84     /*
   85      * It must be a primitive type -- just return it.
   86      */
   87     return (obj);
   88 }
   89 
   90 function deepEqual(obj1, obj2)
   91 {
   92     if (typeof (obj1) != typeof (obj2))
   93         return (false);
   94 
   95     if (obj1 === null || obj2 === null || typeof (obj1) != 'object')
   96         return (obj1 === obj2);
   97 
   98     if (obj1.constructor != obj2.constructor)
   99         return (false);
  100 
  101     var k;
  102     for (k in obj1) {
  103         if (!obj2.hasOwnProperty(k))
  104             return (false);
  105 
  106         if (!deepEqual(obj1[k], obj2[k]))
  107             return (false);
  108     }
  109 
  110     for (k in obj2) {
  111         if (!obj1.hasOwnProperty(k))
  112             return (false);
  113     }
  114 
  115     return (true);
  116 }
  117 
  118 function isEmpty(obj)
  119 {
  120     var key;
  121     for (key in obj)
  122         return (false);
  123     return (true);
  124 }
  125 
  126 function hasKey(obj, key)
  127 {
  128     mod_assert.equal(typeof (key), 'string');
  129     return (Object.prototype.hasOwnProperty.call(obj, key));
  130 }
  131 
  132 function forEachKey(obj, callback)
  133 {
  134     for (var key in obj) {
  135         if (hasKey(obj, key)) {
  136             callback(key, obj[key]);
  137         }
  138     }
  139 }
  140 
  141 function pluck(obj, key)
  142 {
  143     mod_assert.equal(typeof (key), 'string');
  144     return (pluckv(obj, key));
  145 }
  146 
  147 function pluckv(obj, key)
  148 {
  149     if (obj === null || typeof (obj) !== 'object')
  150         return (undefined);
  151 
  152     if (obj.hasOwnProperty(key))
  153         return (obj[key]);
  154 
  155     var i = key.indexOf('.');
  156     if (i == -1)
  157         return (undefined);
  158 
  159     var key1 = key.substr(0, i);
  160     if (!obj.hasOwnProperty(key1))
  161         return (undefined);
  162 
  163     return (pluckv(obj[key1], key.substr(i + 1)));
  164 }
  165 
  166 /*
  167  * Invoke callback(row) for each entry in the array that would be returned by
  168  * flattenObject(data, depth).  This is just like flattenObject(data,
  169  * depth).forEach(callback), except that the intermediate array is never
  170  * created.
  171  */
  172 function flattenIter(data, depth, callback)
  173 {
  174     doFlattenIter(data, depth, [], callback);
  175 }
  176 
  177 function doFlattenIter(data, depth, accum, callback)
  178 {
  179     var each;
  180     var key;
  181 
  182     if (depth === 0) {
  183         each = accum.slice(0);
  184         each.push(data);
  185         callback(each);
  186         return;
  187     }
  188 
  189     mod_assert.ok(data !== null);
  190     mod_assert.equal(typeof (data), 'object');
  191     mod_assert.equal(typeof (depth), 'number');
  192     mod_assert.ok(depth >= 0);
  193 
  194     for (key in data) {
  195         each = accum.slice(0);
  196         each.push(key);
  197         doFlattenIter(data[key], depth - 1, each, callback);
  198     }
  199 }
  200 
  201 function flattenObject(data, depth)
  202 {
  203     if (depth === 0)
  204         return ([ data ]);
  205 
  206     mod_assert.ok(data !== null);
  207     mod_assert.equal(typeof (data), 'object');
  208     mod_assert.equal(typeof (depth), 'number');
  209     mod_assert.ok(depth >= 0);
  210 
  211     var rv = [];
  212     var key;
  213 
  214     for (key in data) {
  215         flattenObject(data[key], depth - 1).forEach(function (p) {
  216             rv.push([ key ].concat(p));
  217         });
  218     }
  219 
  220     return (rv);
  221 }
  222 
  223 function startsWith(str, prefix)
  224 {
  225     return (str.substr(0, prefix.length) == prefix);
  226 }
  227 
  228 function endsWith(str, suffix)
  229 {
  230     return (str.substr(
  231         str.length - suffix.length, suffix.length) == suffix);
  232 }
  233 
  234 function iso8601(d)
  235 {
  236     if (typeof (d) == 'number')
  237         d = new Date(d);
  238     mod_assert.ok(d.constructor === Date);
  239     return (mod_extsprintf.sprintf('%4d-%02d-%02dT%02d:%02d:%02d.%03dZ',
  240         d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate(),
  241         d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(),
  242         d.getUTCMilliseconds()));
  243 }
  244 
  245 var RFC1123_MONTHS = [
  246     'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
  247     'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
  248 var RFC1123_DAYS = [
  249     'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
  250 
  251 function rfc1123(date) {
  252     return (mod_extsprintf.sprintf('%s, %02d %s %04d %02d:%02d:%02d GMT',
  253         RFC1123_DAYS[date.getUTCDay()], date.getUTCDate(),
  254         RFC1123_MONTHS[date.getUTCMonth()], date.getUTCFullYear(),
  255         date.getUTCHours(), date.getUTCMinutes(),
  256         date.getUTCSeconds()));
  257 }
  258 
  259 /*
  260  * Parses a date expressed as a string, as either a number of milliseconds since
  261  * the epoch or any string format that Date accepts, giving preference to the
  262  * former where these two sets overlap (e.g., small numbers).
  263  */
  264 function parseDateTime(str)
  265 {
  266     /*
  267      * This is irritatingly implicit, but significantly more concise than
  268      * alternatives.  The "+str" will convert a string containing only a
  269      * number directly to a Number, or NaN for other strings.  Thus, if the
  270      * conversion succeeds, we use it (this is the milliseconds-since-epoch
  271      * case).  Otherwise, we pass the string directly to the Date
  272      * constructor to parse.
  273      */
  274     var numeric = +str;
  275     if (!isNaN(numeric)) {
  276         return (new Date(numeric));
  277     } else {
  278         return (new Date(str));
  279     }
  280 }
  281 
  282 function validateJsonObjectJS(schema, input)
  283 {
  284     var report = mod_jsonschema.validate(input, schema);
  285 
  286     if (report.errors.length === 0)
  287         return (null);
  288 
  289     /* Currently, we only do anything useful with the first error. */
  290     var error = report.errors[0];
  291 
  292     /* The failed property is given by a URI with an irrelevant prefix. */
  293     var propname = error['property'];
  294     var reason = error['message'].toLowerCase();
  295     var i, j;
  296 
  297     /*
  298      * There's at least one case where the property error message is
  299      * confusing at best.  We work around this here.
  300      */
  301     if ((i = reason.indexOf('the property ')) != -1 &&
  302         (j = reason.indexOf(' is not defined in the schema and the ' +
  303         'schema does not allow additional properties')) != -1) {
  304         i += 'the property '.length;
  305         if (propname === '')
  306             propname = reason.substr(i, j - i);
  307         else
  308             propname = propname + '.' + reason.substr(i, j - i);
  309 
  310         reason = 'unsupported property';
  311     }
  312 
  313     var rv = new mod_verror.VError('property "%s": %s', propname, reason);
  314     rv.jsv_details = error;
  315     return (rv);
  316 }
  317 
  318 function randElt(arr)
  319 {
  320     mod_assert.ok(Array.isArray(arr) && arr.length > 0,
  321         'randElt argument must be a non-empty array');
  322 
  323     return (arr[Math.floor(Math.random() * arr.length)]);
  324 }
  325 
  326 function assertHrtime(a)
  327 {
  328     mod_assert.ok(a[0] >= 0 && a[1] >= 0,
  329         'negative numbers not allowed in hrtimes');
  330     mod_assert.ok(a[1] < 1e9, 'nanoseconds column overflow');
  331 }
  332 
  333 /*
  334  * Compute the time elapsed between hrtime readings A and B, where A is later
  335  * than B.  hrtime readings come from Node's process.hrtime().  There is no
  336  * defined way to represent negative deltas, so it's illegal to diff B from A
  337  * where the time denoted by B is later than the time denoted by A.  If this
  338  * becomes valuable, we can define a representation and extend the
  339  * implementation to support it.
  340  */
  341 function hrtimeDiff(a, b)
  342 {
  343     assertHrtime(a);
  344     assertHrtime(b);
  345     mod_assert.ok(a[0] > b[0] || (a[0] == b[0] && a[1] >= b[1]),
  346         'negative differences not allowed');
  347 
  348     var rv = [ a[0] - b[0], 0 ];
  349 
  350     if (a[1] >= b[1]) {
  351         rv[1] = a[1] - b[1];
  352     } else {
  353         rv[0]--;
  354         rv[1] = 1e9 - (b[1] - a[1]);
  355     }
  356 
  357     return (rv);
  358 }
  359 
  360 /*
  361  * Convert a hrtime reading from the array format returned by Node's
  362  * process.hrtime() into a scalar number of nanoseconds.
  363  */
  364 function hrtimeNanosec(a)
  365 {
  366     assertHrtime(a);
  367 
  368     return (Math.floor(a[0] * 1e9 + a[1]));
  369 }
  370 
  371 /*
  372  * Convert a hrtime reading from the array format returned by Node's
  373  * process.hrtime() into a scalar number of microseconds.
  374  */
  375 function hrtimeMicrosec(a)
  376 {
  377     assertHrtime(a);
  378 
  379     return (Math.floor(a[0] * 1e6 + a[1] / 1e3));
  380 }
  381 
  382 /*
  383  * Convert a hrtime reading from the array format returned by Node's
  384  * process.hrtime() into a scalar number of milliseconds.
  385  */
  386 function hrtimeMillisec(a)
  387 {
  388     assertHrtime(a);
  389 
  390     return (Math.floor(a[0] * 1e3 + a[1] / 1e6));
  391 }
  392 
  393 /*
  394  * Add two hrtime readings A and B, overwriting A with the result of the
  395  * addition.  This function is useful for accumulating several hrtime intervals
  396  * into a counter.  Returns A.
  397  */
  398 function hrtimeAccum(a, b)
  399 {
  400     assertHrtime(a);
  401     assertHrtime(b);
  402 
  403     /*
  404      * Accumulate the nanosecond component.
  405      */
  406     a[1] += b[1];
  407     if (a[1] >= 1e9) {
  408         /*
  409          * The nanosecond component overflowed, so carry to the seconds
  410          * field.
  411          */
  412         a[0]++;
  413         a[1] -= 1e9;
  414     }
  415 
  416     /*
  417      * Accumulate the seconds component.
  418      */
  419     a[0] += b[0];
  420 
  421     return (a);
  422 }
  423 
  424 /*
  425  * Add two hrtime readings A and B, returning the result as a new hrtime array.
  426  * Does not modify either input argument.
  427  */
  428 function hrtimeAdd(a, b)
  429 {
  430     assertHrtime(a);
  431 
  432     var rv = [ a[0], a[1] ];
  433 
  434     return (hrtimeAccum(rv, b));
  435 }
  436 
  437 
  438 /*
  439  * Check an object for unexpected properties.  Accepts the object to check, and
  440  * an array of allowed property names (strings).  Returns an array of key names
  441  * that were found on the object, but did not appear in the list of allowed
  442  * properties.  If no properties were found, the returned array will be of
  443  * zero length.
  444  */
  445 function extraProperties(obj, allowed)
  446 {
  447     mod_assert.ok(typeof (obj) === 'object' && obj !== null,
  448         'obj argument must be a non-null object');
  449     mod_assert.ok(Array.isArray(allowed),
  450         'allowed argument must be an array of strings');
  451     for (var i = 0; i < allowed.length; i++) {
  452         mod_assert.ok(typeof (allowed[i]) === 'string',
  453             'allowed argument must be an array of strings');
  454     }
  455 
  456     return (Object.keys(obj).filter(function (key) {
  457         return (allowed.indexOf(key) === -1);
  458     }));
  459 }
  460 
  461 /*
  462  * Given three sets of properties "provided" (may be undefined), "overrides"
  463  * (required), and "defaults" (may be undefined), construct an object containing
  464  * the union of these sets with "overrides" overriding "provided", and
  465  * "provided" overriding "defaults".  None of the input objects are modified.
  466  */
  467 function mergeObjects(provided, overrides, defaults)
  468 {
  469     var rv, k;
  470 
  471     rv = {};
  472     if (defaults) {
  473         for (k in defaults)
  474             rv[k] = defaults[k];
  475     }
  476 
  477     if (provided) {
  478         for (k in provided)
  479             rv[k] = provided[k];
  480     }
  481 
  482     if (overrides) {
  483         for (k in overrides)
  484             rv[k] = overrides[k];
  485     }
  486 
  487     return (rv);
  488 }