<!DOCTYPE html> <html> <head> <title>install.js</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> install.js </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">¶</a> </div> </td> <td class="code"> <div class="highlight"><pre><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">global</span><span class="p">,</span> <span class="kc">undefined</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">¶</a> </div> <p>Defining the <code>install</code> function more than once leads to mayhem, so return immedately if a property called <code>install</code> is already defined on the global object.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="nx">global</span><span class="p">.</span><span class="nx">install</span><span class="p">)</span> <span class="k">return</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">¶</a> </div> <p>The <code>installed</code> object maps absolute module identifiers to module definitions available for requirement.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">var</span> <span class="nx">installed</span> <span class="o">=</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">¶</a> </div> <p>I make frequent use of <code>hasOwn.call</code> to test for the presence of object properties without traversing the prototype chain.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">var</span> <span class="nx">hasOwn</span> <span class="o">=</span> <span class="nx">installed</span><span class="p">.</span><span class="nx">hasOwnProperty</span><span class="p">;</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">¶</a> </div> <p>Anonymous modules are pushed onto a queue so that (when ready) they can be executed in order of installation.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">var</span> <span class="nx">qhead</span> <span class="o">=</span> <span class="p">{};</span> <span class="kd">var</span> <span class="nx">qtail</span> <span class="o">=</span> <span class="nx">qhead</span><span class="p">;</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">¶</a> </div> <p>Define the <code>install</code> function globally.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">global</span><span class="p">.</span><span class="nx">install</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">id</span><span class="p">,</span> <span class="nx">module</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">¶</a> </div> <p>To install a named module, pass an absolute module identifier string followed by a module definition. Note that named modules are not evaluated until they are required for the first time.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="k">typeof</span> <span class="nx">id</span> <span class="o">===</span> <span class="s2">"string"</span> <span class="o">&&</span> <span class="nx">module</span><span class="p">)</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">hasOwn</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">installed</span><span class="p">,</span> <span class="nx">id</span><span class="p">))</span> <span class="p">{</span> <span class="nx">installed</span><span class="p">[</span><span class="nx">module</span><span class="p">.</span><span class="nx">id</span> <span class="o">=</span> <span class="nx">id</span><span class="p">]</span> <span class="o">=</span> <span class="nx">module</span><span class="p">;</span> <span class="nx">flushQueue</span><span class="p">();</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">¶</a> </div> <p>To install an anonymous module, pass a module definition without an identifier. Anonymous modules are executed in order of installation, as soon as their requirements have been installed.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">id</span> <span class="o">&&</span> <span class="k">typeof</span> <span class="nx">id</span><span class="p">.</span><span class="nx">call</span> <span class="o">===</span> <span class="s2">"function"</span><span class="p">)</span> <span class="p">{</span> <span class="nx">qtail</span> <span class="o">=</span> <span class="nx">qtail</span><span class="p">.</span><span class="nx">next</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">module</span><span class="o">:</span> <span class="nx">id</span> <span class="p">};</span> <span class="k">if</span> <span class="p">(</span><span class="nx">qhead</span><span class="p">.</span><span class="nx">next</span> <span class="o">===</span> <span class="nx">qtail</span><span class="p">)</span> <span class="nx">flushQueue</span><span class="p">();</span> <span class="p">}</span> <span class="p">};</span></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">¶</a> </div> <p>The <code>require</code> function takes an absolute module identifier and returns the <code>exports</code> object defined by that module. An error is thrown if no module with the given identifier is installed.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">function</span> <span class="nx">require</span><span class="p">(</span><span class="nx">moduleId</span><span class="p">)</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="nx">hasOwn</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">installed</span><span class="p">,</span> <span class="nx">moduleId</span><span class="p">))</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">module</span> <span class="o">=</span> <span class="nx">installed</span><span class="p">[</span><span class="nx">moduleId</span><span class="p">];</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">hasOwn</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">module</span><span class="p">,</span> <span class="s2">"exports"</span><span class="p">))</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">¶</a> </div> <p>Each module receives a version of <code>require</code> that knows how to <code>absolutize</code> relative module identifiers with respect to <code>moduleId</code>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">module</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">global</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">id</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="nx">require</span><span class="p">(</span><span class="nx">absolutize</span><span class="p">(</span><span class="nx">id</span><span class="p">,</span> <span class="nx">moduleId</span><span class="p">));</span> <span class="p">},</span> <span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="p">{},</span> <span class="nx">module</span><span class="p">);</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">¶</a> </div> <p>Note that <code>module.exports</code> may be redefined during evaluation of the module.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">return</span> <span class="nx">module</span><span class="p">.</span><span class="nx">exports</span><span class="p">;</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">¶</a> </div> <p>Since modules are evaluated only after all their requirements have been installed, this error generally means that <code>require</code> was called with an identifier that was not seen (or was not understood) by the dependency scanner.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s1">'module "'</span> <span class="o">+</span> <span class="nx">moduleId</span> <span class="o">+</span> <span class="s1">'" not installed'</span><span class="p">);</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">¶</a> </div> <p>Given two module identifiers <code>id</code> and <code>baseId</code>, the <code>absolutize</code> function returns the absolute form of <code>id</code>, as if <code>id</code> were required from a module with the identifier <code>baseId</code>. For more information about relative identifiers, refer to the <a href="http://wiki.commonjs.org/wiki/Modules/1.1#Module_Identifiers">spec</a>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">var</span> <span class="nx">pathNormExp</span> <span class="o">=</span> <span class="sr">/\/(\.?|[^\/]+\/\.\.)\//</span><span class="p">;</span> <span class="kd">function</span> <span class="nx">absolutize</span><span class="p">(</span><span class="nx">id</span><span class="p">,</span> <span class="nx">baseId</span><span class="p">)</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="nx">id</span><span class="p">.</span><span class="nx">charAt</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="o">===</span> <span class="s2">"."</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">¶</a> </div> <p>Note: if <code>baseId</code> is omitted, then <code>"/undefined/../" + id</code> will be the starting point for normalization, which works just fine!</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">id</span> <span class="o">=</span> <span class="s2">"/"</span> <span class="o">+</span> <span class="nx">baseId</span> <span class="o">+</span> <span class="s2">"/../"</span> <span class="o">+</span> <span class="nx">id</span><span class="p">;</span> <span class="k">while</span> <span class="p">(</span><span class="nx">id</span> <span class="o">!=</span> <span class="p">(</span><span class="nx">baseId</span> <span class="o">=</span> <span class="nx">id</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="nx">pathNormExp</span><span class="p">,</span> <span class="s2">"/"</span><span class="p">)))</span> <span class="nx">id</span> <span class="o">=</span> <span class="nx">baseId</span><span class="p">;</span> <span class="nx">id</span> <span class="o">=</span> <span class="nx">id</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/^\//</span><span class="p">,</span> <span class="s2">""</span><span class="p">);</span> <span class="p">}</span> <span class="k">return</span> <span class="nx">id</span><span class="p">;</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">¶</a> </div> <p>The <code>flushQueue</code> function attempts to evaluate the oldest module in the queue, provided all of its dependencies have been installed. This provision is important because it ensures that the module can call <code>require</code> without fear of missing dependencies.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">function</span> <span class="nx">flushQueue</span><span class="p">()</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">next</span> <span class="o">=</span> <span class="nx">qhead</span><span class="p">.</span><span class="nx">next</span><span class="p">,</span> <span class="nx">module</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="nx">next</span> <span class="o">&&</span> <span class="o">!</span><span class="nx">flushing</span> <span class="o">&&</span> <span class="nx">ready</span><span class="p">(</span><span class="nx">module</span> <span class="o">=</span> <span class="nx">next</span><span class="p">.</span><span class="nx">module</span><span class="p">))</span> <span class="p">{</span> <span class="nx">flushing</span> <span class="o">=</span> <span class="nx">qhead</span> <span class="o">=</span> <span class="nx">next</span><span class="p">;</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">¶</a> </div> <p>Module evaluation might throw an exception, so we need to schedule the next call to <code>flushQueue</code> before invoking <code>module.call</code>. The <code>setTimeout</code> function allows the stack to unwind before flushing resumes, so that the browser has a chance to report exceptions and/or handle other events.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">global</span><span class="p">.</span><span class="nx">setTimeout</span><span class="p">(</span><span class="nx">resume</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="nx">module</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">global</span><span class="p">,</span> <span class="nx">require</span><span class="p">);</span> <span class="nx">flushing</span> <span class="o">=</span> <span class="kc">undefined</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">¶</a> </div> <p>If <code>install</code> is called during the evaluation of a queued module, <code>flushQueue</code> could be invoked recursively. To prevent double evaluation, <code>flushQueue</code> sets <code>flushing</code> to a truthy value before it evaluates a module and refuses to evaluate any modules if <code>flushing</code> is truthy already.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">var</span> <span class="nx">flushing</span><span class="p">;</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-18">¶</a> </div> <p>Since <code>resume</code> is only ever invoked from <code>setTimeout</code>, there is no risk that <code>flushQueue</code> is already executing, so it is safe to clear the <code>flushing</code> flag unconditionally.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">function</span> <span class="nx">resume</span><span class="p">()</span> <span class="p">{</span> <span class="nx">flushing</span> <span class="o">=</span> <span class="kc">undefined</span><span class="p">;</span> <span class="nx">flushQueue</span><span class="p">();</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-19">¶</a> </div> <p>To be recognized as dependencies, calls to <code>require</code> must use string literal identifiers.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">var</span> <span class="nx">requireExp</span> <span class="o">=</span> <span class="sr">/\brequire\(['"]([^'"]+)['"]\)/g</span><span class="p">;</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-20">¶</a> </div> <p>A module is <code>ready</code> to be evaluated if</p> <ol> <li>it has an <code>.exports</code> property (indicating that it has already begun to be evaluated) or</li> <li>all of its direct dependencies are installed and <code>ready</code> to be evaluated.</li> </ol> <p>Note that the above definition is recursive.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">function</span> <span class="nx">ready</span><span class="p">(</span><span class="nx">module</span><span class="p">)</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">deps</span><span class="p">,</span> <span class="nx">code</span><span class="p">,</span> <span class="nx">match</span><span class="p">,</span> <span class="nx">id</span><span class="p">,</span> <span class="nx">result</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">module</span><span class="p">.</span><span class="nx">seen</span> <span class="o">&&</span> <span class="o">!</span><span class="nx">hasOwn</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">module</span><span class="p">,</span> <span class="s2">"exports"</span><span class="p">))</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-21">¶</a> </div> <p>Here's a little secret: module definitions don't have to be functions, as long as they have a suitable <code>.toString</code> and <code>.call</code> methods. If you have a really long module that you don't want to waste time scanning, just override its <code>.toString</code> function to return something equivalent (with regard to dependencies) but shorter.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">deps</span> <span class="o">=</span> <span class="nx">module</span><span class="p">.</span><span class="nx">deps</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">deps</span><span class="p">)</span> <span class="p">{</span> <span class="nx">code</span> <span class="o">=</span> <span class="nx">module</span> <span class="o">+</span> <span class="s2">""</span><span class="p">;</span> <span class="nx">deps</span> <span class="o">=</span> <span class="nx">module</span><span class="p">.</span><span class="nx">deps</span> <span class="o">=</span> <span class="p">{};</span> <span class="nx">requireExp</span><span class="p">.</span><span class="nx">lastIndex</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">while</span> <span class="p">((</span><span class="nx">match</span> <span class="o">=</span> <span class="nx">requireExp</span><span class="p">.</span><span class="nx">exec</span><span class="p">(</span><span class="nx">code</span><span class="p">)))</span> <span class="nx">deps</span><span class="p">[</span><span class="nx">absolutize</span><span class="p">(</span><span class="nx">match</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="nx">module</span><span class="p">.</span><span class="nx">id</span><span class="p">)]</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-22"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-22">¶</a> </div> <p>There may be cycles in the dependency graph, so we must be careful that the recursion always terminates. Each module we check is temporarily marked as <code>.seen</code> before its dependencies are traversed, so that if we encounter the same module again we can immediately return <code>true</code>.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">module</span><span class="p">.</span><span class="nx">seen</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span> <span class="k">for</span> <span class="p">(</span><span class="nx">id</span> <span class="k">in</span> <span class="nx">deps</span><span class="p">)</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="nx">hasOwn</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">deps</span><span class="p">,</span> <span class="nx">id</span><span class="p">))</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-23">¶</a> </div> <p>Once a dependency is determined to be satisfied, we remove its identifier from <code>module.deps</code>, so that we can avoid considering it again if <code>ready</code> is called multiple times.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span> <span class="p">(</span><span class="nx">hasOwn</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">installed</span><span class="p">,</span> <span class="nx">id</span><span class="p">)</span> <span class="o">&&</span> <span class="nx">ready</span><span class="p">(</span><span class="nx">installed</span><span class="p">[</span><span class="nx">id</span><span class="p">]))</span> <span class="p">{</span> <span class="k">delete</span> <span class="nx">deps</span><span class="p">[</span><span class="nx">id</span><span class="p">];</span></pre></div> </td> </tr> <tr id="section-24"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-24">¶</a> </div> <p>If any dependency is missing or not <code>ready</code>, then the current module is not yet <code>ready</code>. The <code>break</code> is not strictly necessary here, but immediately terminating the loop postpones work that can be done later.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="nx">result</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span> <span class="k">break</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-25">¶</a> </div> <p>Ordinarily I would be more paranoid about always resetting <code>module.seen</code> to <code>false</code>, but if you thoroughly examine the code above, you'll find that the only real threat of exceptions comes from evaluating <code>code = module + ""</code> in a recursive call to <code>ready</code>. So if you decide to override the <code>.toString</code> method of a module for performance reasons, get it right.</p> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">module</span><span class="p">.</span><span class="nx">seen</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span> <span class="p">}</span> <span class="k">return</span> <span class="nx">result</span><span class="p">;</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-26">¶</a> </div> <p>The most reliable way to get the global object: <a href="http://stackoverflow.com/a/3277192/128454">http://stackoverflow.com/a/3277192/128454</a></p> </td> <td class="code"> <div class="highlight"><pre><span class="p">}(</span><span class="nb">Function</span><span class="p">(</span><span class="s2">"return this"</span><span class="p">)()));</span> </pre></div> </td> </tr> </tbody> </table> </div> </body> </html>