Comparing version 4.3.1 to 4.4.0
@@ -1,3 +0,4 @@ | ||
// Generated by CoffeeScript 2.0.0-beta3 | ||
// Generated by CoffeeScript 2.3.1 | ||
(function() { | ||
//########################################################################################################### | ||
var CND, njs_fs, njs_path, njs_util, rpr, validate_isa_number, | ||
@@ -16,2 +17,3 @@ indexOf = [].indexOf; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.equals = function(...P) { | ||
@@ -21,2 +23,32 @@ return (require('./jkroso-equals'))(...P); | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.is_empty = function(x) { | ||
if (x.length != null) { | ||
return x.length === 0; | ||
} | ||
if (x.size != null) { | ||
return x.size === 0; | ||
} | ||
throw new Error(`unable to determine length of a ${CND.type_of(x)}`); | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.jr = JSON.stringify; | ||
this.assign = Object.assign; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.copy = function(...P) { | ||
var type; | ||
switch (type = this.type_of(P[0])) { | ||
case 'pod': | ||
return this.assign({}, ...P); | ||
case 'list': | ||
return this.assign([], ...P); | ||
default: | ||
throw new Error(`µ09231 unable to copy a ${type}`); | ||
} | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.deep_copy = function(...P) { | ||
@@ -26,5 +58,4 @@ return (require('./universal-copy'))(...P); | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.format_number = function(n, grouper = "'") { | ||
/* A simple number formatter. */ | ||
var f, h; | ||
@@ -44,15 +75,14 @@ n = n.toString(); | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.escape_regex = function(text) { | ||
/* Given a `text`, return the same with all regular expression metacharacters properly escaped. Escaped | ||
characters are `[]{}()*+?-.,\^$|#` plus whitespace. | ||
*/ | ||
characters are `[]{}()*+?-.,\^$|#` plus whitespace. */ | ||
//......................................................................................................... | ||
return text.replace(/[-[\]{}()*+?.,\\\/^$|#\s]/g, "\\$&"); | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.escape_html = function(text) { | ||
/* Given a `text`, return the same with all characters critical in HTML (`&`, `<`, `>`) properly | ||
escaped. | ||
*/ | ||
escaped. */ | ||
var R; | ||
@@ -63,7 +93,9 @@ R = text; | ||
R = R.replace(/>/g, '>'); | ||
//......................................................................................................... | ||
return R; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.find_all = function(text, matcher) { | ||
var flags, ref; | ||
/* `CND.find_all` expects a `text` and a `matcher` (which must be a RegExp object); it returns a | ||
@@ -73,7 +105,6 @@ (possibly empty) list of all matching parts in the text. If `matcher` does not have the `g` (global) flag | ||
turned on may improve performance. | ||
With thanks to http://www.2ality.com/2013/08/regexp-g.html, | ||
http://www.2ality.com/2011/04/javascript-overview-of-regular.html. | ||
*/ | ||
var flags, ref; | ||
*/ | ||
if (!((Object.prototype.toString.call(matcher === '[object RegExp]')) && matcher.global)) { | ||
@@ -96,18 +127,20 @@ flags = matcher.multiline ? 'gm' : 'g'; | ||
//=========================================================================================================== | ||
// UNSORTING | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.shuffle = function(list, ratio = 1) { | ||
/* Shuffles the elements of a list randomly. After the call, the elements of will be—most of the time— | ||
be reordered (but this is not guaranteed, as there is a realistic probability for recurrence of orderings | ||
with short lists). | ||
This is an implementation of the renowned Fisher-Yates algorithm, but with a twist: You may pass in a | ||
`ratio` as second argument (which should be a float in the range `0 <= ratio <= 1`); if set to a value | ||
less than one, a random number will be used to decide whether or not to perform a given step in the | ||
shuffling process, so lists shuffled with zero-ish ratios will show less disorder than lists shuffled with | ||
a one-ish ratio. | ||
Implementation gleaned from http://stackoverflow.com/a/962890/256361. | ||
*/ | ||
var this_idx; | ||
if ((this_idx = list.length) < 2) { | ||
/* Shuffles the elements of a list randomly. After the call, the elements of will be—most of the time— | ||
be reordered (but this is not guaranteed, as there is a realistic probability for recurrence of orderings | ||
with short lists). | ||
This is an implementation of the renowned Fisher-Yates algorithm, but with a twist: You may pass in a | ||
`ratio` as second argument (which should be a float in the range `0 <= ratio <= 1`); if set to a value | ||
less than one, a random number will be used to decide whether or not to perform a given step in the | ||
shuffling process, so lists shuffled with zero-ish ratios will show less disorder than lists shuffled with | ||
a one-ish ratio. | ||
Implementation gleaned from http://stackoverflow.com/a/962890/256361. */ | ||
//......................................................................................................... | ||
return list; | ||
@@ -118,8 +151,7 @@ } | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.get_shuffle = function(seed_0 = 0, seed_1 = 1) { | ||
/* This method works similar to `get_rnd`; it accepts two `seed`s which are used to produce random number | ||
generators and returns a predictable shuffling function that accepts arguments like Bits'N'Pieces | ||
`shuffle`. | ||
*/ | ||
`shuffle`. */ | ||
var random_integer, rnd; | ||
@@ -133,8 +165,11 @@ rnd = this.get_rnd(seed_0); | ||
//----------------------------------------------------------------------------------------------------------- | ||
this._shuffle = function(list, ratio, rnd, random_integer) { | ||
var that_idx, this_idx; | ||
if ((this_idx = list.length) < 2) { | ||
//......................................................................................................... | ||
return list; | ||
} | ||
while (true) { | ||
//......................................................................................................... | ||
this_idx += -1; | ||
@@ -145,2 +180,3 @@ if (this_idx < 1) { | ||
if (ratio >= 1 || rnd() <= ratio) { | ||
// return list if this_idx < 1 | ||
that_idx = random_integer(0, this_idx); | ||
@@ -150,23 +186,24 @@ [list[that_idx], list[this_idx]] = [list[this_idx], list[that_idx]]; | ||
} | ||
//......................................................................................................... | ||
return list; | ||
}; | ||
//=========================================================================================================== | ||
// RANDOM NUMBERS | ||
//----------------------------------------------------------------------------------------------------------- | ||
/* see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number */ | ||
this.MIN_SAFE_INTEGER = -(2 ** 53) - 1; | ||
this.MIN_SAFE_INTEGER = -(Math.pow(2, 53)) - 1; | ||
this.MAX_SAFE_INTEGER = +(2 ** 53) - 1; | ||
this.MAX_SAFE_INTEGER = +(Math.pow(2, 53)) - 1; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.random_number = function(min = 0, max = 1) { | ||
/* Return a random number between min (inclusive) and max (exclusive). | ||
From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random | ||
via http://stackoverflow.com/a/1527820/256361. | ||
*/ | ||
via http://stackoverflow.com/a/1527820/256361. */ | ||
return Math.random() * (max - min) + min; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.integer_from_normal_float = function(x, min = 0, max = 2) { | ||
/* Given a 'normal' float `x` so that `0 <= x < 1`, return an integer `n` so that `min <= n < min`. */ | ||
@@ -176,13 +213,12 @@ return (Math.floor(x * (max - min))) + min; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.random_integer = function(min = 0, max = 2) { | ||
/* Return a random integer between min (inclusive) and max (inclusive). | ||
From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random | ||
via http://stackoverflow.com/a/1527820/256361. | ||
*/ | ||
via http://stackoverflow.com/a/1527820/256361. */ | ||
return this.integer_from_normal_float(Math.random(), min, max); | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.get_rnd_int = function(seed = 1, delta = 1) { | ||
/* Like `get_rnd`, but returns a predictable random integer generator. */ | ||
@@ -196,4 +232,5 @@ var rnd; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.get_rnd = function(seed = 1, delta = 1) { | ||
var R; | ||
/* This method returns a simple deterministic pseudo-random number generator—basically like | ||
@@ -205,3 +242,3 @@ `Math.random`, but (1) very probably with a much worse distribution of results, and (2) with predictable | ||
to reset the generator: | ||
CND = require 'cnd' | ||
@@ -213,8 +250,7 @@ rnd = CND.get_rnd() # or, say, `rnd = CND.get_rnd 123, 0.5` | ||
log rnd() for idx in [ 0 .. 5 ] | ||
Please note that there are no strong guarantees made about the quality of the generated values except the | ||
(1) deterministic repeatability, (2) boundedness, and (3) 'apparent randomness'. Do **not** use this for | ||
cryptographic purposes. | ||
*/ | ||
var R; | ||
cryptographic purposes. */ | ||
//......................................................................................................... | ||
R = function() { | ||
@@ -227,7 +263,6 @@ var x; | ||
}; | ||
//......................................................................................................... | ||
R.reset = function(seed, delta) { | ||
/* Reset the generator. After calling `rnd.reset` (or `rnd.seed` with the same arguments), ensuing calls | ||
to `rnd` will always result in the same sequence of pseudo-random numbers. | ||
*/ | ||
to `rnd` will always result in the same sequence of pseudo-random numbers. */ | ||
if (seed == null) { | ||
@@ -239,5 +274,7 @@ seed = this._seed; | ||
} | ||
//....................................................................................................... | ||
validate_isa_number(seed); | ||
validate_isa_number(delta); | ||
if (seed === 0) { | ||
//....................................................................................................... | ||
throw new Error("seed should not be zero"); | ||
@@ -248,2 +285,3 @@ } | ||
} | ||
//....................................................................................................... | ||
R._s = seed; | ||
@@ -255,9 +293,10 @@ R._seed = seed; | ||
}; | ||
//......................................................................................................... | ||
R.reset(seed, delta); | ||
//......................................................................................................... | ||
return R; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
/* TAINT code duplication (to avoid dependency on CoffeeNode Types). */ | ||
validate_isa_number = function(x) { | ||
@@ -269,8 +308,9 @@ if (!((Object.prototype.toString.call(x)) === '[object Number]' && isFinite(x))) { | ||
//=========================================================================================================== | ||
// PODs | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.pluck = function(x, name, fallback) { | ||
var R; | ||
/* Given some object `x`, a `name` and a `fallback`, return the value of `x[ name ]`, or, if it does not | ||
exist, `fallback`. When the method returns, `x[ name ]` has been deleted. | ||
*/ | ||
var R; | ||
exist, `fallback`. When the method returns, `x[ name ]` has been deleted. */ | ||
if (x[name] != null) { | ||
@@ -285,2 +325,5 @@ R = x[name]; | ||
//=========================================================================================================== | ||
// ROUTES | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.get_parent_routes = function(route) { | ||
@@ -290,2 +333,3 @@ var R; | ||
while (true) { | ||
//......................................................................................................... | ||
R.push(route); | ||
@@ -297,10 +341,14 @@ if (route.length === 0 || route === '/') { | ||
} | ||
//......................................................................................................... | ||
return R; | ||
}; | ||
//=========================================================================================================== | ||
// CALLER LOCATION | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.get_V8_CallSite_objects = function(error = null) { | ||
/* Save original Error.prepareStackTrace */ | ||
var R, prepareStackTrace_original; | ||
prepareStackTrace_original = Error.prepareStackTrace; | ||
//......................................................................................................... | ||
Error.prepareStackTrace = function(ignored, stack) { | ||
@@ -313,39 +361,40 @@ return stack; | ||
R = error.stack; | ||
//......................................................................................................... | ||
/* Restore original Error.prepareStackTrace */ | ||
Error.prepareStackTrace = prepareStackTrace_original; | ||
//......................................................................................................... | ||
return R; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.get_caller_info_stack = function(delta = 0, error = null, limit = 2e308, include_source = false) { | ||
/* Return a list of PODs representing information about the call stack; newest items will be closer | ||
to the start ('top') of the list. | ||
`delta` represents the call distance of the site the inquirer is interested about, relative to the | ||
*inquirer*; this will be `0` if that is the very line where the call originated from, `1` in case another | ||
function is called to collect this information, and so on. | ||
A custom error will be produced and analyzed (with a suitably adjusted value for `delta`) in case no | ||
`error` has been given. Often, one will want to use this facility to see what the source for a caught | ||
error looks like; in that case, just pass in the caught `error` object along with a `delta` of (typically) | ||
`0` (because the error really originated where the problem occurred). | ||
It is further possible to cut down on the amount of data returned by setting `limit` to a smallish | ||
number; entries too close (with a stack index smaller than `delta`) or too far from the interesting | ||
point will be omitted. | ||
When `include_source` is `true`, an attempt will be made to open each source file, read its contents, | ||
split it into lines, and include the indicated line in the respective entry. Note that this is currently | ||
done in a very stupid, blocking, and non-memoizing way, so try not to do that if your stack trace is | ||
hundreds of lines long and includes megabyte-sized sources. | ||
Also see `get_caller_info`, which should be handy if you do not need an entire stack but just a single | ||
targetted entry. | ||
Have a look at https://github.com/loveencounterflow/guy-test to see how to use the BNP caller info | ||
methods to copy with error locations in an asynchronous world. | ||
*/ | ||
var R, call_sites, cs, entry, i, idx, len; | ||
if (error == null) { | ||
/* Return a list of PODs representing information about the call stack; newest items will be closer | ||
to the start ('top') of the list. | ||
`delta` represents the call distance of the site the inquirer is interested about, relative to the | ||
*inquirer*; this will be `0` if that is the very line where the call originated from, `1` in case another | ||
function is called to collect this information, and so on. | ||
A custom error will be produced and analyzed (with a suitably adjusted value for `delta`) in case no | ||
`error` has been given. Often, one will want to use this facility to see what the source for a caught | ||
error looks like; in that case, just pass in the caught `error` object along with a `delta` of (typically) | ||
`0` (because the error really originated where the problem occurred). | ||
It is further possible to cut down on the amount of data returned by setting `limit` to a smallish | ||
number; entries too close (with a stack index smaller than `delta`) or too far from the interesting | ||
point will be omitted. | ||
When `include_source` is `true`, an attempt will be made to open each source file, read its contents, | ||
split it into lines, and include the indicated line in the respective entry. Note that this is currently | ||
done in a very stupid, blocking, and non-memoizing way, so try not to do that if your stack trace is | ||
hundreds of lines long and includes megabyte-sized sources. | ||
Also see `get_caller_info`, which should be handy if you do not need an entire stack but just a single | ||
targetted entry. | ||
Have a look at https://github.com/loveencounterflow/guy-test to see how to use the BNP caller info | ||
methods to copy with error locations in an asynchronous world. */ | ||
//......................................................................................................... | ||
delta += +2; | ||
@@ -355,2 +404,3 @@ } | ||
R = []; | ||
//......................................................................................................... | ||
for (idx = i = 0, len = call_sites.length; i < len; idx = ++i) { | ||
@@ -376,5 +426,7 @@ cs = call_sites[idx]; | ||
} | ||
//......................................................................................................... | ||
return R; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.get_caller_info = function(delta = 0, error = null, include_source = false) { | ||
@@ -387,5 +439,7 @@ var R; | ||
} | ||
// console.log '©3cc0i', rpr R | ||
return R; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this._source_line_from_caller_info = function(info) { | ||
@@ -407,4 +461,7 @@ var R, error, line_nr, route, source_lines; | ||
//=========================================================================================================== | ||
// ID CREATION | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.create_id = function(values, length) { | ||
var value; | ||
/* Given a number of `values` and a `length`, return an ID with `length` hexadecimal digits (`[0-9a-f]`) | ||
@@ -417,5 +474,3 @@ that deterministically depends on the input but can probably not reverse-engeneered to yield the input | ||
the BITSNPIECES ID utilities is *not* to be 'crypto-safe'; its intent is to give you a tool for generating | ||
repetition-free IDs. | ||
*/ | ||
var value; | ||
repetition-free IDs. */ | ||
return this.id_from_text(((function() { | ||
@@ -432,4 +487,4 @@ var i, len, results; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.create_random_id = function(values, length) { | ||
/* Like `create_id`, but with an extra random factor built in that should exclude that two identical | ||
@@ -440,4 +495,3 @@ outputs are ever returned for any two identical inputs. Under the assumption that two calls to this | ||
assuming you are using a reasonable value for `length` (i.e., say, `7 < length < 20`), you should never | ||
see the same ID twice. | ||
*/ | ||
see the same ID twice. */ | ||
values.push(1 * new Date() * Math.random()); | ||
@@ -447,4 +501,5 @@ return this.create_id(values, length); | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.get_create_rnd_id = function(seed, delta) { | ||
var R; | ||
/* Given an optional `seed` and `delta`, returns a function that will create pseudo-random IDs similar to | ||
@@ -454,3 +509,3 @@ the ones `create_random_id` returns; however, the Bits'n'Pieces `get_rnd` method is used to obtain a | ||
`fn.rnd`, so `fn.rnd.reset` may be used to start over. | ||
**Use Case Example**: The below code demonstrates the interesting properties of the method returned by | ||
@@ -464,11 +519,11 @@ `get_create_rnd_id`: **(1)** we can seed the PRNG with numbers of our choice, so we get a chance to create | ||
see the identical *same* IDs generated—which is great for testing. | ||
create_rnd_id = CND.get_create_rnd_id 1234, 87.23 | ||
* three different user IDs: | ||
* three different user IDs: | ||
log create_rnd_id [ 'foo@example.com' ], 12 | ||
log create_rnd_id [ 'alice@nosuchname.com' ], 12 | ||
log create_rnd_id [ 'tim@cern.ch' ], 12 | ||
* the same repeated, but yielding random other IDs: | ||
* the same repeated, but yielding random other IDs: | ||
log() | ||
@@ -478,4 +533,4 @@ log create_rnd_id [ 'foo@example.com' ], 12 | ||
log create_rnd_id [ 'tim@cern.ch' ], 12 | ||
* the same repeated, but yielding the same IDs as in the first run: | ||
* the same repeated, but yielding the same IDs as in the first run: | ||
log() | ||
@@ -486,17 +541,17 @@ create_rnd_id.rnd.reset() | ||
log create_rnd_id [ 'tim@cern.ch' ], 12 | ||
The output you should see is | ||
c40f774fce65 | ||
9d44f31f9a55 | ||
1b26e6e3e736 | ||
a0e11f616685 | ||
d7242f6935c7 | ||
976f26d1b25b | ||
c40f774fce65 | ||
9d44f31f9a55 | ||
1b26e6e3e736 | ||
Note the last three IDs exactly match the first three IDs. The upshot of this is that we get reasonably | ||
@@ -508,5 +563,4 @@ hard-to-guess, yet on-demand replayable IDs. Apart from weaknesses in the PRNG itself (for which see the | ||
a replay would then need to provide all of the case-specific pieces of data a second time, in the right | ||
order. | ||
*/ | ||
var R; | ||
order. */ | ||
//......................................................................................................... | ||
R = (values, length) => { | ||
@@ -516,14 +570,14 @@ values.push(R.rnd()); | ||
}; | ||
//......................................................................................................... | ||
R.rnd = this.get_rnd(seed, delta); | ||
//......................................................................................................... | ||
return R; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.id_from_text = function(text, length) { | ||
/* Given a `text` and a `length`, return an ID with `length` hexadecimal digits (`[0-9a-f]`)—this is like | ||
`create_id`, but working on a text rather than a number of arbitrary values. The hash algorithm currently | ||
used is SHA-1, which returns 40 hex digits; it should be good enough for the task at hand and has the | ||
advantage of being widely implemented. | ||
*/ | ||
advantage of being widely implemented. */ | ||
/* TAINT should be a user option, or take 'good' algorithm universally available */ | ||
@@ -539,7 +593,7 @@ var R; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.id_from_route = function(route, length, handler) { | ||
/* Like `id_from_text`, but accepting a file route instead of a text. */ | ||
var R, content; | ||
if (handler != null) { | ||
/* Like `id_from_text`, but accepting a file route instead of a text. */ | ||
throw new Error("asynchronous `id_from_route` not yet supported"); | ||
@@ -556,17 +610,6 @@ } | ||
//=========================================================================================================== | ||
// APP INFO | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.get_app_home = function(routes = null) { | ||
/* Return the file system route to the current (likely) application folder. This works by traversing all | ||
the routes in `require[ 'main' ][ 'paths' ]` and checking whether one of the `node_modules` folders | ||
listed there exists and is a folder; the first match is accepted and returned. If no matching existing | ||
route is found, an error is thrown. | ||
NB that the algorithm works even if the CoffeeNode Options module has been symlinked from another location | ||
(rather than 'physically' installed) and even if the application main file has been executed from outside | ||
the application folder (i.e. this obviates the need to `cd ~/route/to/my/app` before doing `node ./start` | ||
or whatever—you can simply do `node ~/route/to/my/app/start`), but it does presuppose that (1) there *is* | ||
a `node_modules` folder in your app folder; (2) there is *no* `node_modules` folder in the subfolder or | ||
any of the intervening levels (if any) that contains your startup file. Most modules that follow the | ||
established NodeJS / npm way of structuring modules should naturally comply with these assumptions. | ||
*/ | ||
var error, i, len, route; | ||
@@ -577,2 +620,3 @@ njs_fs = require('fs'); | ||
} | ||
//......................................................................................................... | ||
for (i = 0, len = routes.length; i < len; i++) { | ||
@@ -585,6 +629,6 @@ route = routes[i]; | ||
} catch (error1) { | ||
//....................................................................................................... | ||
error = error1; | ||
/* silently ignore missing routes: */ | ||
if (error['code'] === 'ENOENT') { | ||
/* silently ignore missing routes: */ | ||
continue; | ||
@@ -595,5 +639,9 @@ } | ||
} | ||
//......................................................................................................... | ||
throw new Error(`unable to determine application home; tested routes: \n\n ${routes.join('\n ')}\n`); | ||
}; | ||
//=========================================================================================================== | ||
// FS ROUTES | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.swap_extension = function(route, extension) { | ||
@@ -608,2 +656,5 @@ var extname; | ||
//=========================================================================================================== | ||
// LISTS | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.first_of = function(collection) { | ||
@@ -617,2 +668,5 @@ return collection[0]; | ||
//=========================================================================================================== | ||
// OBJECT SIZES | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.size_of = function(x, settings) { | ||
@@ -647,4 +701,6 @@ var ref, ref1, selector, type; | ||
//=========================================================================================================== | ||
// NETWORK | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.get_local_ips = function() { | ||
/* thx to http://stackoverflow.com/a/10756441/256361 */ | ||
@@ -666,7 +722,8 @@ var R, _, description, i, interface_, len, ref; | ||
//=========================================================================================================== | ||
// SETS | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.is_subset = function(subset, superset) { | ||
/* `is_subset subset, superset` returns whether `subset` is a subset of `superset`; this is true if each | ||
element of `subset` is also an element of `superset`. | ||
*/ | ||
element of `subset` is also an element of `superset`. */ | ||
var done, element, i, iterator, len, type_of_sub, type_of_super, value; | ||
@@ -704,2 +761,4 @@ type_of_sub = CND.type_of(subset); | ||
} | ||
// for element in | ||
// return false unless element in subset | ||
return true; | ||
@@ -712,25 +771,28 @@ default: | ||
//=========================================================================================================== | ||
// ERROR HANDLING | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.run = function(method, on_error = null, on_after_error = null) { | ||
var trycatch, trycatch_settings; | ||
/* Provide asynchronous error handling and long stacktraces. Usage: | ||
/* Provide asynchronous error handling and long stacktraces. Usage: | ||
To run a method, catch all the synchronous and asynchronous errors and print a stacktrace | ||
to `process.stderr` (using `console.error`): | ||
```coffee | ||
CND.run -> f 42 | ||
``` | ||
Same as the above, but do the error handling yourself: | ||
```coffee | ||
CND.run ( -> f 42 ), ( error ) -> foobar() | ||
``` | ||
Same as the last, except have CND output the error's stacktrace and be called back afterwards: | ||
```coffee | ||
CND.run ( -> f 42 ), null, ( error ) -> foobar() | ||
``` | ||
NB.: `CND.run` may be made configurable in the future; as of now, it is hardwired to use colors | ||
@@ -740,4 +802,4 @@ and always provide long (cross-event) stack traces. Colors used are blue for NodeJS VM built-ins, | ||
else. | ||
*/ | ||
var trycatch, trycatch_settings; | ||
*/ | ||
if (on_error == null) { | ||
@@ -752,5 +814,7 @@ on_error = function(error) { | ||
trycatch = require('trycatch'); | ||
//......................................................................................................... | ||
trycatch_settings = { | ||
'long-stack-traces': true, | ||
'colors': { | ||
// 'none' or falsy values will omit | ||
'node': 'blue', | ||
@@ -761,4 +825,6 @@ 'node_modules': 'green', | ||
}; | ||
//......................................................................................................... | ||
trycatch.configure(trycatch_settings); | ||
trycatch(method, on_error); | ||
//......................................................................................................... | ||
return null; | ||
@@ -765,0 +831,0 @@ }; |
@@ -1,8 +0,7 @@ | ||
// Generated by CoffeeScript 2.0.0-beta3 | ||
/* LIST methods */ | ||
// Generated by CoffeeScript 2.3.1 | ||
(function() { | ||
/* LIST methods */ | ||
var insert, rotate_left, rotate_right; | ||
//....................................................................................................... | ||
insert = function(list, item, idx = 0) { | ||
@@ -13,2 +12,3 @@ list.splice(idx, 0, item); | ||
//....................................................................................................... | ||
rotate_left = function(list, count = 1) { | ||
@@ -19,3 +19,3 @@ var _, i, ref; | ||
} | ||
for (_ = i = 0, ref = count; 0 <= ref ? i < ref : i > ref; _ = 0 <= ref ? ++i : --i) { | ||
for (_ = i = 0, ref = count; (0 <= ref ? i < ref : i > ref); _ = 0 <= ref ? ++i : --i) { | ||
list.push(list.shift()); | ||
@@ -26,2 +26,3 @@ } | ||
//....................................................................................................... | ||
rotate_right = function(list, count = 1) { | ||
@@ -32,3 +33,3 @@ var _, i, ref; | ||
} | ||
for (_ = i = 0, ref = count; 0 <= ref ? i < ref : i > ref; _ = 0 <= ref ? ++i : --i) { | ||
for (_ = i = 0, ref = count; (0 <= ref ? i < ref : i > ref); _ = 0 <= ref ? ++i : --i) { | ||
list.unshift(list.pop()); | ||
@@ -35,0 +36,0 @@ } |
@@ -1,2 +0,2 @@ | ||
// Generated by CoffeeScript 2.0.0-beta3 | ||
// Generated by CoffeeScript 2.3.1 | ||
(function() { | ||
@@ -3,0 +3,0 @@ |
@@ -1,2 +0,2 @@ | ||
// Generated by CoffeeScript 2.0.0-beta3 | ||
// Generated by CoffeeScript 2.3.1 | ||
(function() { | ||
@@ -3,0 +3,0 @@ |
@@ -1,5 +0,7 @@ | ||
// Generated by CoffeeScript 2.0.0-beta3 | ||
// Generated by CoffeeScript 2.3.1 | ||
(function() { | ||
var base, i, len, method_count, module, name, njs_util, ref, route, routes, rpr, value, σ_cnd; | ||
'use strict'; | ||
var L, base, i, len, method_count, module, name, njs_util, ref, route, routes, rpr, value, σ_cnd; | ||
//########################################################################################################### | ||
njs_util = require('util'); | ||
@@ -9,2 +11,3 @@ | ||
//........................................................................................................... | ||
σ_cnd = Symbol.for('cnd'); | ||
@@ -20,2 +23,5 @@ | ||
//=========================================================================================================== | ||
// ACQUISITION | ||
//----------------------------------------------------------------------------------------------------------- | ||
method_count = 0; | ||
@@ -25,2 +31,5 @@ | ||
L = this; | ||
//........................................................................................................... | ||
for (i = 0, len = routes.length; i < len; i++) { | ||
@@ -36,3 +45,4 @@ route = routes[i]; | ||
if ((Object.prototype.toString.call(value)) === '[object Function]') { | ||
value = value.bind(module); | ||
// value = value.bind module if ( Object::toString.call value ) is '[object Function]' | ||
value = value.bind(L); | ||
} | ||
@@ -43,2 +53,3 @@ this[name] = value; | ||
//........................................................................................................... | ||
this.XJSON = require('./XJSON'); | ||
@@ -48,4 +59,9 @@ | ||
// ############################################################################################################ | ||
// unless module.parent? | ||
// console.log "acquired #{method_count} names from #{routes.length} sub-modules" | ||
// @dir @ | ||
}).call(this); | ||
//# sourceMappingURL=main.js.map |
@@ -1,13 +0,12 @@ | ||
// Generated by CoffeeScript 2.0.0-beta3 | ||
// Generated by CoffeeScript 2.3.1 | ||
(function() { | ||
var CND, suspend, | ||
slice = [].slice; | ||
splice = [].splice; | ||
CND = require('..'); | ||
/* original code from https://github.com/jmar777/suspend. */ | ||
//----------------------------------------------------------------------------------------------------------- | ||
suspend = function(context, generatorfn) { | ||
var arity, type; | ||
/* Like `https://github.com/jmar777/suspend`, but: | ||
@@ -22,5 +21,5 @@ * written in CoffeeScript; | ||
`suspend.eventually`); | ||
* more utilities possible in the future. | ||
*/ | ||
var arity, type; | ||
* more utilities possible in the future. */ | ||
// do_throw = options?[ 'throw' ] ? yes | ||
//......................................................................................................... | ||
switch (arity = arguments.length) { | ||
@@ -36,17 +35,19 @@ case 1: | ||
} | ||
//......................................................................................................... | ||
if ((type = CND.type_of(generatorfn)) !== 'generatorfunction') { | ||
throw new Error(`expected a generator function, got a ${type}`); | ||
} | ||
return function() { | ||
return function() { //......................................................................................................... | ||
var iterator; | ||
//....................................................................................................... | ||
Array.prototype.unshift.call(arguments, function(error) { | ||
var _arguments; | ||
_arguments = arguments; | ||
//..................................................................................................... | ||
/* Here we postpone sending errors and values until the next turn of the event loop; this will | ||
prevent `Generator is already running` errors in case a non-asynchronous function happened to be | ||
called. | ||
*/ | ||
called. */ | ||
return suspend.eventually(function() { | ||
if (error != null) { | ||
// if do_throw | ||
return iterator.throw(error); | ||
@@ -61,2 +62,6 @@ } | ||
}); | ||
// else | ||
// iterator.next Array::slice.call _arguments | ||
//....................................................................................................... | ||
// context ?= this | ||
iterator = generatorfn.apply(context, arguments); | ||
@@ -71,5 +76,4 @@ if (iterator.next != null) { | ||
//----------------------------------------------------------------------------------------------------------- | ||
/* Like `suspend`, but executing the suspended function immediately. */ | ||
suspend.step = function(...P) { | ||
@@ -79,8 +83,7 @@ return (suspend(...P))(); | ||
//----------------------------------------------------------------------------------------------------------- | ||
suspend.wrap = suspend.step.wrap = function(method, handler) { | ||
/* Since i've found that rarely some functions don't like to be called using `yield f resume`, i've added | ||
`suspend.wrap` (a.k.a. `suspend.step.wrap`) as a very thin wrapper that avoids such problems; simply | ||
call `yield step.wrap f, resume` in such cases. | ||
*/ | ||
call `yield step.wrap f, resume` in such cases. */ | ||
return method(function() { | ||
@@ -91,28 +94,25 @@ return handler(); | ||
//----------------------------------------------------------------------------------------------------------- | ||
suspend.after = function(time_s, handler) { | ||
/* `after` is a shim for `setTimeout` that adheres to NodeJS conventions, taking a `handler` | ||
callback function as last argument. Also, the timeout is given in humane seconds rather than in ms. | ||
*/ | ||
callback function as last argument. Also, the timeout is given in humane seconds rather than in ms. */ | ||
return setTimeout(handler, time_s * 1000); | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
suspend.eventually = function(handler) { | ||
/* `eventually f` is just another name for `process.nextTick f`—which in turn is basically equivalent to | ||
`after 0, f`. | ||
*/ | ||
`after 0, f`. */ | ||
return process.nextTick(handler); | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
suspend.immediately = function(handler) { | ||
/* `immediately f` is just another name for `setImmediate f`, which is very similar to | ||
`process.nextTick`. | ||
*/ | ||
`process.nextTick`. */ | ||
return setImmediate(handler); | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
suspend.repeat_immediately = function(method) { | ||
/* Accepts a function that should (when called without arguments) return a trueish or a falsey value | ||
@@ -122,4 +122,3 @@ to indicate whether to (when trueish) continue repeating or else (when falsey) stop repeating. The | ||
the return value, it will be scheduled to be run again with `setImmediate` semantics (i.e. like being | ||
scheduled with `setTimeout f, 0`) as long as it doesn't return a falsey value. | ||
*/ | ||
scheduled with `setTimeout f, 0`) as long as it doesn't return a falsey value. */ | ||
var f; | ||
@@ -136,14 +135,11 @@ f = function() { | ||
//----------------------------------------------------------------------------------------------------------- | ||
suspend.every = function(time_s, handler) { | ||
/* `every` is a shim for `setIntervall` that adheres to NodeJS conventions, taking a `handler` | ||
callback function as last argument. Also, the timeout is given in humane seconds rather than in ms. | ||
*/ | ||
callback function as last argument. Also, the timeout is given in humane seconds rather than in ms. */ | ||
return setInterval(handler, time_s * 1000); | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
suspend.collect = function(method, ...P) { | ||
var Z, finish, handler, has_finished, i, ref; | ||
ref = P, P = 2 <= ref.length ? slice.call(ref, 0, i = ref.length - 1) : (i = 0, []), handler = ref[i++]; | ||
/* `collect` is a convenience method for asynchronous functions that comply with the following interface: | ||
@@ -156,3 +152,3 @@ * They accept a number of arguments, the last of whioch is a callback handler. | ||
* When termination has been signalled and after an error has occurred, no more callbacks are performed. | ||
`collect` will collect all values in a list, which will be sent to the callback handler; there will be no | ||
@@ -163,9 +159,9 @@ extra call to signal completion. Each time `collect` receives data, it looks whether it has received one | ||
to callback. | ||
Usage example: | ||
step ( resume ) ->* | ||
lines = yield collect read_lines_of, route, resume | ||
log lines | ||
Mind the comma after the function name in the example—that function must be passed as the first argument, | ||
@@ -175,10 +171,12 @@ not called at this point in time. Also Remeber that in JavaScript, passing `library.method` will in most | ||
want to write | ||
lines = yield collect ( library.read_lines_of.bind library ), route, resume | ||
instead. This is a well-known, if unfortunate fact about JavaScript; proposals on how to better deal with | ||
this situation are welcome. | ||
*/ | ||
this situation are welcome. */ | ||
var Z, finish, handler, has_finished, ref; | ||
ref = P, [...P] = ref, [handler] = splice.call(P, -1); | ||
Z = []; | ||
has_finished = false; | ||
//......................................................................................................... | ||
finish = function() { | ||
@@ -188,2 +186,3 @@ has_finished = true; | ||
}; | ||
//......................................................................................................... | ||
method(...P, function(error, ...data) { | ||
@@ -213,5 +212,7 @@ var first_item; | ||
}); | ||
//......................................................................................................... | ||
return null; | ||
}; | ||
//########################################################################################################### | ||
module.exports = suspend; | ||
@@ -218,0 +219,0 @@ |
110
lib/tests.js
@@ -1,3 +0,5 @@ | ||
// Generated by CoffeeScript 2.0.0-beta3 | ||
// Generated by CoffeeScript 2.3.1 | ||
(function() { | ||
//########################################################################################################### | ||
// njs_util = require 'util' | ||
var CND, TRM, alert, badge, debug, echo, help, include, info, log, njs_path, praise, rpr, test, urge, warn, whisper, | ||
@@ -8,2 +10,4 @@ indexOf = [].indexOf; | ||
// njs_fs = require 'fs' | ||
//........................................................................................................... | ||
TRM = require('./TRM'); | ||
@@ -35,2 +39,3 @@ | ||
//........................................................................................................... | ||
CND = require('./main'); | ||
@@ -40,2 +45,27 @@ | ||
// #----------------------------------------------------------------------------------------------------------- | ||
// eq = ( P... ) => | ||
// whisper P | ||
// # throw new Error "not equal: \n#{( ( rpr p ) for p in P ).join '\n'}" unless CND.equals P... | ||
// unless CND.equals P... | ||
// warn "not equal: \n#{( ( rpr p ) for p in P ).join '\n'}" | ||
// return 1 | ||
// return 0 | ||
// #----------------------------------------------------------------------------------------------------------- | ||
// @_test = -> | ||
// error_count = 0 | ||
// for name, method of @ | ||
// continue if name.startsWith '_' | ||
// whisper name | ||
// try | ||
// method() | ||
// catch error | ||
// # throw error | ||
// error_count += +1 | ||
// warn error[ 'message' ] | ||
// help "tests completed successfully" if error_count is 0 | ||
// process.exit error_count | ||
//----------------------------------------------------------------------------------------------------------- | ||
this["test type_of"] = function(T) { | ||
@@ -67,2 +97,3 @@ T.eq(CND.type_of(new WeakMap()), 'weakmap'); | ||
T.eq(CND.type_of(new ArrayBuffer(42)), 'arraybuffer'); | ||
//......................................................................................................... | ||
T.eq(CND.type_of(new Int8Array(5)), 'int8array'); | ||
@@ -77,6 +108,12 @@ T.eq(CND.type_of(new Uint8Array(5)), 'uint8array'); | ||
T.eq(CND.type_of(new Float64Array(5)), 'float64array'); | ||
//......................................................................................................... | ||
return null; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this["test size_of"] = function(T) { | ||
// debug ( new Buffer '𣁬', ), ( '𣁬'.codePointAt 0 ).toString 16 | ||
// debug ( new Buffer '𡉜', ), ( '𡉜'.codePointAt 0 ).toString 16 | ||
// debug ( new Buffer '𠑹', ), ( '𠑹'.codePointAt 0 ).toString 16 | ||
// debug ( new Buffer '𠅁', ), ( '𠅁'.codePointAt 0 ).toString 16 | ||
T.eq(CND.size_of([1, 2, 3, 4]), 4); | ||
@@ -129,2 +166,3 @@ T.eq(CND.size_of(new Buffer([1, 2, 3, 4])), 4); | ||
//----------------------------------------------------------------------------------------------------------- | ||
this["is_subset"] = function(T) { | ||
@@ -145,7 +183,8 @@ T.eq(false, CND.is_subset(Array.from('abcde'), Array.from('abcd'))); | ||
T.eq(true, CND.is_subset(new Set(), new Set())); | ||
//......................................................................................................... | ||
return null; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this["deep_copy"] = function(T) { | ||
/* TAINT set comparison doesn't work */ | ||
@@ -155,7 +194,11 @@ var i, len, probe, probes, result; | ||
[ | ||
'foo', 42, [ | ||
'bar', (function() { | ||
'foo', | ||
42, | ||
[ | ||
'bar', | ||
(function() { | ||
return 'xxx'; | ||
}) | ||
], { | ||
], | ||
{ | ||
q: 'Q', | ||
@@ -166,2 +209,4 @@ s: 'S' | ||
]; | ||
// probe = [ 'foo', 42, [ 'bar', ( -> 'xxx' ), ], ( new Set Array.from 'abc' ), ] | ||
// matcher = [ 'foo', 42, [ 'bar', ( -> 'xxx' ), ], ( new Set Array.from 'abc' ), ] | ||
for (i = 0, len = probes.length; i < len; i++) { | ||
@@ -173,5 +218,7 @@ probe = probes[i]; | ||
} | ||
//......................................................................................................... | ||
return null; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this["XJSON (1)"] = function(T) { | ||
@@ -183,3 +230,2 @@ var d, e; | ||
T.eq(CND.XJSON.stringify(d), "[\"A\",\"B\",{\"~isa\":\"-x-set\",\"%self\":[\"x\",\"y\",{\"~isa\":\"-x-set\",\"%self\":[\"a\",\"b\",\"c\"]}]}]"); | ||
/* TAINT doing string comparison here to avoid implicit test that T.eq deals with sets correctly */ | ||
@@ -190,2 +236,3 @@ T.eq(rpr(CND.XJSON.parse(CND.XJSON.stringify(d))), "[ 'A', 'B', Set { 'x', 'y', Set { 'a', 'b', 'c' } } ]"); | ||
//----------------------------------------------------------------------------------------------------------- | ||
this["XJSON (2)"] = function(T) { | ||
@@ -196,5 +243,6 @@ var d, d_json, d_ng, d_ng_json, f, m, s; | ||
f = function(x) { | ||
return Math.pow(x, 2); | ||
return x ** 2; | ||
}; | ||
d = {s, m, f}; | ||
//......................................................................................................... | ||
d_json = CND.XJSON.stringify(d); | ||
@@ -204,6 +252,5 @@ d_ng = CND.XJSON.parse(d_json); | ||
T.eq(d_json, d_ng_json); | ||
//......................................................................................................... | ||
/* TAINT using T.eq directly on values, not their alternative serialization would implicitly test whether | ||
CND.equals accepts sets and maps | ||
*/ | ||
CND.equals accepts sets and maps */ | ||
T.eq(rpr(d_ng['s']), rpr(d['s'])); | ||
@@ -214,5 +261,7 @@ T.eq(rpr(d_ng['m']), rpr(d['m'])); | ||
T.eq(d_ng['f'](12), 144); | ||
//......................................................................................................... | ||
return null; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this["XJSON (3)"] = function(T) { | ||
@@ -228,4 +277,8 @@ var d, d_json, d_ng, d_ng_text; | ||
}; | ||
// my_arraybuffer: new ArrayBuffer 3 | ||
//......................................................................................................... | ||
d[Symbol.for('foo')] = 'bar'; | ||
d[Symbol('FOO')] = 'BAR'; | ||
//......................................................................................................... | ||
// help '01220', rpr d | ||
d_json = CND.XJSON.stringify(d); | ||
@@ -238,3 +291,2 @@ d_ng = CND.XJSON.parse(d_json); | ||
T.eq(d_ng.my_global_symbol, d.my_global_symbol); | ||
/* NOTE it's not possible to recreate the identity of a local symbol, so we check value and status: */ | ||
@@ -244,5 +296,7 @@ T.eq(d_ng.my_local_symbol.toString(), d.my_local_symbol.toString()); | ||
T.ok(d.my_local_symbol !== Symbol.for(d_ng_text)); | ||
//......................................................................................................... | ||
return null; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this["logging with timestamps"] = function(T, done) { | ||
@@ -258,2 +312,5 @@ var my_badge, my_help, my_info; | ||
//=========================================================================================================== | ||
// SUSPEND | ||
//----------------------------------------------------------------------------------------------------------- | ||
this["suspend (basic)"] = function(T, done) { | ||
@@ -270,2 +327,3 @@ var count, step, wait; | ||
while (true) { | ||
// debug JSON.stringify( name for name of @ ), @ is global, setTimeout | ||
count += +1; | ||
@@ -285,2 +343,3 @@ if (count >= 5) { | ||
//----------------------------------------------------------------------------------------------------------- | ||
this["suspend (with ordinary function)"] = function(T, done) { | ||
@@ -298,2 +357,3 @@ var step; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this["suspend (with custom this)"] = function(T, done) { | ||
@@ -314,2 +374,3 @@ var after, count, my_ctx, step; | ||
while (true) { | ||
// debug JSON.stringify( name for name of @ ), @ is global, setTimeout | ||
count += +1; | ||
@@ -329,13 +390,25 @@ whisper((yield this.wait(0.250, resume))); | ||
//----------------------------------------------------------------------------------------------------------- | ||
this["isa-generator"] = function(T, done) { | ||
var i, is_gen, is_genf, jr, len, probe, probes_and_matchers, result_is_gen, result_is_genf, type; | ||
probes_and_matchers = [ | ||
[(function() {}), false, false, 'function'], [ | ||
[(function() {}), | ||
false, | ||
false, | ||
'function'], | ||
[ | ||
(function*() { | ||
return (yield 42); | ||
}), false, true, 'generatorfunction' | ||
], [ | ||
}), | ||
false, | ||
true, | ||
'generatorfunction' | ||
], | ||
[ | ||
(function*() { | ||
return (yield 42); | ||
})(), true, false, 'generator' | ||
})(), | ||
true, | ||
false, | ||
'generator' | ||
] | ||
@@ -348,2 +421,4 @@ ]; | ||
result_is_genf = CND.isa_generator_function(probe); | ||
// debug jr [ probe, result_is_gen, result_is_genf, ] | ||
// debug ( CND.isa_function probe ), probe.constructor.name | ||
T.eq(result_is_gen, is_gen); | ||
@@ -356,2 +431,5 @@ T.eq(result_is_genf, is_genf); | ||
//=========================================================================================================== | ||
// MAIN | ||
//----------------------------------------------------------------------------------------------------------- | ||
this._main = function(handler) { | ||
@@ -363,2 +441,3 @@ return test(this, { | ||
//----------------------------------------------------------------------------------------------------------- | ||
this._prune = function() { | ||
@@ -379,2 +458,3 @@ var name, ref, value; | ||
//########################################################################################################### | ||
if (module.parent == null) { | ||
@@ -381,0 +461,0 @@ include = ["test type_of", "test size_of", "is_subset", "deep_copy", "XJSON (1)", "XJSON (2)", "XJSON (3)", "logging with timestamps", "suspend (basic)", "suspend (with ordinary function)", "suspend (with custom this)", "isa-generator"]; |
@@ -1,3 +0,6 @@ | ||
// Generated by CoffeeScript 2.0.0-beta3 | ||
// Generated by CoffeeScript 2.3.1 | ||
(function() { | ||
//----------------------------------------------------------------------------------------------------------- | ||
// Effects On | ||
//........................................................................................................... | ||
this.blink = "\x1b[5m"; | ||
@@ -11,2 +14,5 @@ | ||
//----------------------------------------------------------------------------------------------------------- | ||
// Effects Off | ||
//........................................................................................................... | ||
this.no_blink = "\x1b[25m"; | ||
@@ -22,2 +28,5 @@ | ||
//----------------------------------------------------------------------------------------------------------- | ||
// Colors | ||
//........................................................................................................... | ||
this.colors = { | ||
@@ -45,2 +54,4 @@ black: "\x1b[38;05;16m", | ||
white: "\x1b[38;05;255m", | ||
// experimental: | ||
// colors as defined by http://ethanschoonover.com/solarized | ||
BASE03: "\x1b[38;05;234m", | ||
@@ -64,15 +75,18 @@ BASE02: "\x1b[38;05;235m", | ||
this.cr = "\x1b[1G"; | ||
//----------------------------------------------------------------------------------------------------------- | ||
// Moves etc | ||
//........................................................................................................... | ||
this.cr = "\x1b[1G"; // Carriage Return; move to first column | ||
this.clear_line_right = "\x1b[0K"; | ||
this.clear_line_right = "\x1b[0K"; // Clear to end of line | ||
this.clear_line_left = "\x1b[1K"; | ||
this.clear_line_left = "\x1b[1K"; // Clear to start of line | ||
this.clear_line = "\x1b[2K"; | ||
this.clear_line = "\x1b[2K"; // Clear all line content | ||
this.clear_below = "\x1b[0J"; | ||
this.clear_below = "\x1b[0J"; // Clear to the bottom | ||
this.clear_above = "\x1b[1J"; | ||
this.clear_above = "\x1b[1J"; // Clear to the top (including current line) | ||
this.clear = "\x1b[2J"; | ||
this.clear = "\x1b[2J"; // Clear entire screen | ||
@@ -79,0 +93,0 @@ }).call(this); |
@@ -1,2 +0,2 @@ | ||
// Generated by CoffeeScript 2.0.0-beta3 | ||
// Generated by CoffeeScript 2.3.1 | ||
(function() { | ||
@@ -7,3 +7,5 @@ var CND, ansi_vt100_cc_matcher, rgb_hex_by_vt100_colorcode; | ||
//----------------------------------------------------------------------------------------------------------- | ||
rgb_hex_by_vt100_colorcode = { | ||
// Primary 3-bit 8 colors. Unique representation! | ||
'0': '000000', | ||
@@ -17,2 +19,3 @@ '1': '800000', | ||
'7': 'c0c0c0', | ||
// Equivalent "bright" versions of original 8 colors. | ||
'8': '808080', | ||
@@ -26,2 +29,3 @@ '9': 'ff0000', | ||
'15': 'ffffff', | ||
// Strictly ascending. | ||
'16': '000000', | ||
@@ -243,2 +247,3 @@ '17': '00005f', | ||
'231': 'ffffff', | ||
// Gray-scale range | ||
'232': '080808', | ||
@@ -270,6 +275,7 @@ '233': '121212', | ||
//----------------------------------------------------------------------------------------------------------- | ||
ansi_vt100_cc_matcher = /(?:\x1b\x5b)([\?=;0-9]*?)([ABCDHJKfhlmnpsu])/g; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.analyze = function(text) { | ||
/* Parse ANSI control codes out of `text` and return a list of alternating text / opcode chunks; the | ||
@@ -280,8 +286,8 @@ first element of the list and all elements with even indexes will represent (possibly empty) literal | ||
by the integer parameters. | ||
Adapted from https://github.com/atdt/escapes.js/blob/master/escapes.js | ||
*/ | ||
Adapted from https://github.com/atdt/escapes.js/blob/master/escapes.js */ | ||
var R, i, len, match, parameters, position, ref, x; | ||
R = []; | ||
while (true) { | ||
//......................................................................................................... | ||
position = ansi_vt100_cc_matcher.lastIndex; | ||
@@ -304,2 +310,3 @@ match = ansi_vt100_cc_matcher.exec(text); | ||
if (position < text.length) { | ||
//......................................................................................................... | ||
R.push(text.slice(position)); | ||
@@ -310,2 +317,3 @@ } | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.as_html = function(text, options) { | ||
@@ -315,2 +323,3 @@ return (this._as_html(text, options)).join(''); | ||
//----------------------------------------------------------------------------------------------------------- | ||
this._as_html = function(text, options) { | ||
@@ -325,2 +334,3 @@ var R, chunk, color_code, css_class, css_prefix, i, is_ansicode, j, len, n, open_span_count, ref, ref1, vt100_clear, vt100_reset; | ||
ref = this.analyze(text); | ||
//......................................................................................................... | ||
for (i = 0, len = ref.length; i < len; i++) { | ||
@@ -337,2 +347,3 @@ chunk = ref[i]; | ||
R.push(`<span style='color:#${rgb_hex_by_vt100_colorcode[color_code]};'>`); | ||
// R.push "<span class='#{css_class}'>" | ||
open_span_count += 1; | ||
@@ -342,3 +353,2 @@ } | ||
} else { | ||
/* TAINT must escape */ | ||
@@ -348,10 +358,13 @@ R.push(CND.escape_html(chunk)); | ||
} | ||
//......................................................................................................... | ||
if (open_span_count > 0 && ((options != null) && options['close-spans'])) { | ||
for (n = j = 0, ref1 = open_span_count; 0 <= ref1 ? j < ref1 : j > ref1; n = 0 <= ref1 ? ++j : --j) { | ||
for (n = j = 0, ref1 = open_span_count; (0 <= ref1 ? j < ref1 : j > ref1); n = 0 <= ref1 ? ++j : --j) { | ||
R.push('</span>'); | ||
} | ||
} | ||
//......................................................................................................... | ||
return R; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.get_css_source = function(options) { | ||
@@ -365,2 +378,3 @@ var R, color_code, css_prefix, rgb_hex; | ||
} | ||
//......................................................................................................... | ||
return R.join('\n'); | ||
@@ -367,0 +381,0 @@ }; |
205
lib/TRM.js
@@ -1,4 +0,5 @@ | ||
// Generated by CoffeeScript 2.0.0-beta3 | ||
// Generated by CoffeeScript 2.3.1 | ||
(function() { | ||
var TYPES, _rpr, badge, color_code, color_name, effect_name, effect_names, effect_off, effect_on, fn, fn1, get_timestamp, isa_text, lines_from_stdout, rainbow_color_names, rainbow_idx, ref, σ_cnd; | ||
//########################################################################################################### | ||
var TYPES, _rpr, badge, color_code, color_name, effect_name, effect_names, effect_off, effect_on, get_timestamp, isa_text, lines_from_stdout, rainbow_color_names, rainbow_idx, ref, σ_cnd; | ||
@@ -23,2 +24,14 @@ this.constants = require('./TRM-CONSTANTS'); | ||
// #----------------------------------------------------------------------------------------------------------- | ||
// @rpr = ( x ) -> | ||
// try | ||
// if x.toString? and ( x.toString isnt Object::toString ) | ||
// return x.toString() | ||
// else | ||
// return @_rpr x | ||
// catch error | ||
// throw error unless /^Cannot read property/.test error[ 'message' ] | ||
// return @_rpr x | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.rpr = function(x) { | ||
@@ -30,2 +43,3 @@ return _rpr(x, { | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.get_output_method = function(target, options) { | ||
@@ -37,12 +51,11 @@ return (...P) => { | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.pen = function(...P) { | ||
/* Given any number of arguments, return a text representing the arguments as seen fit for output | ||
commands like `log`, `echo`, and the colors. | ||
*/ | ||
commands like `log`, `echo`, and the colors. */ | ||
return (this._pen(...P)).concat('\n'); | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this._pen = function(...P) { | ||
/* ... */ | ||
@@ -62,2 +75,3 @@ var R, p; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.log = this.get_output_method(process.stderr); | ||
@@ -67,9 +81,11 @@ | ||
//=========================================================================================================== | ||
// KEY CAPTURING | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.listen_to_keys = function(handler) { | ||
/* thx to http://stackoverflow.com/a/12506613/256361 */ | ||
/* try not to bind handler to same handler more than once: */ | ||
var R, help, last_key_was_ctrl_c; | ||
if (handler.__TRM__listen_to_keys__is_registered) { | ||
/* thx to http://stackoverflow.com/a/12506613/256361 */ | ||
//......................................................................................................... | ||
/* try not to bind handler to same handler more than once: */ | ||
return null; | ||
@@ -87,2 +103,3 @@ } | ||
R.resume(); | ||
//......................................................................................................... | ||
R.on('data', (key) => { | ||
@@ -101,5 +118,7 @@ var response; | ||
}); | ||
//......................................................................................................... | ||
return R; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.ask = function(prompt, handler) { | ||
@@ -112,2 +131,3 @@ var rl; | ||
if (!/\s+$/.test(prompt)) { | ||
//......................................................................................................... | ||
prompt += ' '; | ||
@@ -121,2 +141,24 @@ } | ||
// #=========================================================================================================== | ||
// # SHELL COMMANDS | ||
// #----------------------------------------------------------------------------------------------------------- | ||
// @execute = ( command, handler ) -> | ||
// unless handler? | ||
// ### https://github.com/gvarsanyi/sync-exec ### | ||
// exec = require 'sync-exec' | ||
// #........................................................................................................... | ||
// { stdout | ||
// stderr | ||
// status } = exec 'ls' | ||
// throw new Error stderr if stderr? and stderr.length > 0 | ||
// return lines_from_stdout stdout | ||
// #......................................................................................................... | ||
// ( require 'child_process' ).exec O[ 'on-change' ], ( error, stdout, stderr ) => | ||
// return handler error if error? | ||
// return handler new Error stderr if stderr? and stderr.length isnt 0 | ||
// handler null, lines_from_stdout stdout | ||
// #......................................................................................................... | ||
// return null | ||
//----------------------------------------------------------------------------------------------------------- | ||
lines_from_stdout = function(stdout) { | ||
@@ -131,2 +173,3 @@ var R; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.spawn = function(command, parameters, handler) { | ||
@@ -138,5 +181,9 @@ var R; | ||
R.on('close', handler); | ||
//......................................................................................................... | ||
return R; | ||
}; | ||
//=========================================================================================================== | ||
// COLORS & EFFECTS | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.clear_line_right = this.constants.clear_line_right; | ||
@@ -154,2 +201,3 @@ | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.goto = function(line_nr = 1, column_nr = 1) { | ||
@@ -163,2 +211,3 @@ return `\x1b[${line_nr};${column_nr}H`; | ||
//........................................................................................................... | ||
this.up = function(count = 1) { | ||
@@ -180,2 +229,3 @@ return `\x1b[${count}A`; | ||
//........................................................................................................... | ||
this.move = function(line_count, column_count) { | ||
@@ -185,2 +235,3 @@ return (line_count < 0 ? this.up(line_count) : this.down(line_count)) + (column_count < 0 ? this.left(column_count) : this.right(column_count)); | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.ring_bell = function() { | ||
@@ -190,2 +241,3 @@ return process.stdout.write("\x07"); | ||
//----------------------------------------------------------------------------------------------------------- | ||
effect_names = { | ||
@@ -198,54 +250,70 @@ blink: 1, | ||
fn = (effect_name, effect_on, effect_off) => { | ||
return this[effect_name] = (...P) => { | ||
var R, i, idx, last_idx, len, p; | ||
R = [effect_on]; | ||
last_idx = P.length - 1; | ||
for (idx = i = 0, len = P.length; i < len; idx = ++i) { | ||
p = P[idx]; | ||
R.push(isa_text(p) ? p : this.rpr(p)); | ||
if (idx !== last_idx) { | ||
R.push(effect_on); | ||
R.push(this.separator); | ||
} | ||
} | ||
R.push(effect_off); | ||
return R.join(''); | ||
}; | ||
}; | ||
//........................................................................................................... | ||
for (effect_name in effect_names) { | ||
effect_on = this.constants[effect_name]; | ||
effect_off = this.constants['no_' + effect_name]; | ||
fn(effect_name, effect_on, effect_off); | ||
((effect_name, effect_on, effect_off) => { | ||
return this[effect_name] = (...P) => { | ||
var R, i, idx, last_idx, len, p; | ||
R = [effect_on]; | ||
last_idx = P.length - 1; | ||
for (idx = i = 0, len = P.length; i < len; idx = ++i) { | ||
p = P[idx]; | ||
R.push(isa_text(p) ? p : this.rpr(p)); | ||
if (idx !== last_idx) { | ||
R.push(effect_on); | ||
R.push(this.separator); | ||
} | ||
} | ||
R.push(effect_off); | ||
return R.join(''); | ||
}; | ||
})(effect_name, effect_on, effect_off); | ||
} | ||
ref = this.constants['colors']; | ||
fn1 = (color_name, color_code) => { | ||
return this[color_name] = (...P) => { | ||
var R, i, idx, last_idx, len, p; | ||
R = [color_code]; | ||
last_idx = P.length - 1; | ||
for (idx = i = 0, len = P.length; i < len; idx = ++i) { | ||
p = P[idx]; | ||
R.push(isa_text(p) ? p : this.rpr(p)); | ||
if (idx !== last_idx) { | ||
R.push(color_code); | ||
R.push(this.separator); | ||
} | ||
} | ||
R.push(this.constants['reset']); | ||
return R.join(''); | ||
}; | ||
}; | ||
//........................................................................................................... | ||
for (color_name in ref) { | ||
color_code = ref[color_name]; | ||
fn1(color_name, color_code); | ||
((color_name, color_code) => { | ||
return this[color_name] = (...P) => { | ||
var R, i, idx, last_idx, len, p; | ||
R = [color_code]; | ||
last_idx = P.length - 1; | ||
for (idx = i = 0, len = P.length; i < len; idx = ++i) { | ||
p = P[idx]; | ||
R.push(isa_text(p) ? p : this.rpr(p)); | ||
if (idx !== last_idx) { | ||
R.push(color_code); | ||
R.push(this.separator); | ||
} | ||
} | ||
R.push(this.constants['reset']); | ||
return R.join(''); | ||
}; | ||
})(color_name, color_code); | ||
} | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.remove_colors = function(text) { | ||
// this one from http://regexlib.com/UserPatterns.aspx?authorId=f3ce5c3c-5970-48ed-9c4e-81583022a387 | ||
// looks smarter but isn't JS-compatible: | ||
// return text.replace /(?s)(?:\e\[(?:(\d+);?)*([A-Za-z])(.*?))(?=\e\[|\z)/g, '' | ||
return text.replace(this.color_matcher, ''); | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.color_matcher = /\x1b\[[^m]*m/g; | ||
// #----------------------------------------------------------------------------------------------------------- | ||
// $.length_of_ansi_text = ( text ) -> | ||
// return ( text.replace /\x1b[^m]m/, '' ).length | ||
// #----------------------------------------------------------------------------------------------------------- | ||
// $.truth = ( P... ) -> | ||
// return ( ( ( if p == true then green else if p == false then red else white ) p ) for p in P ).join '' | ||
//----------------------------------------------------------------------------------------------------------- | ||
// rainbow_color_names = """blue tan cyan sepia indigo steel brown red olive lime crimson green plum orange pink | ||
// gold yellow""".split /\s+/ | ||
rainbow_color_names = "red orange yellow green blue pink".split(/\s+/); | ||
@@ -255,2 +323,3 @@ | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.rainbow = function(...P) { | ||
@@ -261,2 +330,3 @@ rainbow_idx = (rainbow_idx + 1) % rainbow_color_names.length; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.route = function(...P) { | ||
@@ -266,2 +336,3 @@ return this.lime(this.underline(...P)); | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.truth = function(...P) { | ||
@@ -280,5 +351,8 @@ var p; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.get_logger = function(category, badge = null) { | ||
var R, colorize, pointer, prefix; | ||
//......................................................................................................... | ||
switch (category) { | ||
//....................................................................................................... | ||
case 'plain': | ||
@@ -288,2 +362,3 @@ colorize = null; | ||
break; | ||
//....................................................................................................... | ||
case 'info': | ||
@@ -293,2 +368,3 @@ colorize = this.BLUE.bind(this); | ||
break; | ||
//....................................................................................................... | ||
case 'whisper': | ||
@@ -298,2 +374,3 @@ colorize = this.grey.bind(this); | ||
break; | ||
//....................................................................................................... | ||
case 'urge': | ||
@@ -303,2 +380,3 @@ colorize = this.orange.bind(this); | ||
break; | ||
//....................................................................................................... | ||
case 'praise': | ||
@@ -308,2 +386,3 @@ colorize = this.GREEN.bind(this); | ||
break; | ||
//....................................................................................................... | ||
case 'debug': | ||
@@ -313,2 +392,3 @@ colorize = this.pink.bind(this); | ||
break; | ||
//....................................................................................................... | ||
case 'alert': | ||
@@ -318,2 +398,3 @@ colorize = this.RED.bind(this); | ||
break; | ||
//....................................................................................................... | ||
case 'warn': | ||
@@ -323,2 +404,3 @@ colorize = this.RED.bind(this); | ||
break; | ||
//....................................................................................................... | ||
case 'help': | ||
@@ -329,5 +411,8 @@ colorize = this.lime.bind(this); | ||
default: | ||
//....................................................................................................... | ||
throw new Error(`unknown logger category ${_rpr(category)}`); | ||
} | ||
//......................................................................................................... | ||
prefix = badge != null ? (this.grey(badge)).concat(' ', pointer) : pointer; | ||
//......................................................................................................... | ||
if (colorize != null) { | ||
@@ -342,5 +427,7 @@ R = (...P) => { | ||
} | ||
//......................................................................................................... | ||
return R; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
get_timestamp = function() { | ||
@@ -362,5 +449,11 @@ var m, s, t1; | ||
//=========================================================================================================== | ||
// EXTRACTING COLORS / CONVERTING COLORS TO HTML | ||
//----------------------------------------------------------------------------------------------------------- | ||
/* TAINT naming unstable, to be renamed */ | ||
// @as_html = @ANSI.as_html.bind @ANSI | ||
// @get_css_source = @ANSI.get_css_source.bind @ANSI | ||
// @analyze = @ANSI.analyze.bind @ANSI | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.clean = function(text) { | ||
@@ -377,2 +470,3 @@ var R, chunk, is_ansicode; | ||
if ((is_ansicode = !is_ansicode)) { | ||
//......................................................................................................... | ||
results.push(chunk); | ||
@@ -385,4 +479,8 @@ } | ||
//=========================================================================================================== | ||
// VALUE REPORTING | ||
//----------------------------------------------------------------------------------------------------------- | ||
this._prototype_of_object = Object.getPrototypeOf(new Object()); | ||
//----------------------------------------------------------------------------------------------------------- | ||
this._dir_options = { | ||
@@ -393,2 +491,3 @@ 'skip-list-idxs': true, | ||
//----------------------------------------------------------------------------------------------------------- | ||
this._marker_by_type = { | ||
@@ -398,2 +497,3 @@ 'function': '()' | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.dir = function(...P) { | ||
@@ -419,3 +519,3 @@ var arity, i, idx, len, p, r, width, x; | ||
if (r.length > width) { | ||
r = r.slice(0, +Math.max(5, width - 5) + 1 || 9e9).concat(this.grey(' ...')); | ||
r = r.slice(0, +(Math.max(5, width - 5)) + 1 || 9e9).concat(this.grey(' ...')); | ||
} | ||
@@ -425,2 +525,3 @@ return this.log('\n'.concat(this.lime(r), '\n', (this._dir(x)).join(this.grey(' ')), '\n')); | ||
//----------------------------------------------------------------------------------------------------------- | ||
this._dir = function(x) { | ||
@@ -443,2 +544,3 @@ var R, i, j, len, len1, marker, name, names, p, ref1, role, type; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this._is_list_idx = function(idx_txt, length) { | ||
@@ -452,2 +554,3 @@ var ref1; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this._marker_from_type = function(type) { | ||
@@ -458,2 +561,3 @@ var ref1; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this._get_prototypes_types_and_property_names = function(x, types_and_names) { | ||
@@ -467,2 +571,3 @@ var error, length, name, names, prototype, role, x_; | ||
try { | ||
//......................................................................................................... | ||
names = Object.getOwnPropertyNames(x); | ||
@@ -480,2 +585,3 @@ prototype = Object.getPrototypeOf(x); | ||
try { | ||
//......................................................................................................... | ||
length = x.length; | ||
@@ -501,7 +607,10 @@ if (length != null) { | ||
} | ||
//......................................................................................................... | ||
names.sort(); | ||
types_and_names.push([role, x, TYPES.type_of(x), names]); | ||
//......................................................................................................... | ||
if ((prototype != null) && !(this._dir_options['skip-object'] && prototype === this._prototype_of_object)) { | ||
this._get_prototypes_types_and_property_names(prototype, types_and_names); | ||
} | ||
//......................................................................................................... | ||
return types_and_names; | ||
@@ -508,0 +617,0 @@ }; |
124
lib/TYPES.js
@@ -1,3 +0,4 @@ | ||
// Generated by CoffeeScript 2.0.0-beta3 | ||
// Generated by CoffeeScript 2.3.1 | ||
(function() { | ||
//########################################################################################################### | ||
var js_type_of, log, njs_util, rpr; | ||
@@ -11,2 +12,3 @@ | ||
//----------------------------------------------------------------------------------------------------------- | ||
njs_util = require('util'); | ||
@@ -18,7 +20,17 @@ | ||
//........................................................................................................... | ||
//=========================================================================================================== | ||
// TYPE ELUCIDATION | ||
//----------------------------------------------------------------------------------------------------------- | ||
this._coffeenode_type_by_js_type = { | ||
'[object Array]': 'list', | ||
// '[object Boolean]': 'boolean' | ||
'[object Function]': 'function', | ||
// '[object Null]': 'null' | ||
'[object String]': 'text', | ||
//......................................................................................................... | ||
'[object Generator]': 'generator', | ||
//......................................................................................................... | ||
// '[object Undefined]': 'jsundefined' | ||
'[object Arguments]': 'arguments', | ||
@@ -32,2 +44,3 @@ '[object Date]': 'date', | ||
'[object ArrayBuffer]': 'arraybuffer', | ||
//......................................................................................................... | ||
'[object Object]': function(x) { | ||
@@ -39,8 +52,9 @@ if (Buffer.isBuffer(x)) { | ||
}, | ||
//......................................................................................................... | ||
'[object Number]': function(x) { | ||
/* TAINT isNaN is broken as per https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN#Description */ | ||
if (isNaN(x)) { | ||
/* TAINT isNaN is broken as per https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN#Description */ | ||
return 'nan'; | ||
} | ||
// return 'jsinfinity' if x == Infinity or x == -Infinity | ||
return 'number'; | ||
@@ -50,5 +64,7 @@ } | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.type_of = function(x) { | ||
"Given any kind of value ``x``, return its type."; | ||
var R, js_type; | ||
//......................................................................................................... | ||
switch (x) { | ||
@@ -66,2 +82,3 @@ case null: | ||
} | ||
//......................................................................................................... | ||
R = x['~isa']; | ||
@@ -72,2 +89,3 @@ if (R != null) { | ||
if (Buffer.isBuffer(x)) { | ||
//......................................................................................................... | ||
return 'buffer'; | ||
@@ -87,7 +105,25 @@ } | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.isa = function(x, probe) { | ||
"Given any value ``x`` and a non-empty text ``probe``, return whether ``TYPES/type_of x`` equals\n``probe``."; | ||
// validate_name probe | ||
return (this.type_of(x)) === probe; | ||
}; | ||
//=========================================================================================================== | ||
// TYPE TESTING | ||
//----------------------------------------------------------------------------------------------------------- | ||
// It is outright incredible, some would think frightening, how much manpower has gone into reliable | ||
// JavaScript type checking. Here is the latest and greatest for a language that can claim to be second | ||
// to none when it comes to things that should be easy but aren’t: the ‘Miller Device’ by Mark Miller of | ||
// Google (http://www.caplet.com), popularized by James Crockford of Yahoo!.* | ||
// As per https://groups.google.com/d/msg/nodejs/P_RzSyPkjkI/NvP28SXvf24J, now also called the 'Flanagan | ||
// Device' | ||
// http://ajaxian.com/archives/isarray-why-is-it-so-bloody-hard-to-get-right | ||
// http://blog.360.yahoo.com/blog-TBPekxc1dLNy5DOloPfzVvFIVOWMB0li?p=916 # page gone | ||
// http://zaa.ch/past/2009/1/31/the_miller_device_on_null_and_other_lowly_unvalues/ # moved to: | ||
// http://zaa.ch/post/918977126/the-miller-device-on-null-and-other-lowly-unvalues | ||
//........................................................................................................... | ||
this.isa_list = function(x) { | ||
@@ -129,2 +165,3 @@ return (js_type_of(x)) === '[object Array]'; | ||
//........................................................................................................... | ||
this.isa_jsarguments = function(x) { | ||
@@ -134,5 +171,3 @@ return (js_type_of(x)) === '[object Arguments]'; | ||
/* TAINT isNaN is broken as per https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN#Description */ | ||
this.isa_jsnotanumber = function(x) { | ||
@@ -170,5 +205,7 @@ return isNaN(x); | ||
//........................................................................................................... | ||
// @isa_jsbuffer = Buffer.isBuffer | ||
//----------------------------------------------------------------------------------------------------------- | ||
/* https://github.com/blakeembrey/is-generator/blob/master/is-generator.js */ | ||
this.isa_generator = function(x) { | ||
@@ -182,2 +219,5 @@ return (x != null) && (typeof x.next === 'function') && (typeof x.throw === 'function'); | ||
//----------------------------------------------------------------------------------------------------------- | ||
// Replace some of our ``isa_*`` methods by the ≈6× faster methods provided by NodeJS ≥ 0.6.0, where | ||
// available: | ||
this.isa_list = Array.isArray; | ||
@@ -187,2 +227,50 @@ | ||
// @isa_jsregex = njs_util.isRegExp if njs_util.isRegExp? | ||
// @isa_jsdate = njs_util.isDate if njs_util.isDate? | ||
// @isa_boolean = njs_util.isBoolean if njs_util.isBoolean? | ||
// @isa_jserror = njs_util.isError if njs_util.isError? | ||
// @isa_function = njs_util.isFunction if njs_util.isFunction? | ||
// @isa_primitive = njs_util.isPrimitive if njs_util.isPrimitive? | ||
// @isa_text = njs_util.isString if njs_util.isString? | ||
// @isa_jsundefined = njs_util.isUndefined if njs_util.isUndefined? | ||
// @isa_null = njs_util.isNull if njs_util.isNull? | ||
// @isa_nullorundefined = njs_util.isNullOrUndefined if njs_util.isNullOrUndefined? | ||
// @isa_number = njs_util.isNumber if njs_util.isNumber? | ||
// @isa_object = njs_util.isObject if njs_util.isObject? | ||
// @isa_symbol = njs_util.isSymbol if njs_util.isSymbol? | ||
//=========================================================================================================== | ||
// TYPE FEATURES | ||
//----------------------------------------------------------------------------------------------------------- | ||
// these await further elaboration | ||
// @is_mutable = ( x ) -> return type_features[ @type_of x ][ 'mutable' ] is true | ||
// @is_indexed = ( x ) -> return type_features[ @type_of x ][ 'indexed' ] is true | ||
// @is_facetted = ( x ) -> return type_features[ @type_of x ][ 'facetted' ] is true | ||
// @is_ordered = ( x ) -> return type_features[ @type_of x ][ 'ordered' ] is true | ||
// @is_repetitive = ( x ) -> return type_features[ @type_of x ][ 'repetitive' ] is true | ||
// @is_single_valued = ( x ) -> return type_features[ @type_of x ][ 'single_valued' ] is true | ||
// @is_dense = ( x ) -> return type_features[ @type_of x ][ 'dense' ] is true | ||
// @is_callable = ( x ) -> return type_features[ @type_of x ][ 'callable' ] is true | ||
// @is_numeric = ( x ) -> return type_features[ @type_of x ][ 'numeric' ] is true | ||
// @is_basic = ( x ) -> return type_features[ @type_of x ][ 'basic' ] is true | ||
// @is_ecma = ( x ) -> return type_features[ @type_of x ][ 'ecma' ] is true | ||
// @is_covered_by_json = ( x ) -> return type_features[ @type_of x ][ 'json' ] is true | ||
//=========================================================================================================== | ||
// HELPERS | ||
//----------------------------------------------------------------------------------------------------------- | ||
// vaq = validate_argument_count_equals = ( count ) -> | ||
// a = arguments.callee.caller.arguments | ||
// unless a.length == count then throw new Error "expected #{count} arguments, got #{a.length}" | ||
// #----------------------------------------------------------------------------------------------------------- | ||
// validate_name = ( x ) -> | ||
// unless @isa_text x then throw new Error "expected a text, got a #{@type_of x}" | ||
// unless x.length > 0 then throw new Error "expected a non-empty text, got an empty one" | ||
//----------------------------------------------------------------------------------------------------------- | ||
// This registry lists all types that can be meaningfully compared using JS's ``===`` / CS's ``==`` strict | ||
// equality operator; conspicuously absent here are lists and PODs, for which the Δ method ``equals`` should | ||
// be used instead: | ||
this.simple_equality_types = { | ||
@@ -197,2 +285,4 @@ 'number': true, | ||
//----------------------------------------------------------------------------------------------------------- | ||
// This registry lists all types that can be meaningfully compared using `<` and `>`: | ||
this.simple_comparison_types = { | ||
@@ -206,2 +296,7 @@ 'number': true, | ||
// 'jsundefined': true | ||
//----------------------------------------------------------------------------------------------------------- | ||
// 'ISA' VALIDATION | ||
//........................................................................................................... | ||
this.validate_isa = function(x, ...types) { | ||
@@ -212,2 +307,3 @@ var i, len, message, probe_type, type; | ||
} | ||
//......................................................................................................... | ||
probe_type = this.type_of(x); | ||
@@ -220,2 +316,3 @@ for (i = 0, len = types.length; i < len; i++) { | ||
} | ||
//......................................................................................................... | ||
if (types.length === 1) { | ||
@@ -227,6 +324,7 @@ message = `expected a ${types[0]}, got a ${probe_type}`; | ||
} | ||
//......................................................................................................... | ||
return null; | ||
}; | ||
(() => { | ||
(() => { //----------------------------------------------------------------------------------------------------------- | ||
var match, name, results, type; | ||
@@ -240,2 +338,3 @@ results = []; | ||
type = match[1]; | ||
//....................................................................................................... | ||
results.push(((name, type) => { | ||
@@ -253,4 +352,15 @@ return this[`validate_${name}`] = function(x) { | ||
//----------------------------------------------------------------------------------------------------------- | ||
// TAG VALIDATION | ||
//........................................................................................................... | ||
// do -> | ||
// for name of TYPES | ||
// continue unless name.match /^is_/ | ||
// do ( name ) -> | ||
// $[ "validate_#{name}" ] = ( x ) -> | ||
// return null if TYPES[ name ] x | ||
// throw new Error "expected a x, got a #{TYPES.type_of x}" | ||
}).call(this); | ||
//# sourceMappingURL=TYPES.js.map |
@@ -1,10 +0,9 @@ | ||
// Generated by CoffeeScript 2.0.0-beta3 | ||
// Generated by CoffeeScript 2.3.1 | ||
(function() { | ||
/* | ||
/* | ||
https://github.com/loveencounterflow/universal-copy | ||
https://github.com/nrn/universal-copy | ||
https://github.com/loveencounterflow/universal-copy | ||
https://github.com/nrn/universal-copy | ||
*/ | ||
(function() { | ||
*/ | ||
@@ -11,0 +10,0 @@ var OPtoString = Object.prototype.toString |
@@ -1,3 +0,4 @@ | ||
// Generated by CoffeeScript 2.0.0-beta3 | ||
// Generated by CoffeeScript 2.3.1 | ||
(function() { | ||
//########################################################################################################### | ||
var CND, log, rpr; | ||
@@ -11,8 +12,25 @@ | ||
// badge = 'scratch' | ||
// log = CND.get_logger 'plain', badge | ||
// info = CND.get_logger 'info', badge | ||
// whisper = CND.get_logger 'whisper', badge | ||
// alert = CND.get_logger 'alert', badge | ||
// debug = CND.get_logger 'debug', badge | ||
// warn = CND.get_logger 'warn', badge | ||
// help = CND.get_logger 'help', badge | ||
// urge = CND.get_logger 'urge', badge | ||
// echo = CND.echo.bind CND | ||
// rainbow = CND.rainbow.bind CND | ||
// suspend = require 'coffeenode-suspend' | ||
// step = suspend.step | ||
// after = suspend.after | ||
// eventually = suspend.eventually | ||
// immediately = suspend.immediately | ||
// every = suspend.every | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.replacer = function(key, value) { | ||
var data, local, type; | ||
/* NOTE Buffers are treated specially; at this point, they are already converted into sth that looks | ||
like `{ type: 'Buffer', data: [ ... ], }`. | ||
*/ | ||
var data, local, type; | ||
like `{ type: 'Buffer', data: [ ... ], }`. */ | ||
if ((CND.isa_pod(value)) && (value['type'] === 'Buffer') && (CND.isa_list(data = value['data']))) { | ||
@@ -24,3 +42,5 @@ return { | ||
} | ||
//......................................................................................................... | ||
switch (type = CND.type_of(value)) { | ||
//....................................................................................................... | ||
case 'nan': | ||
@@ -30,2 +50,3 @@ return { | ||
}; | ||
//....................................................................................................... | ||
case 'set': | ||
@@ -46,2 +67,3 @@ return { | ||
}; | ||
//....................................................................................................... | ||
case 'symbol': | ||
@@ -56,10 +78,15 @@ data = value.toString().replace(/^Symbol\((.*)\)$/, '$1'); | ||
} | ||
//......................................................................................................... | ||
return value; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.reviver = function(key, value) { | ||
var type; | ||
//......................................................................................................... | ||
switch (type = CND.type_of(value)) { | ||
//....................................................................................................... | ||
case '-x-nan': | ||
return 0/0; | ||
//....................................................................................................... | ||
case '-x-buffer': | ||
@@ -76,5 +103,7 @@ return Buffer.from(value['%self']); | ||
} | ||
//......................................................................................................... | ||
return value; | ||
}; | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.stringify = function(value, replacer, spaces) { | ||
@@ -87,2 +116,3 @@ if (replacer == null) { | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.parse = function(text, reviver) { | ||
@@ -95,2 +125,3 @@ if (reviver == null) { | ||
//----------------------------------------------------------------------------------------------------------- | ||
this.replacer = this.replacer.bind(this); | ||
@@ -97,0 +128,0 @@ |
{ | ||
"name": "cnd", | ||
"version": "4.3.1", | ||
"version": "4.4.0", | ||
"description": "a grab-bag NodeJS package mainly for functionalities that used to live in coffeenode-trm, coffeenode-bitsnpieces, and coffeenode-types", | ||
@@ -5,0 +5,0 @@ "main": "lib/main.js", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
442269
3075
42