Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial commit, spinning off this part of connect-assets

  • Loading branch information...
commit 4367f67642e5ebbd84048c4bcecd6d51f9beea48 0 parents
@TrevorBurnham authored
1  .gitignore
@@ -0,0 +1 @@
+node_modules
49 Cakefile
@@ -0,0 +1,49 @@
+fs = require 'fs'
+{print} = require 'sys'
+{spawn, exec} = require 'child_process'
+{watchTree} = require 'watch-tree'
+
+build = (watch, callback) ->
+ if typeof watch is 'function'
+ callback = watch
+ watch = false
+ options = ['-c', '-o', 'lib', 'src']
+ options.unshift '-w' if watch
+
+ coffee = spawn 'coffee', options
+ coffee.stdout.on 'data', (data) -> print data.toString()
+ coffee.stderr.on 'data', (data) -> print data.toString()
+ coffee.on 'exit', (status) -> callback?() if status is 0
+
+task 'docs', 'Generate annotated source code with Docco', ->
+ fs.readdir 'src', (err, contents) ->
+ files = ("src/#{file}" for file in contents when /\.coffee$/.test file)
+ docco = spawn 'docco', files
+ docco.stdout.on 'data', (data) -> print data.toString()
+ docco.stderr.on 'data', (data) -> print data.toString()
+ docco.on 'exit', (status) -> callback?() if status is 0
+
+task 'build', 'Compile CoffeeScript source files', ->
+ build()
+
+task 'watch', 'Recompile CoffeeScript source files when modified', ->
+ build true
+
+task 'test', 'Run the test suite (and re-run if anything changes)', ->
+ suite = null
+ build ->
+ do runTests = ->
+ suite?.kill()
+ suiteNames = ['test']
+ suiteIndex = 0
+ do runNextTestSuite = ->
+ return unless suiteName = suiteNames[suiteIndex]
+ suite = spawn "coffee", ["-e", "{reporters} = require 'nodeunit'; reporters.default.run ['#{suiteName}.coffee']"], cwd: 'test'
+ suite.stdout.on 'data', (data) -> print data.toString()
+ suite.stderr.on 'data', (data) -> print data.toString()
+ suite.on 'exit', -> suiteIndex++; runNextTestSuite()
+ invoke 'docs' # lest I forget
+ testWatcher = watchTree 'test', 'sample-rate': 5
+ testWatcher.on 'fileModified', runTests
+ libWatcher = watchTree 'src', 'sample-rate': 5
+ libWatcher.on 'fileModified', -> build(-> runTests())
21 docs/dep-graph.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html> <html> <head> <title>dep-graph.coffee</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> dep-graph.coffee </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-1">&#182;</a> </div> <p><a href="http://github.com/TrevorBurnham/dep-graph">dep-graph</a></p> </td> <td class="code"> <div class="highlight"><pre><span class="nv">module.exports = </span><span class="k">class</span> <span class="nx">DepGraph</span>
+ <span class="nv">constructor: </span><span class="o">-&gt;</span></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">&#182;</a> </div> <p>The internal representation of the dependency graph in the format
+<code>id: [ids]</code>, indicating only <em>direct</em> dependencies.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="vi">@map = </span><span class="p">{}</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">&#182;</a> </div> <p>Add a direct dependency. Returns <code>false</code> if that dependency is a duplicate.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">add: </span><span class="nf">(id, depId) -&gt;</span>
+ <span class="nx">@map</span><span class="p">[</span><span class="nx">id</span><span class="p">]</span> <span class="o">?=</span> <span class="p">[]</span>
+ <span class="k">return</span> <span class="kc">false</span> <span class="k">if</span> <span class="nx">depId</span> <span class="k">in</span> <span class="nx">@map</span><span class="p">[</span><span class="nx">id</span><span class="p">]</span>
+ <span class="nx">@map</span><span class="p">[</span><span class="nx">id</span><span class="p">].</span><span class="nx">push</span> <span class="nx">depId</span>
+ <span class="nx">@map</span><span class="p">[</span><span class="nx">id</span><span class="p">]</span></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</a> </div> <p>Generate a list of all dependencies (direct and indirect) for the given id,
+in logical order with no duplicates.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nv">getChain: </span><span class="nf">(id, traversedPaths = [], traversedBranch = []) -&gt;</span>
+ <span class="k">return</span> <span class="p">[]</span> <span class="nx">unless</span> <span class="nx">@map</span><span class="p">[</span><span class="nx">id</span><span class="p">]</span>
+
+ <span class="k">for</span> <span class="nx">depId</span> <span class="k">in</span> <span class="nx">@map</span><span class="p">[</span><span class="nx">id</span><span class="p">].</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">).</span><span class="nx">reverse</span><span class="p">()</span>
+ <span class="k">if</span> <span class="nx">depId</span> <span class="k">in</span> <span class="nx">traversedBranch</span> <span class="c1"># cycle</span>
+ <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s2">&quot;Cyclic dependency from #{id} to #{depId}&quot;</span><span class="p">)</span>
+ <span class="k">continue</span> <span class="k">if</span> <span class="nx">depId</span> <span class="k">in</span> <span class="nx">traversedPaths</span> <span class="c1"># duplicate</span>
+ <span class="nx">traversedPaths</span><span class="p">.</span><span class="nx">unshift</span> <span class="nx">depId</span>
+ <span class="nx">traversedBranch</span><span class="p">.</span><span class="nx">unshift</span> <span class="nx">depId</span>
+ <span class="nx">@getChain</span> <span class="nx">depId</span><span class="p">,</span> <span class="nx">traversedPaths</span><span class="p">,</span> <span class="nx">traversedBranch</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
+
+ <span class="nx">traversedPaths</span>
+
+</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>
186 docs/docco.css
@@ -0,0 +1,186 @@
+/*--------------------- Layout and Typography ----------------------------*/
+body {
+ font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;
+ font-size: 15px;
+ line-height: 22px;
+ color: #252519;
+ margin: 0; padding: 0;
+}
+a {
+ color: #261a3b;
+}
+ a:visited {
+ color: #261a3b;
+ }
+p {
+ margin: 0 0 15px 0;
+}
+h1, h2, h3, h4, h5, h6 {
+ margin: 0px 0 15px 0;
+}
+ h1 {
+ margin-top: 40px;
+ }
+#container {
+ position: relative;
+}
+#background {
+ position: fixed;
+ top: 0; left: 525px; right: 0; bottom: 0;
+ background: #f5f5ff;
+ border-left: 1px solid #e5e5ee;
+ z-index: -1;
+}
+#jump_to, #jump_page {
+ background: white;
+ -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777;
+ -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px;
+ font: 10px Arial;
+ text-transform: uppercase;
+ cursor: pointer;
+ text-align: right;
+}
+#jump_to, #jump_wrapper {
+ position: fixed;
+ right: 0; top: 0;
+ padding: 5px 10px;
+}
+ #jump_wrapper {
+ padding: 0;
+ display: none;
+ }
+ #jump_to:hover #jump_wrapper {
+ display: block;
+ }
+ #jump_page {
+ padding: 5px 0 3px;
+ margin: 0 0 25px 25px;
+ }
+ #jump_page .source {
+ display: block;
+ padding: 5px 10px;
+ text-decoration: none;
+ border-top: 1px solid #eee;
+ }
+ #jump_page .source:hover {
+ background: #f5f5ff;
+ }
+ #jump_page .source:first-child {
+ }
+table td {
+ border: 0;
+ outline: 0;
+}
+ td.docs, th.docs {
+ max-width: 450px;
+ min-width: 450px;
+ min-height: 5px;
+ padding: 10px 25px 1px 50px;
+ overflow-x: hidden;
+ vertical-align: top;
+ text-align: left;
+ }
+ .docs pre {
+ margin: 15px 0 15px;
+ padding-left: 15px;
+ }
+ .docs p tt, .docs p code {
+ background: #f8f8ff;
+ border: 1px solid #dedede;
+ font-size: 12px;
+ padding: 0 0.2em;
+ }
+ .pilwrap {
+ position: relative;
+ }
+ .pilcrow {
+ font: 12px Arial;
+ text-decoration: none;
+ color: #454545;
+ position: absolute;
+ top: 3px; left: -20px;
+ padding: 1px 2px;
+ opacity: 0;
+ -webkit-transition: opacity 0.2s linear;
+ }
+ td.docs:hover .pilcrow {
+ opacity: 1;
+ }
+ td.code, th.code {
+ padding: 14px 15px 16px 25px;
+ width: 100%;
+ vertical-align: top;
+ background: #f5f5ff;
+ border-left: 1px solid #e5e5ee;
+ }
+ pre, tt, code {
+ font-size: 12px; line-height: 18px;
+ font-family: Monaco, Consolas, "Lucida Console", monospace;
+ margin: 0; padding: 0;
+ }
+
+
+/*---------------------- Syntax Highlighting -----------------------------*/
+td.linenos { background-color: #f0f0f0; padding-right: 10px; }
+span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
+body .hll { background-color: #ffffcc }
+body .c { color: #408080; font-style: italic } /* Comment */
+body .err { border: 1px solid #FF0000 } /* Error */
+body .k { color: #954121 } /* Keyword */
+body .o { color: #666666 } /* Operator */
+body .cm { color: #408080; font-style: italic } /* Comment.Multiline */
+body .cp { color: #BC7A00 } /* Comment.Preproc */
+body .c1 { color: #408080; font-style: italic } /* Comment.Single */
+body .cs { color: #408080; font-style: italic } /* Comment.Special */
+body .gd { color: #A00000 } /* Generic.Deleted */
+body .ge { font-style: italic } /* Generic.Emph */
+body .gr { color: #FF0000 } /* Generic.Error */
+body .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+body .gi { color: #00A000 } /* Generic.Inserted */
+body .go { color: #808080 } /* Generic.Output */
+body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+body .gs { font-weight: bold } /* Generic.Strong */
+body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+body .gt { color: #0040D0 } /* Generic.Traceback */
+body .kc { color: #954121 } /* Keyword.Constant */
+body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */
+body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */
+body .kp { color: #954121 } /* Keyword.Pseudo */
+body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */
+body .kt { color: #B00040 } /* Keyword.Type */
+body .m { color: #666666 } /* Literal.Number */
+body .s { color: #219161 } /* Literal.String */
+body .na { color: #7D9029 } /* Name.Attribute */
+body .nb { color: #954121 } /* Name.Builtin */
+body .nc { color: #0000FF; font-weight: bold } /* Name.Class */
+body .no { color: #880000 } /* Name.Constant */
+body .nd { color: #AA22FF } /* Name.Decorator */
+body .ni { color: #999999; font-weight: bold } /* Name.Entity */
+body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+body .nf { color: #0000FF } /* Name.Function */
+body .nl { color: #A0A000 } /* Name.Label */
+body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+body .nt { color: #954121; font-weight: bold } /* Name.Tag */
+body .nv { color: #19469D } /* Name.Variable */
+body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+body .w { color: #bbbbbb } /* Text.Whitespace */
+body .mf { color: #666666 } /* Literal.Number.Float */
+body .mh { color: #666666 } /* Literal.Number.Hex */
+body .mi { color: #666666 } /* Literal.Number.Integer */
+body .mo { color: #666666 } /* Literal.Number.Oct */
+body .sb { color: #219161 } /* Literal.String.Backtick */
+body .sc { color: #219161 } /* Literal.String.Char */
+body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */
+body .s2 { color: #219161 } /* Literal.String.Double */
+body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+body .sh { color: #219161 } /* Literal.String.Heredoc */
+body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+body .sx { color: #954121 } /* Literal.String.Other */
+body .sr { color: #BB6688 } /* Literal.String.Regex */
+body .s1 { color: #219161 } /* Literal.String.Single */
+body .ss { color: #19469D } /* Literal.String.Symbol */
+body .bp { color: #954121 } /* Name.Builtin.Pseudo */
+body .vc { color: #19469D } /* Name.Variable.Class */
+body .vg { color: #19469D } /* Name.Variable.Global */
+body .vi { color: #19469D } /* Name.Variable.Instance */
+body .il { color: #666666 } /* Literal.Number.Integer.Long */
52 lib/dep-graph.js
@@ -0,0 +1,52 @@
+(function() {
+ var DepGraph;
+ var __indexOf = Array.prototype.indexOf || function(item) {
+ for (var i = 0, l = this.length; i < l; i++) {
+ if (this[i] === item) return i;
+ }
+ return -1;
+ };
+ module.exports = DepGraph = (function() {
+ function DepGraph() {
+ this.map = {};
+ }
+ DepGraph.prototype.add = function(id, depId) {
+ var _base, _ref;
+ if ((_ref = (_base = this.map)[id]) == null) {
+ _base[id] = [];
+ }
+ if (__indexOf.call(this.map[id], depId) >= 0) {
+ return false;
+ }
+ this.map[id].push(depId);
+ return this.map[id];
+ };
+ DepGraph.prototype.getChain = function(id, traversedPaths, traversedBranch) {
+ var depId, _i, _len, _ref;
+ if (traversedPaths == null) {
+ traversedPaths = [];
+ }
+ if (traversedBranch == null) {
+ traversedBranch = [];
+ }
+ if (!this.map[id]) {
+ return [];
+ }
+ _ref = this.map[id].slice(0).reverse();
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ depId = _ref[_i];
+ if (__indexOf.call(traversedBranch, depId) >= 0) {
+ throw new Error("Cyclic dependency from " + id + " to " + depId);
+ }
+ if (__indexOf.call(traversedPaths, depId) >= 0) {
+ continue;
+ }
+ traversedPaths.unshift(depId);
+ traversedBranch.unshift(depId);
+ this.getChain(depId, traversedPaths, traversedBranch.slice(0));
+ }
+ return traversedPaths;
+ };
+ return DepGraph;
+ })();
+}).call(this);
17 package.json
@@ -0,0 +1,17 @@
+{
+ "author": "Trevor Burnham (http://trevorburnham.com)",
+ "name": "dep-graph",
+ "description": "Simple dependency graph management",
+ "version": "1.0.0",
+ "homepage": "http://github.com/TrevorBurnham/dep-graph",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/TrevorBurnham/dep-graph.git"
+ },
+ "main": "lib/dep-graph.js",
+ "devDependencies": {
+ "coffee-script": "1.1.2",
+ "nodeunit": "0.5.4",
+ "watch-tree": "0.1.1"
+ }
+}
29 src/dep-graph.coffee
@@ -0,0 +1,29 @@
+# [dep-graph](http://github.com/TrevorBurnham/dep-graph)
+
+module.exports = class DepGraph
+ constructor: ->
+ # The internal representation of the dependency graph in the format
+ # `id: [ids]`, indicating only *direct* dependencies.
+ @map = {}
+
+ # Add a direct dependency. Returns `false` if that dependency is a duplicate.
+ add: (id, depId) ->
+ @map[id] ?= []
+ return false if depId in @map[id]
+ @map[id].push depId
+ @map[id]
+
+ # Generate a list of all dependencies (direct and indirect) for the given id,
+ # in logical order with no duplicates.
+ getChain: (id, traversedPaths = [], traversedBranch = []) ->
+ return [] unless @map[id]
+
+ for depId in @map[id].slice(0).reverse()
+ if depId in traversedBranch # cycle
+ throw new Error("Cyclic dependency from #{id} to #{depId}")
+ continue if depId in traversedPaths # duplicate
+ traversedPaths.unshift depId
+ traversedBranch.unshift depId
+ @getChain depId, traversedPaths, traversedBranch.slice(0)
+
+ traversedPaths
20 test/test.coffee
@@ -0,0 +1,20 @@
+DepGraph = require('../lib/dep-graph.js')
+depGraph = new DepGraph
+
+exports['Direct dependencies are chained in original order'] = (test) ->
+ depGraph.add '0', '1'
+ depGraph.add '0', '2'
+ depGraph.add '0', '3'
+ test.deepEqual depGraph.getChain('0'), ['1', '2', '3']
+ test.done()
+
+exports['Indirect dependencies are chained before their dependents'] = (test) ->
+ depGraph.add '2', 'A'
+ depGraph.add '2', 'B'
+ test.deepEqual depGraph.getChain('0'), ['1', 'A', 'B', '2', '3']
+ test.done()
+
+exports['getChain can safely be called for unknown resources'] = (test) ->
+ test.doesNotThrow -> depGraph.getChain('Z')
+ test.deepEqual depGraph.getChain('Z'), []
+ test.done()
Please sign in to comment.
Something went wrong with that request. Please try again.