Installations
npm install cnd
Developer Guide
Typescript
No
Module System
CommonJS
Node Version
19.7.0
NPM Version
9.5.0
Score
73
Supply Chain
78.9
Quality
75.3
Maintenance
100
Vulnerability
99.3
License
Releases
Unable to fetch releases
Contributors
Unable to fetch Contributors
Languages
CoffeeScript (86.44%)
JavaScript (13.33%)
Shell (0.22%)
Developer
loveencounterflow
Download Statistics
Total Downloads
73,707
Last Day
7
Last Week
80
Last Month
311
Last Year
4,328
GitHub Statistics
231 Commits
3 Watching
3 Branches
1 Contributors
Bundle Size
18.83 kB
Minified
7.10 kB
Minified + Gzipped
Package Meta Information
Latest Version
9.3.0
Package Id
cnd@9.3.0
Unpacked Size
267.25 kB
Size
69.01 kB
File Count
33
NPM Version
9.5.0
Node Version
19.7.0
Publised On
04 Mar 2023
Total Downloads
Cumulative downloads
Total Downloads
73,707
Last day
-78.8%
7
Compared to previous day
Last week
-42%
80
Compared to previous week
Last month
-1.6%
311
Compared to previous month
Last year
-67.2%
4,328
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
Dependencies
2
Table of Contents generated with DocToc
cnd
a grab-bag NodeJS package mainly for functionalities that used to live in coffeenode-trm, coffeenode-bitsnpieces, and coffeenode-types
CND Interval Tree
-
Simplified API (compared to
functional-red-black-tree
) -
possible to dynamically add nodes
-
possible to access underlying red/black tree as
tree[ '%self' ]
, root node astree[ '%self' ][ 'root' ]
-
possible to access
1CND = require 'cnd' 2ITREE = CND.INTERVALTREE 3tree = ITREE.new_tree() 4intervals = [ 5 [ 3, 7, 'A', ] 6 [ 5, 7, 'B', ] 7 [ 8, 12, 'C', ] 8 [ 2, 14, 'D', ] 9 [ 4, 4, 'E', ] 10 ] 11ITREE.add_interval tree, interval for interval in intervals 12for n in [ 0 .. 15 ] 13 console.log n 14 for node in ITREE.find tree, n 15 console.log node[ 'key' ], node[ 'value' ]
CND Shim
CND now includes https://github.com/es-shims/es6-shim and https://github.com/es-shims/es7-shim; in order to use these, say
1CND = require 'cnd' 2CND.shim()
which will then polyfill you current runtime to the point where you approximately
reach compatibility with NodeJS v0.12 run with the --harmony
switch. Note
that not everything can be polyfilled; in particular WeakMaps and yield
cannot
be provided this way.
CND TSort
CND TSort implements a simple tool to perform the often-needed requirement of doing a topological sorting over an DAG (directed acyclic graph). It is an adaption of the npm: tsort module.
Here is the basic usage: you instantiate a graph by saying e.g.
1CND = require 'cnd' 2TS = CND.TSORT 3settings = 4 strict: yes 5 prefixes: [ 'f|', 'g|', ] 6graph = TS.new_graph settings
The settings
object itself and its members are optional. The strict
setting
(true by default) will check for the well-formedness on the graph each time a
relationship is entered; this means you get early errors at the cost of
decreased performance. We come back to the prefixes
later; the default is not
to use prefixes.
Topological sorting is all about finding a total, linear ordering of actions, values, objects or whatever from a series of statements about the relative ordering of pairs of such objects. This is used in many fields, for example in package management, project management, programming language grammars and so on.
So let's say you have a todo list:
1'buy books' 2'buy food' 3'buy food' 4'cook' 5'do some reading' 6'eat' 7'fetch money' 8'go home' 9'go to bank' 10'go to exam' 11'go to market'
Now you don't have money, foods or books at home right now, but you want to eat, do some reading, and go to the exam after that, so clearly there are certain orderings of events that would make more sense than other orderings. It's perhaps not immediately clear how you can organize all these jobs when you look at the entire list, but given any two jobs, it's often easy to see which one should preced the other one.
Once we have instantiated a graph g
, we can add dual relationships piecemeal,
the convention being that we imagine arrows or links pointing from preconditions
'down' to consequences, which is why the corresponding method is named
link_down
. Calling TS.link_down g, 'buy food', 'cook'
means: 'Add a link to
graph g
to indicate that before I can 'cook'
, I have to 'buy food'
first',
and so on. It is customary to symbolically write 'buy food' > 'cook'
to
indicate the dependency.
In case the graph has been instantiated with a strict: yes
setting, CND TSort
will validate the graph for each single new relationship; as a side effect, a
list of entries is produced and returned that reflects one of the possible
linearizations of the graph which satisfies all requirements so far. For the
purpose of demonstration, we can take advantage of that list and print it out;
we can see that the ordering of jobs will sometimes take a dramatic turn when
new requirements are added. In case you've started the graph with strict: no
,
you'll have to call TS.sort g
yourself to perform a validation and obtain
a serialization.—Let's try that for some obvious dependencies on our list:
1console.log ( TS.link_down g, 'buy food', 'cook' ).join ' > ' 2console.log ( TS.link_down g, 'fetch money', 'buy food' ).join ' > ' 3console.log ( TS.link_down g, 'do some reading', 'go to exam' ).join ' > ' 4console.log ( TS.link_down g, 'cook', 'eat' ).join ' > ' 5console.log ( TS.link_down g, 'go to bank', 'fetch money' ).join ' > ' 6console.log ( TS.link_down g, 'fetch money', 'buy books' ).join ' > ' 7console.log ( TS.link_down g, 'buy books', 'do some reading' ).join ' > ' 8console.log ( TS.link_down g, 'go to market', 'buy food' ).join ' > '
The output from the above will be (re-arranged for readability):
1 buy food > cook 2 fetch money > buy food > cook 3 fetch money > buy food > cook > do some reading > go to exam 4 fetch money > buy food > cook > do some reading > go to exam > eat 5go to bank > fetch money > buy food > cook > do some reading > go to exam > eat 6go to bank > fetch money > buy food > cook > do some reading > go to exam > eat > buy books 7go to bank > fetch money > buy food > cook > buy books > do some reading > go to exam > eat 8go to bank > fetch money > go to market > buy food > cook > buy books > do some reading > go to exam > eat
Observe how the requirement 'fetch money' > 'buy books'
made 'buy books'
appear at the very end of the list, and how only the additonal requirement 'buy books' > 'do some reading'
managed to put the horse before the cart, as it
were. It still looks as though we're not quite done here yet, as we have to
leave house after cooking and go to the exam with an empty stomach according to
the current linearization, so some dependencies are still missing:
1console.log ( TS.link_down g, 'buy food', 'go home' ).join ' > ' 2console.log ( TS.link_down g, 'buy books', 'go home' ).join ' > ' 3console.log ( TS.link_down g, 'go home', 'cook' ).join ' > ' 4console.log ( TS.link_down g, 'eat', 'go to exam' ).join ' > '
This makes the order of events more reasonable with each step:
1go to bank > fetch money > go to market > buy food > cook > buy books > do some reading > go to exam > eat > go home 2go to bank > fetch money > go to market > buy food > cook > buy books > do some reading > go to exam > eat > go home 3go to bank > fetch money > go to market > buy food > buy books > go home > cook > do some reading > go to exam > eat 4go to bank > fetch money > go to market > buy food > buy books > go home > cook > do some reading > eat > go to exam
The takeaway up to this point is that although you may have already entered all relevant activities, it may or or may not be the case that the relationships define a unique ordering—TSort will always give you some ordering, but not necessarily the only one. TSort remains silent about that. For this reason and because the precise ordering is dependent upon order of insertion, it may happen that a given result looks satisfying not because the constraints entered were both sufficient and complete, but because they happened to be added to the graph in a fitting sequence. In the same vein, adding more constraints may or may not change the linearization.
Furthermore, each new requirement may introduce an incompatible constraint. It
is by no means unreasonable as such to require that we want to eat before going
to the bank, but should we call TS.link_down g, 'eat', 'go to bank'
at this
point in time, TSort will throw an error (immediately if set to strict
,
otherwise as soon as TS.sort
is called), complaining that it has detected cycle involving node 'buy food'
. Had we added TS.link_down g, 'eat', 'go to bank'
first, the error would have resulted upon adding the constraint
TS.link_down g, 'go to bank', 'fetch money'
; in this case the message would've
been detected cycle involving node 'eat'
.
Now for a more CS-ish application of TSort; specifically, we want to implement the 'function table' that Ravindrababu Ravula derives in his lecture on Compiler Design Lecture 9—Operator grammar and Operator precedence parser (one of the few materials about Pratt-style Top-Down Operator Parsing (TDOP) i was able to find on the web).
. | id | + | * | $ |
---|---|---|---|---|
id | — | > | > | > |
+ | < | > | < | > |
* | < | > | > | > |
$ | < | < | < | — |
operator precedence table
f|id > g|* > f|+ > g|+ > f|$
g|id > f|* > ⤴
. | id | + | * | $ |
---|---|---|---|---|
f | 4 | 2 | 4 | 0 |
g | 5 | 1 | 3 | 0 |
1 2CND = require 'cnd' 3rpr = CND.rpr 4badge = 'scratch' 5debug = CND.get_logger 'debug', badge 6help = CND.get_logger 'help', badge 7 8 9test_tsort = -> 10 TS = CND.TSORT 11 settings = 12 strict: yes 13 prefixes: [ 'f|', 'g|', ] 14 graph = TS.new_graph settings 15 TS.link graph, 'id', '-', 'id' 16 TS.link graph, 'id', '>', '+' 17 TS.link graph, 'id', '>', '*' 18 TS.link graph, 'id', '>', '$' 19 TS.link graph, '+', '<', 'id' 20 TS.link graph, '+', '>', '+' 21 TS.link graph, '+', '<', '*' 22 TS.link graph, '+', '>', '$' 23 TS.link graph, '*', '<', 'id' 24 TS.link graph, '*', '>', '+' 25 TS.link graph, '*', '>', '*' 26 TS.link graph, '*', '>', '$' 27 TS.link graph, '$', '<', 'id' 28 TS.link graph, '$', '<', '+' 29 TS.link graph, '$', '<', '*' 30 TS.link graph, '$', '-', '$' 31 help nodes = TS.sort graph 32 matcher = [ 'f|id', 'g|id', 'f|*', 'g|*', 'f|+', 'g|+', 'g|$', 'f|$' ] 33 unless CND.equals nodes, matcher 34 throw new Error """is: #{rpr nodes} 35 expected: #{rpr matcher}""" 36 try 37 TS.link graph, '$', '>', '$' 38 TS.link graph, '$', '<', '$' 39 catch error 40 { message } = error 41 if /^detected cycle involving node/.test message 42 warn error 43 else 44 throw error 45 46test_tsort()
1console.log '1', ( TS.precedence_of graph, 'f|id' ) > ( TS.precedence_of graph, 'g|+' ) # true 2console.log '2', ( TS.precedence_of graph, 'f|id' ) > ( TS.precedence_of graph, 'g|*' ) # true 3console.log '3', ( TS.precedence_of graph, 'f|id' ) > ( TS.precedence_of graph, 'g|$' ) # true 4console.log '4', ( TS.precedence_of graph, 'f|+' ) < ( TS.precedence_of graph, 'g|id' ) # true 5console.log '5', ( TS.precedence_of graph, 'f|+' ) > ( TS.precedence_of graph, 'g|+' ) # true 6console.log '6', ( TS.precedence_of graph, 'f|+' ) < ( TS.precedence_of graph, 'g|*' ) # true 7console.log '7', ( TS.precedence_of graph, 'f|+' ) > ( TS.precedence_of graph, 'g|$' ) # true 8console.log '8', ( TS.precedence_of graph, 'f|*' ) < ( TS.precedence_of graph, 'g|id' ) # true 9console.log '9', ( TS.precedence_of graph, 'f|*' ) > ( TS.precedence_of graph, 'g|+' ) # true 10console.log '10', ( TS.precedence_of graph, 'f|*' ) > ( TS.precedence_of graph, 'g|*' ) # true 11console.log '11', ( TS.precedence_of graph, 'f|*' ) > ( TS.precedence_of graph, 'g|$' ) # true 12console.log '12', ( TS.precedence_of graph, 'f|$' ) < ( TS.precedence_of graph, 'g|id' ) # true 13console.log '13', ( TS.precedence_of graph, 'f|$' ) < ( TS.precedence_of graph, 'g|+' ) # true 14console.log '14', ( TS.precedence_of graph, 'f|$' ) < ( TS.precedence_of graph, 'g|*' ) # true
TSort API
-
@new_graph = ( settings ) ->
-
@link = ( me, f, r, g ) ->
-
@link_down = ( me, precedence, consequence ) ->
-
@link_up = ( me, consequence, precedence ) -> @link_down me, precedence, consequence
-
@register = ( me, names... ) ->
-
@sort = ( me ) ->
-
@get_precedences = ( me ) ->
-
@precedence_of = ( me, name ) ->
Some TDOP Links
- Pratt's original paper from 1973: http://hall.org.ua/halls/wizzard/pdf/Vaughan.Pratt.TDOP.pdf
- The same as an HTML page: http://tdop.github.io/
- Simple Top-Down Parsing in Python: http://effbot.org/zone/simple-top-down-parsing.htm
- Douglas Crockford on TDOP: http://javascript.crockford.com/tdop/tdop.html
XJSON
1 e = new Set 'xy' 2 e.add new Set 'abc' 3 d = [ 'A', 'B', e, ] 4 info CND.XJSON.stringify d 5 info CND.XJSON.parse CND.XJSON.stringify d
Output:
1["A","B",{"~isa":"set","%self":["x","y",{"~isa":"set","%self":["a","b","c"]}]}] 2[ 'A', 'B', Set { 'x', 'y', Set { 'a', 'b', 'c' } } ]
CND.TEXT.to_width
2
|北|2
|P |2
|Pe|2
|……|2
|P…|2
|a…|2
|x…|2
|a…|2
|a…|2
|……|2
|……|2
3
|北 |3
|P |3
|Pe |3
|北…|3
|Pe…|3
|a …|3
|xa…|3
|àx…|4
|a⃝b…|4
|北…|3
|北…|3
4
|北 |4
|P |4
|Pe |4
|北京|4
|Pek…|4
|a n…|4
|xàx…|5
|àxa…|5
|a⃝b⃞c…|6
|北……|4
|北……|4
5
|北 |5
|P |5
|Pe |5
|北京 |5
|Peki…|5
|a ni…|5
|xàxa…|6
|àxáx…|7
|a⃝b⃞c⃟a…|8
|北京…|5
|北京…|5
10
|北 |10
|P |10
|Pe |10
|北京 |10
|Peking |10
|a nice te…|10
|xàxáxâxãx…|14
|àxáxâxãxa…|14
|a⃝b⃞c⃟a⃝b⃞c⃟a⃝b⃞c…|18
|北京 (Pek…|10
|北京 (Pek…|10
15
|北 |15
|P |15
|Pe |15
|北京 |15
|Peking |15
|a nice test to…|15
|xàxáxâxãxāxa̅xa…|21
|àxáxâxãxāxa̅xăx…|22
|a⃝b⃞c⃟a⃝b⃞c⃟a⃝b⃞c⃟a⃝b⃞c⃟…|25
|北京 (Peking) …|15
|北京 (Peking) …|15
20
|北 |20
|P |20
|Pe |20
|北京 |20
|Peking |20
|a nice test to see …|20
|xàxáxâxãxāxa̅xăxȧxax…|28
|àxáxâxãxāxa̅xăxȧxaxa…|28
|a⃝b⃞c⃟a⃝b⃞c⃟a⃝b⃞c⃟a⃝b⃞c⃟…|25
|北京 (Peking) 位於……|20
|北京 (Peking) 位於……|20
25
|北 |25
|P |25
|Pe |25
|北京 |25
|Peking |25
|a nice test to see the e…|25
|xàxáxâxãxāxa̅xăxȧxaxa̠xa̡xa…|35
|àxáxâxãxāxa̅xăxȧxaxa̠xa̡xa̢x…|36
|a⃝b⃞c⃟a⃝b⃞c⃟a⃝b⃞c⃟a⃝b⃞c⃟ |25
|北京 (Peking) 位於華北 (…|25
|北京 (Peking) 位於華北 (…|25
0 1 2 3
0123456789012345678901234567890123456789
a nice test to see the effect*
北京 (Peking) 位於華北 (North*
北京 (Peking) 位於華北 (North*
ToDo
- Add a utility method to enable catch-all listeners on event emitters (as used in kleinbild):
1 _emit = R.emit.bind R 2 R.emit = ( event_name, P... ) => 3 _emit '*', event_name, P... 4 _emit event_name, P... 5 return null 6 R.on '*', ( event_name, P... ) => 7 @U.dump event_name, P... 8 return null
- use together with
node-icecream
:ic = ( require 'node-icecream' ) { prefix: '', outputFunction: debug, }
![Empty State](/_next/static/media/empty.e5fae2e5.png)
No vulnerabilities found.
Reason
no binaries found in the repo
Reason
license file detected
Details
- Info: project has a license file: LICENSE:0
- Info: FSF or OSI recognized license: MIT License: LICENSE:0
Reason
0 existing vulnerabilities detected
Reason
Found 0/30 approved changesets -- score normalized to 0
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
no SAST tool detected
Details
- Warn: no pull requests merged into dev branch
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
- Warn: no security policy file detected
- Warn: no security file to analyze
- Warn: no security file to analyze
- Warn: no security file to analyze
Reason
project is not fuzzed
Details
- Warn: no fuzzer integrations found
Reason
branch protection not enabled on development/release branches
Details
- Warn: branch protection not enabled for branch 'master'
Score
3
/10
Last Scanned on 2025-01-27
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More