Skip to content
Browse files

Merge branch '1.0-wip'

Conflicts:
	README.md
	lib/ender.js
	package.json
	support/closure.jar
  • Loading branch information...
2 parents f11cab9 + 3fd53f5 commit c9e97442a025ff781d81be87859500ca48e0b6dd @rvagg rvagg committed Feb 16, 2013
Showing with 5,457 additions and 1,980 deletions.
  1. +1 −6 .gitignore
  2. +29 −0 .jshintrc
  3. +1 −4 .travis.yml
  4. +52 −0 Changelog.md
  5. +20 −0 Contributors
  6. +39 −0 LICENSE
  7. +12 −5 Makefile
  8. +28 −0 README.md
  9. +4 −1 bin/ender
  10. +38 −0 buster.js
  11. +22 −0 lib/README.md
  12. +0 −27 lib/ender.closure.js
  13. +0 −100 lib/ender.cmd.js
  14. +0 −116 lib/ender.docs.js
  15. +0 −519 lib/ender.file.js
  16. +0 −35 lib/ender.get.js
  17. +0 −272 lib/ender.js
  18. +0 −186 lib/ender.npm.js
  19. +0 −140 lib/ender.search.js
  20. +0 −65 lib/ender.util.js
  21. +41 −0 lib/errors.js
  22. +51 −0 lib/main-add.js
  23. +65 −0 lib/main-build-util.js
  24. +76 −0 lib/main-build.js
  25. +113 −0 lib/main-compile.js
  26. +68 −0 lib/main-help.js
  27. +71 −0 lib/main-info-util.js
  28. +97 −0 lib/main-info.js
  29. +50 −0 lib/main-refresh.js
  30. +77 −0 lib/main-remove.js
  31. +61 −0 lib/main-search-util.js
  32. +116 −0 lib/main-search.js
  33. +50 −0 lib/main-version.js
  34. +84 −0 lib/main.js
  35. +37 −0 lib/output/main-add-output.js
  36. +55 −0 lib/output/main-build-output.js
  37. +51 −0 lib/output/main-compile-output.js
  38. +46 −0 lib/output/main-help-output.js
  39. +68 −0 lib/output/main-info-output.js
  40. +37 −0 lib/output/main-refresh-output.js
  41. +37 −0 lib/output/main-remove-output.js
  42. +97 −0 lib/output/main-search-output.js
  43. +40 −0 lib/output/main-version-output.js
  44. +98 −0 lib/output/output.js
  45. +74 −0 lib/parse-context.js
  46. +38 −0 lib/util.js
  47. +40 −21 package.json
  48. +13 −0 resources/build.mustache
  49. +7 −0 resources/help/add.tmpl
  50. +14 −0 resources/help/build.tmpl
  51. +15 −0 resources/help/compile.tmpl
  52. +7 −0 resources/help/info.tmpl
  53. +32 −0 resources/help/main.tmpl
  54. +7 −0 resources/help/refresh.tmpl
  55. +8 −0 resources/help/remove.tmpl
  56. +6 −0 resources/help/search.tmpl
  57. +82 −0 resources/help/zalgo.tmpl
  58. +10 −0 resources/root-package.mustache
  59. +1 −0 resources/source-file.mustache
  60. +19 −0 resources/source-package.mustache
  61. BIN support/closure.jar
  62. +0 −98 test/O_O.js
  63. +57 −0 test/common.js
  64. +144 −0 test/functional/add-test.js
  65. +94 −0 test/functional/build-from-package-json-test.js
  66. +75 −0 test/functional/build-packages-with-binaries-test.js
  67. +246 −0 test/functional/build-test.js
  68. +234 −0 test/functional/common.js
  69. +108 −0 test/functional/info-test.js
  70. +146 −0 test/functional/minifier-test.js
  71. +81 −0 test/functional/noop-test.js
  72. +76 −0 test/functional/output-test.js
  73. +117 −0 test/functional/package-descriptor-overrides.js
  74. +1 −0 test/functional/packages/endr-test-1/bridge.js
  75. +1 −0 test/functional/packages/endr-test-1/main-override.js
  76. +1 −0 test/functional/packages/endr-test-1/main.js
  77. +21 −0 test/functional/packages/endr-test-1/package.json
  78. +1 −0 test/functional/packages/endr-test-2/main.js
  79. +18 −0 test/functional/packages/endr-test-2/package.json
  80. +126 −0 test/functional/refresh-test.js
  81. +149 −0 test/functional/remove-test.js
  82. +59 −0 test/functional/version-test.js
  83. +0 −385 test/test.js
  84. +67 −0 test/unit/main-add-test.js
  85. +88 −0 test/unit/main-build-test.js
  86. +164 −0 test/unit/main-build-util-test.js
  87. +199 −0 test/unit/main-compile-test.js
  88. +87 −0 test/unit/main-help-test.js
  89. +100 −0 test/unit/main-info-test.js
  90. +95 −0 test/unit/main-info-util-test.js
  91. +82 −0 test/unit/main-remove-test.js
  92. +53 −0 test/unit/main-search-output-test.js
  93. +83 −0 test/unit/main-search-test.js
  94. +53 −0 test/unit/main-search-util-test.js
  95. +73 −0 test/unit/main-test.js
  96. +81 −0 test/unit/main-version-test.js
  97. +85 −0 test/unit/output-test.js
  98. +187 −0 test/unit/parse-context-test.js
View
7 .gitignore
@@ -1,6 +1 @@
-node_modules/
-test/ender.js
-test/ender.min.js
-test/node_modules/
-test/js/bean.js
-test/js/bean.min.js
+node_modules
View
29 .jshintrc
@@ -0,0 +1,29 @@
+{
+ "predef": [ "assert", "refute" ]
+ , "boss": true
+ , "bitwise": true
+ , "shadow": true
+ , "trailing": true
+ , "immed": true
+ , "latedef": true
+ , "forin": false
+ , "curly": false
+ , "debug": true
+ , "devel": false
+ , "evil": true
+ , "regexp": false
+ , "undef": true
+ , "sub": true
+ , "white": false
+ , "asi": true
+ , "laxbreak": true
+ , "eqnull": true
+ , "browser": true
+ , "node": true
+ , "laxcomma": true
+ , "proto": true
+ , "expr": true
+ , "es5": true
+ , "esnext": true
+ , "strict": false
+}
View
5 .travis.yml
@@ -1,12 +1,9 @@
language: node_js
node_js:
- - 0.6
+ - 0.8
branches:
only:
- master
- - 1.0-wip
notifications:
email:
- - dustin@dustindiaz.com
- rod@vagg.org
- - jacob@twitter.com
View
52 Changelog.md
@@ -0,0 +1,52 @@
+0.9.12-dev (1.0-wip) / 2012-12-28
+=================================
+
+ * Heavily refactored code into multiple, separate, packages.
+ * Lots of minor tweaks and fixes
+
+0.9.6-dev (1.0-wip) / 2012-10-16
+================================
+
+ * Update Closure Compiler version in ender-minify to r2180
+
+0.9.5-dev (1.0-wip) / 2012-10-15
+================================
+
+ * "externs" key (or "ender"->"externs", or "overlay"->"ender"->"externs") for each package in a build can supply an array of files that are passed to Closure as --externs arguments, on top of any Ender --externs arguments
+
+0.9.4-dev (1.0-wip) / 2012-06-20
+================================
+
+ * Additional support for overriding package.json keys with "ender" (and "overlay"->"ender" key)
+ * Node 0.7/0.8 support
+ * Use new `logstream` property in npm (@1.1.30) rather than the (removed) `logfd`
+ * extract ender-minify project
+ * --minifier argument to switch between Closure and UglifyJS (default)
+
+0.9.3-dev (1.0-wip) / 2012-06-01
+================================
+
+ * Adjust package.json data after reading to allow for some keys in an "ender" object (if it exists) to override root keys, including "name", "main", "ender" (bridge), "dependencies". Also accept overriding with "overlay"->"ender" as per the CommonJS Packages spec.
+ * Take more responsibility for deciding which packages to install via npm. If packages are already in node_modules they are not installed with npm *unless* the package is specified as a path. Also allows Ender to install dependencies specified in "ender"->"dependencies".
+ * --force-install option to force npm install of root packages, always true for for `refresh`
+ * --quiet option to suppress stdout (except for errors)
+ * upgrade dependencies
+ * fix dupe dir scanning for dependency tree construction
+ * add Contributors file
+ * add Changelog.md file
+ * --level (-l) of whitespace|simple|advanced to pass to Closure compiler
+
+0.9.x-dev (1.0-wip)
+===================
+
+ * Nearly complete rewrite of 0.8.x branch, mainly to solve dependency tree related problems, feature-compatible with 0.8.x
+ * Dependencies are properly ordered (dependencies come before their dependents) and always come out in the same order on each build
+ * Stdout is now exclusively performed via the modules in the lib/output/ directory
+ * `ender info` is now run after a build/add/remove/set/refresh
+ * "ender" key in package.json can now take an array of files to concatenate to build a bridge file, just like the "main" key
+ * The --client-lib command line argument can be used to override the default root/client library 'ender-js'
+ * Much better error handling and reporting, including a --debug option for extra detail
+ * bin/ender gives proper exit codes in all cases, 0 for success and 1 for any kind of error--good for including in a build chain (such as a Makefile)
+ * Tons of tests, unit tests and functional tests; uses BusterJS
+ * Template-based build process, uses Hogan to compile ender.js from sources
+ * ... lots of other stuff ...
View
20 Contributors
@@ -0,0 +1,20 @@
+ 173 Jacob Thornton 37.9%
+ 129 Rod Vagg 28.3%
+ 125 Dustin Diaz 27.4%
+ 5 Tim Fischbach 1.1%
+ 3 Erin 0.7%
+ 3 matt knox 0.7%
+ 2 AJ ONeal 0.4%
+ 2 Andrew McCollum 0.4%
+ 2 David Wood 0.4%
+ 2 Drew Robinson 0.4%
+ 1 Andrew Plummer 0.2%
+ 1 Connor Montgomery 0.2%
+ 1 Jameson Little 0.2%
+ 1 Kit Goncharov 0.2%
+ 1 Paul Vorbach 0.2%
+ 1 Pelle Wessman 0.2%
+ 1 Raynos 0.2%
+ 1 Torgeir Thoresen 0.2%
+ 1 rvagg 0.2%
+ 1 tbranyen 0.2%
View
39 LICENSE
@@ -0,0 +1,39 @@
+Copyright 2012, Rod Vagg, Dustin Diaz, Jacob Thornton and other contributors. (the "Original Author")
+All rights reserved.
+
+MIT +no-false-attribs License
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+Distributions of all or part of the Software intended to be used
+by the recipients as they would use the unmodified Software,
+containing modifications that substantially alter, remove, or
+disable functionality of the Software, outside of the documented
+configuration mechanisms provided by the Software, shall be
+modified such that the Original Author's bug reporting email
+addresses and urls are either replaced with the contact information
+of the parties responsible for the changes, or removed entirely.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+
+Except where noted, this license applies to any and all software
+programs and associated documentation files created by the
+Original Author, when distributed with the Software.
View
17 Makefile
@@ -1,7 +1,14 @@
-.PHONY: test
+unittests:
+ @node -e "require('colors');console.log('Running unit tests...'.bold.yellow)"
+ @./node_modules/.bin/jshint lib/ test/unit/
+ @./node_modules/.bin/buster-test -g unit
-test:
- @rm -rf test/node_modules
- @npm install > /dev/null
- @cd ./test; node ./test.js;
+functionaltests:
+ @node -e "require('colors');console.log('Running functional tests (patience please)...'.bold.yellow)"
+ @./node_modules/.bin/jshint lib/ test/functional/
+ @./node_modules/.bin/buster-test -g functional
+alltests: unittests functionaltests
+
+contributors:
+ git summary | grep -P '^\s+\d' > Contributors
View
28 README.md
@@ -1,3 +1,31 @@
+#Ender 1.0 - work in progress - developer notes
+
+Architecture notes can be found in *lib/README.md*.
+
+This branch won't be deployed to npm until it's ready for a 1.0 release. Use `npm link` to install your local repo as the global *ender* package.
+
+What does *ready* mean? We haven't quite pinned that down yet, but we'll get there!
+
+Use `npm install` to install both the dependencies and the devDependencies, otherwise you won't be able to run the executable (in *bin/ender*) or run the tests (using the Makefile).
+
+Unit tests can be invoked by running a `make` or `make unittests`. Functional tests take longer to run as they check out packages from npm and can be invoked by running a `make functionaltests`. All types of tests can be run with `make alltests`--**this must be done before any pull-request and must all pass**.
+
+Tests use BusterJS, you can read more about it [here](http://busterjs.org/). Buster has integrated support for Sinon for mocking and stubbing, you can read more about it [here](http://sinonjs.org/). Note that Buster is still in Beta and may occasionally break. Bug @augustl or @cjno about that.
+
+Feel free to open an issue on GitHub if you would like to discuss something or want support of some kind. Alternatively you can bug [@rvagg](http://twitter.com/rvagg) on Twitter or via [email](mailto:rod@vagg.org).
+
+## Some behavioural differences from 0.8.x
+
+This branch should do everything that the current 0.8.x branch does, with some additions:
+
+ * Some of the output to stdout will be different. Mostly minor wording changes but also the `ender info` output is included in each *build*, *add* and *remove*.
+ * Packages are properly ordered (*!!*). Your *ender.js* will contain the packages you requested *in the order you requested them* on the commandline, with any dependencies placed *before* they are required.
+ * *bin/ender* now gives proper exit-codes, if there is any kind of error you'll get a `1`, otherwise a `0`.
+ * The `"ender"` key in *package.json* supports an array of files to concatenate to form the bridge.
+ * A new `--client-lib` argument can be used to specify an alternative to the default *ender-js* package as a client lib. At the moment a client lib still needs to conform to the basics of the `$` + CommonJS pattern in order to support existing Ender packages.
+
+------------
+
#ENDER [![Build Status](https://secure.travis-ci.org/ender-js/Ender.png)](http://travis-ci.org/ender-js/Ender)
**Ender is a full featured package manager for your browser.**<br/>
View
5 bin/ender
@@ -1,2 +1,5 @@
#!/usr/bin/env node
-require('../lib/ender').exec(process.argv);
+
+require('../lib/main').exec(process.argv, function (err) {
+ process.exit(err ? 1 : 0)
+})
View
38 buster.js
@@ -0,0 +1,38 @@
+/*!
+ * ENDER - The open module JavaScript framework
+ *
+ * Copyright (c) 2011-2012 @ded, @fat, @rvagg and other contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+var config = module.exports
+
+config['unit'] = {
+ environment: 'node'
+ , tests: [ 'test/unit/*-test.js' ]
+ , libs: [ 'test/common.js' ]
+}
+
+config['functional'] = {
+ environment: 'node'
+ , tests: [ 'test/functional/*-test.js' ]
+ , libs: [ 'test/common.js' ]
+}
View
22 lib/README.md
@@ -0,0 +1,22 @@
+# Architecture notes
+
+The main entry point of the application is `exec()` in *main.js*. This is used by *../bin/ender* and accepts a standard argv array. It can also take a build string which it will split and parse (see the *version* functional test for an example of this).
+
+*args-parse.js* is used to parse the commandline and will determine which 'main' command to run. Each available 'main' command has a *main-X.js* file and an *output/main-X-output.js* file which are loaded by *main.js* and executed.
+
+Each main main-X module has an `exec()` method that is called by *main.js* with the parsed commandline arguments, an 'output' object and a callback. The 'output' object is constructed by the corresponding output/main-X-output module and is responsible for all stdout for that command. Nothing is printed to stdout except by the objects available in the *output/* directory. This separation should allow for alternative front-ends to be applied to Ender and other creative uses of Ender via the API.
+
+All interaction with npm occurs through *repository.js*, knowledge of npm is completely partitioned from the rest of the application. *install.js* handles all the special logic to decide which packages need to be installed via npm.
+
+Utilities for dealing with Node packages are kept in *package-util.js* (i.e. anything to do with 'node_modules' or 'package.json').
+
+Ender builds are compiled in the *SourceBuild* object which contains a single *SourcePackage* object for each package in the build. *SourcePackage* understands how to assemble the JavaScript source for that package (the 'main' and 'ender' files). *SourceBuild* knows how to put the packages together for a plain and minified build.
+
+The most complicated parts of the application can be found in *main-build-util.js* where the dependency tree is built from package.json files and node_modules directories and forEach* utilities are used to traverse the tree and spit out the required packages.
+
+## Some general rules
+
+ * No stdout except via *output* modules.
+ * No global or module-globals for keeping state. Everything is either passed from function-to-function or is kept in an object that is instantiated by `Object.create()`. The *output* modules are instantiated as are the *SourceBuild* and *SourcePackage* objects. There are a couple of minor exceptions to this rule for caching results (in *template.js* for instance).
+ * Complicated utility functions for the main executable modules are stored in their corresponding *-util.js* module and are exposed via `module.exports`. This way the executable modules can be kept relatively clean and the uility functions can be easily unit-tested.
+ * Unit tests for as much as possible, functional tests for broad, verifiable executable processes.
View
27 lib/ender.closure.js
@@ -1,27 +0,0 @@
-var process = require('child_process')
- , path = require('path')
- , exec = process.exec
- , CLOSURE = {
-
- compile: function (files, outfile, callback) {
- var nextIsExterns = false
-
- files = files.map(function (file) {
- if (file == '--externs') {
- nextIsExterns = true
- return ''
- } else if(nextIsExterns) {
- nextIsExterns = false
- return '--externs=' + file
- }
- return '--js=' + file
- }).join(' ')
- var jar = path.join(__dirname, '../support/closure.jar')
- exec('java -jar ' + jar + ' --compilation_level ADVANCED_OPTIMIZATIONS ' + files + ' --js_output_file=' + outfile, function (err, out, stderr) {
- if (err) return console.log('Something went wrong trying to compile :('.red)
- callback()
- })
- }
- }
-
-module.exports = CLOSURE
View
100 lib/ender.cmd.js
@@ -1,100 +0,0 @@
-/*COMMAND METHODS*/
-var ENDER = {
- util: require('./ender.util')
-}
-
-module.exports = {
-
- process: function (cmd, callback) {
- var cmdOptions = typeof cmd == 'string' ? cmd.split(' ').slice(1) : cmd.slice(2)
- , type = cmdOptions.shift()
- , options = {}
- , context = ''
- , option
- , value
- , size
- , opts
- , i
- , j
- , l
-
- for (i = cmdOptions.length; i--;) {
- option = cmdOptions[i]
- size = 0
- if (option == '-o' || option == '--output') {
- option = 'output'
- value = cmdOptions[i + 1] && cmdOptions[i + 1].replace(/\.js$/, '')
- size = 2
- } else if (option == '--use' || option == '-u') {
- option = 'use'
- value = cmdOptions[i + 1] && cmdOptions[i + 1].replace(/\.js$/, '')
- size = 2
- } else if (option == '--max') {
- option = 'max'
- value = cmdOptions[i + 1]
- size = 2
- } else if (option == '--sandbox') {
- option = 'sandbox'
- opts = cmdOptions.slice(i + 1)
- for (j = 0, l = opts.length; j < l; j++) {
- if (!opts[j].indexOf('-')) break
- }
- value = opts.splice(0, j)
- size = 1 + value.length
- } else if (option == '--noop' || option == '-x'){
- option = 'noop'
- value = true
- size = 1
- } else if (option == '--silent' || option == '-s') {
- option = 'silent'
- value = true
- size = 1
- } else if (option == '--help') {
- option = 'help'
- value = true
- size = 1
- } else if (option == '--sans') {
- option = 'sans'
- value = true
- size = 1
- } else if (option == '--debug') {
- option = 'debug'
- value = true
- size = 1
- }
-
- if (size) {
- options[option] = value
- cmdOptions.splice(i, size)
- }
- }
-
- for (i in options) {
- context += ' --' + i + (typeof options[i] == 'string' ? ' ' + options[i] : '')
- }
-
- if (context) {
- options.context = context
- }
-
- type = type ? type.toLowerCase() : 'help'
-
- if (/\-v/.test(type)) {
- type = 'version'
- }
-
- cmdOptions = cmdOptions.join(',').replace(/\,(?=\,)/g,'').split(',').filter(function(x){ return x !== '' })
-
- callback(null, type, cmdOptions, options)
- }
-
- , normalize: function (packages) {
- return ENDER.util.reject(packages, ['ender-js'])
- }
-
- , getContext: function (type, packages, options) {
- packages = this.normalize(packages)
- return [type].concat(packages).join(' ') + (options || '')
- }
-
-}
View
116 lib/ender.docs.js
@@ -1,116 +0,0 @@
-var ENDER = {
-
- util: require('./ender.util')
-
- , docs: {
-
- build: '- build:\n'.yellow +
- ' + accepts multiple npm packages to build into ender library\n' +
- ' + example: $ ' + 'ender build domready qwery bean\n'.cyan +
- ' + note: alternatively you can specify the -b flag\n' +
- ' + options:\n'.red +
- ' - ' + '--sandbox'.yellow + ' (--sandbox) Prevents global leakage of ender lib variables. Passing additional arguments will define the specified packages directly on the window.\n' +
- ' + example: ' + '$ ender build jeesh backbone --sandbox backbone\n'.cyan +
- ' - ' + '--noop'.yellow + ' (--noop, -x) build without the ender-js client library\n' +
- ' + example: ' + '$ ender build mootools-class --noop\n'.cyan +
- ' - ' + '--output'.yellow + ' (--output, -o) out ender library to path with custom name\n' +
- ' + example: ' + '$ ender build mootools-class --output ../public/js/mootools.js\n'.cyan +
- ' + (above example would generate a mootools.js file as well as a mootools.min.js file in the ../public/js/ dir.)\n\n'
-
- , refresh: '- refresh:\n'.yellow +
- ' + refreshes the current build (reinstalls all packages)\n' +
- ' + example: $ ender refresh\n' +
- ' + options:\n'.red +
- ' - ' + '--use'.yellow + ' (--use, -u) target a specific ender package (without use, ender defaults to local ender.js || ender.min.js)\n' +
- ' + example: ' + '$ ender refresh -u ../public/js/mootools.js\n\n'.cyan
-
- , add: '- add:\n'.yellow +
- ' + adds a package to the current ender build\n' +
- ' + example: $ ender add underscore backbone\n' +
- ' + options:\n'.red +
- ' - ' + '--use'.yellow + ' (--use, -u) target a specific ender package (without use, ender defaults to local ender.js || ender.min.js)\n' +
- ' + example: ' + '$ ender add -u ../public/js/mootools.js\n\n'.cyan
-
- , remove: '- remove:\n'.yellow +
- ' + removes a package from the current ender build\n' +
- ' + example: $ ender remove underscore backbone\n' +
- ' + note: alternatively you can specify the -d flag ($ ender -d underscore backbone)\n' +
- ' + options:\n'.red +
- ' - ' + '--use'.yellow + ' (--use, -u) target a specific ender package (without use, ender defaults to local ender.js || ender.min.js)\n' +
- ' + example: ' + '$ ender remove -u ../public/js/mootools.js\n\n'.cyan
-
- , info: '- info:\n'.yellow +
- ' + gives you the status of the current ender build (including files size and package list)\n' +
- ' + example: $ ender info\n' +
- ' + note: alternatively you can specify the -i flag ($ ender -i underscore backbone)\n' +
- ' + options:\n'.red +
- ' - ' + '--use'.yellow + ' (--use, -u) target a specific ender package (without use, ender defaults to local ender.js || ender.min.js)\n' +
- ' + example: ' + '$ ender info -u ../public/js/mootools.js\n\n'.cyan
-
- , search: '- search:\n'.yellow +
- ' + searches NPM registry for provided keywords -- bubbles up ender compatible modules' +
- ' + example: ' + '$ ender search bean\n'.cyan +
- ' + options:\n'.red +
- ' - ' + '--max'.yellow + ' (--max) set a max number of search results to return (defaults to 8)\n' +
- ' + example: ' + '$ ender search selector engine --max 20\n\n'.cyan
-
- , compile: '- compile:\n'.yellow +
- ' + Allows you to compile your application along-side your ender installation using the Google Closure Compiler\n' +
- ' + example: ' + '$ ender compile header.js footer.js app.js\n'.cyan +
- ' - ' + '--use'.yellow + ' target a specific ender package (without use, ender defaults to local ender.js)\n' +
- ' + example: ' + '$ ender compile app.js -u myenderbuild.js\n'.cyan +
- ' - ' + '--output'.yellow + ' write the compiled file to somewhere other than ender-app.js\n' +
- ' + example: ' + '$ ender compile app.js -o myapp.js\n'.cyan +
- ' - ' + '--externs'.yellow + ' pass through any externs files to Closure Compiler\n' +
- ' + example: ' + '$ ender compile header.js footer.js app.js --externs externs1.js externs2.js\n\n'.cyan
-
-
- , overview: '\nMethods'.red + ' - for more info on any one method run ' + '$ ender method --help\n'.cyan +
- '----------------------------------------------------------------------\n' +
-
- '- build:\n'.yellow +
- ' + accepts multiple npm packages to build into ender library\n' +
- ' + example: ' + '$ ender build domready qwery bean\n'.cyan +
-
- '- refresh:\n'.yellow +
- ' + refreshes the current build (reinstalls all packages)\n' +
- ' + example: ' + '$ ender refresh\n'.cyan +
-
- '- add:\n'.yellow +
- ' + adds a package to the current ender build\n' +
- ' + example: ' + '$ ender add underscore backbone\n'.cyan +
-
- '- remove:\n'.yellow +
- ' + removes a package from the current ender build\n' +
- ' + example: '+ '$ ender remove underscore backbone\n'.cyan +
-
- '- info:\n'.yellow +
- ' + gives you the status of the current ender build (including files size and package list)\n' +
- ' + example: ' + '$ ender info\n'.cyan +
-
- '- search:\n'.yellow +
- ' + searches NPM registry for provided keywords -- bubbles up ender compatible modules\n' +
- ' + example: ' + '$ ender search selector engine\n'.cyan +
-
- '- compile:\n'.yellow +
- ' + Allows you to compile your application along-side your ender installation using the Google Closure Compiler\n' +
- ' + example: ' + '$ ender compile header.js footer.js app.js\n\n'.cyan +
-
-
- 'General Help\n'.red +
- '------------\n' +
- 'If you get stuck please visit ' + 'http://github.com/ender-js/Ender'.yellow + ' and file an issue.\n\n' +
- 'You may also want to consider @messaging ' + '@fat'.yellow + ' or ' + '@ded'.yellow + ' on twitter directly\n'
-
- }
- }
-
-module.exports = ENDER.util.merge(ENDER.docs, {
-
- 'rm': ENDER.docs.remove
-
- , 'ls': ENDER.docs.info
-
- , 'list': ENDER.docs.info
-
-});
View
519 lib/ender.file.js
@@ -1,519 +0,0 @@
-var fs = require('fs')
- , path = require('path')
- , gzip = require('zlib').gzip
- , async = require('async')
- , uglifyJS = require('uglify-js')
- , ENDER = {
- util: require('./ender.util')
- , get: require('./ender.get')
- }
-
-ENDER.file = module.exports = {
-
- getComment: function (context) {
- return (
- [ "/*!"
- , " * ============================================================="
- , " * Ender: open module JavaScript framework (https://ender.no.de)"
- , " * Build: ender " + context
- , " * ============================================================="
- , " */"
- ].join('\n')
- )
- }
-
-, uglifySource: function (source, callback) {
- try {
- var comments = []
- , token = '"Ender: preserved comment block"'
- , reMultiComments = /\/\*![\s\S]*?\*\//g
-
- , reTokens = RegExp(token, 'g')
-
- , tok
- , ast
- , c
- source = source.replace(reMultiComments, function(comment) {
- comments.push(comment)
- return token
- })
-
- tok = uglifyJS.parser.tokenizer(source)
- c = tok()
- ast = uglifyJS.parser.parse(source)
- ast = uglifyJS.uglify.ast_mangle(ast)
- ast = uglifyJS.uglify.ast_squeeze(ast, {
- make_seqs: false
- })
- source = uglifyJS.uglify.gen_code(ast)
-
- source = source.replace(reTokens, function() {
- return '\n' + comments.shift() + '\n'
- })
-
- callback(null, source)
- } catch (e) {
- callback(e)
- }
- }
-
-, uglify: function (source, filename, context, options, callback) {
- ENDER.file.uglifySource(source, function (err, source) {
- if (err) {
- console.log('Ender was unable to minify your library with UglifyJS!'.red)
- return console.log('This usually means you have a js syntax error in one of your packages.')
- }
-
- filename = filename || 'ender'
- filename += '.min'
- ENDER.file.output(source, filename, context, options, callback)
- })
- }
-
-, output: function(data, filename, context, options, callback) {
- filename = filename || 'ender'
- filename += '.js'
-
- fs.writeFile(filename, ([ENDER.file.getComment(context), data].join('\n\n')), encoding='utf8', function (err) {
- if (err) {
- if (options.debug) throw err
- console.log('something went wrong trying to write to ' + filename + '.')
- return callback(err)
- }
- console.log((filename + ' successfully built!').yellow)
- callback()
- })
- }
-
-, prettyPrintEnderSize: function (type, file, callback) {
- file = file || 'ender'
- file += '.js'
-
- path.exists(file, function (exists) {
- if (exists) {
- async.waterfall([
- async.apply(fs.readFile, file, 'utf-8')
- , ENDER.file.uglifySource
- , ENDER.file.gzip
- , writeSize
- ])
- } else if(/\.min\.js$/.test(file)) {
- console.log('Active Ender library couldn\'t be found.')
- callback(new Error)
- } else {
- ENDER.file.prettyPrintEnderSize(type, file.replace(/\.js$/, '.min'), callback)
- }
- })
-
- function writeSize (data) {
- console.log('Your current build type is ' + ('"' + type + '"').yellow)
- console.log('Your current minified and compressed library size is ' + ((Math.round((data.length/1024) * 10) / 10) + '').yellow + ' kB\n')
- callback && callback()
- }
- }
-
-, createDir: function (dir, callback) {
- path.exists(dir, function(exists) {
- if (!exists) {
- fs.mkdir(dir, 0777, function (err) {
- if (err) {
- callback(err)
- return console.log("something went wrong trying to create your dir :(")
- }
- callback()
- })
- } else {
- callback()
- }
- })
- }
-
-, gzip: function (_data, callback) {
- gzip(_data, function (err, data) {
- if (err) {
- console.log('failed to gzip file')
- callback(err)
- }
- callback(null, data)
- })
- }
-
-, assemble: function (packages, options, callback){
- console.log('assembling packages...')
- packages = packages.map(function (item) { return item.replace(/@.*/, '') })
-
- ENDER.file.processPackages(packages, options, function (err, result) {
- result = result.join('\n\n')
- if (options.sandbox) {
- result = ['(function () {', result, '}).call({});'].join('\n\n')
- }
- callback(null, result)
- })
- }
-
-, validatePaths: function (paths, uniques, callback) {
- var j = 0
- , k = paths.length
- , fullPath
-
- paths.forEach(function (packagePath, i) {
- fullPath = path.join('node_modules', packagePath.replace(/\//g, '/node_modules/'))
- path.exists(fullPath, function(exists) {
- if (!exists) {
- i = uniques.indexOf(packagePath)
- paths.splice(i, 1)
- uniques.splice(i, 1)
- }
- if (++j == k) {
- callback(null, paths, uniques)
- }
- })
- })
- }
-
-, flattenDependencyTree: function (tree, uniques, callback) {
- var packages = []
- , flattenedTree
- , packageName
- , cleanPackageName
- , packageValue
- , reg
- , j
-
- uniques = uniques || []
-
- for (packageName in tree) {
-
- if (~uniques.indexOf(packageName)) {
- continue
- }
-
- packageValue = tree[packageName]
-
- if (!~packageValue) {
- packageName = '!@' + packageName
- } else if (packageValue) {
- flattenedTree = this.flattenDependencyTree(packageValue, uniques)
- flattenedTree = flattenedTree.map(function (treeItem) {
- if (treeItem.indexOf('!@')) {
- return [packageName, treeItem].join('/')
- } else {
- cleanPackageName = treeItem.replace(/^!@/, '')
- if (~tree[cleanPackageName]) {
- return cleanPackageName
- }
- }
- }).filter(function (item) {
- return item
- })
- packages = packages.concat(flattenedTree)
- }
-
- packages.push(packageName)
- uniques.push(packageName)
- }
-
- if (callback) {
- return ENDER.file.orderFlattenedTree(packages, uniques, callback)
- }
-
- return packages
- }
-
-, orderFlattenedTree: function (packages, uniques, callback) {
- var ordered = []
- , i = 0
- , l = packages.length
- , j
- , packageName
- , packageMatcher
- , lookahead
-
- for (i; i < l; i++) {
- packageName = packages[i]
- packageMatcher = RegExp('^' + packageName + '(@|$)')
-
- if (!packageName) {
- continue
- }
-
- for (j = i + 1; j < l; j++) {
- lookahead = packages[j]
- if (packageMatcher.test(lookahead) && !~ordered.indexOf(lookahead)) {
- ordered.push(lookahead)
- packages[j] = false
- }
- }
-
- if (!~ordered.indexOf(packageName)) {
- ordered.push(packageName)
- }
- }
-
- uniques = ordered.map(function (uniquePackage) {
- return uniquePackage.replace(/.*(?=\/.*)\/?/, '')
- })
-
- callback(null, ordered, uniques)
- }
-
-// Recursive function to create a dependency tree.
-// + 0 == package found, with no dependency
-// + -1 == package not found
-// + object means, file has x dependencies
-//
-// Example Obj:
-// ============
-//
-// tree = {
-// somePackage: {
-// backbone: {
-// underscore: -1
-// }
-// , underscore: 0
-// }
-// }
-
-, constructDependencyTree: function (packages, dir, callback) {
- var tree = {}
- , x = 0
- , that = this
-
- packages.forEach(function (packageName) {
- var packageName = packageName.replace(/\@.*/, '')
- , packagePath = /^[\/.]/.test(packageName) ? path.join(packageName, 'package.json') : path.join(dir, packageName, 'package.json')
- , isInstallingFromRoot = /^\.\/?$/.test(packageName)
-
- async.waterfall([
- function (cb) { fs.readFile(packagePath, 'utf-8', function (err, data) { if (err) { return ++x } cb(err, data) }) }
- , function (data, cb) { ENDER.file.findDependencies(data, tree, dir, isInstallingFromRoot, cb) }
- , function () { if (++x == packages.length) { callback(null, tree) } }
- ])
- })
- }
-
-, findDependencies: function (data, tree, directory, isInstallingFromRoot, callback) {
- var packageJSON = JSON.parse(data)
- , dependencies = packageJSON.dependencies
- , packageName = packageJSON.name
-
- if (dependencies && !Array.isArray(dependencies)) {
- dependencies = Object.keys(dependencies)
- }
-
- if (!dependencies || dependencies.length == 0) {
- tree[packageName] = 0
- return callback(null, tree)
- }
-
- if (isInstallingFromRoot) {
- return ENDER.file.constructDependencyTree(dependencies, directory, function (err, result) {
- tree = ENDER.util.merge(tree, result)
- callback(null, tree)
- })
- }
-
- directory = path.join(directory, packageName, 'node_modules')
-
- path.exists(directory, function (exists) {
- if (exists) {
- return fs.readdir(directory, function (err, filenames) {
- dependencyFromDirectories(err, packageName, directory, filenames)
- })
- } else if (dependencies.length) {
- tree[packageName] = tree[packageName] || {}
- dependencies.forEach(function (item) {
- tree[packageName][item] = -1
- })
- } else {
- tree[packageName] = 0
- }
- callback(null, tree)
- })
-
- function dependencyFromDirectories(err, packageName, directory, filenames) {
- if (err) {
- console.log('something went wrong while trying to read ' + _dir)
- return callback(err)
- } else {
- //issue #40 ignore dirs != dependencies
- filenames = ENDER.util.keep(filenames, dependencies)
- ENDER.file.constructDependencyTree(filenames, directory, function (err, subTree) {
- tree[packageName] = subTree
- if (filenames.length != dependencies.length) {
- ENDER.util.reject(dependencies, filenames).forEach(function (item) {
- tree[packageName][item] = -1
- })
- }
- callback(null, tree)
- })
- }
- }
- }
-
-, getRootPackageName: function (packages, callback) {
- var packageJSON
- , packageName
- , i
- , l
-
- for (i = 0, l = packages.length; i < l; i++) {
- packageName = packages[i].replace(/\@.*/, '')
- if (/^\.\/?$/.test(packageName)) {
- return fs.readFile('./package.json', 'utf-8', function (err, data) {
- if (err) {
- callback(err)
- return console.log('something went wrong trying to read ./package.json')
- }
- packageJSON = JSON.parse(data)
- packageName = packageJSON.name
- callback(null, packageName)
- })
- }
- }
- callback(null, false)
- }
-
-, processPackages: function (packages, options, callback) {
- var result = []
- , packagesCompleteCount = 0
- , flattenedPackageLength
- , rootPackageName
-
- async.waterfall([
- async.apply(ENDER.file.getRootPackageName, packages)
- , function (name, cb) { rootPackageName = name; cb(); }
- , async.apply(ENDER.file.constructDependencyTree, packages, 'node_modules')
- , function (tree, cb) { ENDER.file.flattenDependencyTree(tree, null, cb) }
- , proccessPackageJSONs
- ])
-
- function proccessPackageJSONs(packages) {
- var clientPosition = packages.indexOf('ender-js')
- flattenedPackageLength = packages.length
-
- if (clientPosition > 0) { // move ender-js to top if present and not already there
- packages.splice(0, 0, packages.splice(clientPosition, 1)[0])
- }
-
- packages.forEach(function (packageName, index) {
- var packagePath = packageName == rootPackageName ? '.' : path.join('node_modules', packageName.replace(/\//g, '/node_modules/'))
- , packageJSONLocation = path.join(packagePath, 'package.json')
-
- path.exists(packageJSONLocation, function (exists) {
- if (!exists) {
- if (++packagesCompleteCount == flattenedPackageLength) {
- callback(result)
- }
- return console.log('The package.json for ' + packageName.red + ' could not be found.')
- }
-
- fs.readFile(packageJSONLocation, 'utf-8', function (err, data) {
- if (err && options.debug) throw err
- gatherSource(err, packageName, packagePath, index, data, options)
- })
- })
- })
- }
-
- function gatherSource(err, packageName, packagePath, index, data, options) {
- var packageJSON
- , parallelQue
- , source
-
- if (err) {
- return console.log('something went wrong trying to read ' + err.path)
- }
-
- packageJSON = JSON.parse(data)
-
- if (!packageJSON.main) {
- packageJSON.main = []
- } else if (typeof packageJSON.main == 'string') {
- packageJSON.main = [packageJSON.main]
- }
-
- parallelQue = {
- source: async.apply(ENDER.file.constructSource, packagePath, packageJSON.main)
- , content: async.apply(ENDER.file.constructBridge, packagePath, packageJSON.ender)
- }
-
- async.parallel(parallelQue, function (err, results) {
- if (err && options.debug) throw err
- var source = results.source
- , content = results.content
- , strippedName = packageName.replace(/.*(?=\/)\//, '')
-
- if (source && packageName != 'ender-js' && !options.noop) {
- source = [ '(function () {\n\n var module = { exports: {} }, exports = module.exports;'
- , source.replace(/\n/g, '\n ')
- , 'provide("' + strippedName + '", module.exports);'
- ]
-
- if (options.sandbox && ~options.sandbox.indexOf(strippedName)) {
- source.push('window["' + strippedName + '"] = module.exports;')
- }
-
- if (packageJSON.ender && content) {
- source.push(content.replace(/\n/g, '\n '))
- } else if (!packageJSON.ender) {
- source.push('$.ender(module.exports);')
- }
-
- source = source.join('\n\n ') + '\n\n}());'
- }
-
- if (options.sandbox && packageName == 'ender-js') {
- source = ['/* Declare local API */\nvar require, provide, $, ender;\n'
- , source
- , '\n/* Set Local API */\nrequire = this.require\nprovide = this.provide\nender = $ = this.ender;'
- ].join('\n')
- }
-
- result[index] = source
-
- if (++packagesCompleteCount == flattenedPackageLength) {
- callback && callback(null, result)
- }
- })
- }
- }
-
-, constructSource: function(packagePath, filePaths, callback) {
- var result = []
-
- if (!filePaths.length) {
- return callback && callback(null, '')
- }
-
- filePaths.forEach(function (filePath) {
- if (!(/\.js$/.test(filePath))) {
- filePath += '.js'
- }
- fs.readFile(path.join(packagePath, filePath), 'utf-8', function (err, data) {
- if (err) {
- callback(err)
- return console.log('something went wrong trying to read ' + path.join(packagePath, filePath))
- }
- result.push(data)
- if (filePaths.length == result.length) {
- callback && callback(null, result.join('\n\n'))
- }
- })
- })
- }
-
-, constructBridge: function (packagePath, bridge, callback) {
- if (!bridge || bridge == 'noop') {
- return callback && callback(null, '')
- }
- fs.readFile(path.join(packagePath, bridge), 'utf-8', function (err, data) {
- if (err) {
- callback(err)
- return console.log('something went wrong trying to read ' + path.join(packagePath, bridge))
- }
- callback && callback(null, data)
- })
- }
-
-}
View
35 lib/ender.get.js
@@ -1,35 +0,0 @@
-//internal get methods for ender
-var fs = require('fs')
- , path = require('path')
- , ENDER = { get: module.exports }
-
-module.exports = {
-
- special: function (options) {
- return options.sans || options.noop ? [] : ['ender-js'];
- }
-
- , buildHistory: function (file, callback) {
- file = file || 'ender'
- file = file += '.js'
-
- path.exists(file, function (exists) {
- if (exists) {
- returnBuildHistory(file)
- } else if(/\.min\.js$/.test(file)) {
- console.log('Active Ender library couldn\'t be found.')
- callback(new Error)
- }
- })
-
- function returnBuildHistory(file) {
- fs.readFile(file, 'utf-8', function (err, data) {
- if (err) {
- callback(err)
- return console.log('something went wrong trying to read' + file + '.js')
- }
- callback(null, data.match(/\*\sBuild:\s([^\n]*)/)[1])
- })
- }
- }
-}
View
272 lib/ender.js
@@ -1,272 +0,0 @@
-// Ender: open module JavaScript framework
-// copyright @ded and @fat
-// https://ender.no.de
-// License MIT
-// ==============
-
-process.title = "Ender"
-
-// for Node 0.7+ compatibility
-;('exists' in require('fs')) && (function () {
- require('path').exists = require('fs').exists
- require('path').existsSync = require('fs').existsSync
-}())
-
-var colors = require('colors')
- , fs = require('fs')
- , path = require('path')
- , async = require('async')
- , context = null
-
-// ENDER OBJECTS
-// =============
-
- , ENDER = { cmd: require('./ender.cmd')
- , file: require('./ender.file')
- , npm: require('./ender.npm')
- , search: require('./ender.search')
- , get: require('./ender.get')
- , util: require('./ender.util')
- , docs: require('./ender.docs')
- , closure: require('./ender.closure')
- }
-
-// ENDER'S API DEFINITION
-// ======================
-
- , API = module.exports = {
-
- search: ENDER.search
-
- , welcome: function () {
- console.log("Welcome to ENDER - The no-library library".red)
- console.log("-----------------------------------------")
- }
-
- , build: function (packages, options, callback) {
- packages = options.sans ? packages : ENDER.get.special(options).concat(packages)
- packages = ENDER.util.unique(packages)
-
- async.waterfall([
- async.apply(ENDER.npm.install, packages, options)
- , async.apply(ENDER.file.assemble, packages, options, writeSource)
- , writeSource
- ])
-
- function writeSource(err, source) {
- async.parallel([
- async.apply(ENDER.file.output, source, options.output, context, options)
- , async.apply(ENDER.file.uglify, source, options.output, context, options)
- ], callback)
- }
- }
-
- , add: function (newPackages, options, callback) {
- if (!newPackages.length) {
- return console.log('Error: you must specify a package to add.'.yellow)
- }
-
- newPackages = options.sans ? newPackages : ENDER.get.special(options).concat(newPackages)
- newPackages = ENDER.util.unique(newPackages)
-
- async.waterfall([
- async.apply(ENDER.get.buildHistory, options.use)
- , ENDER.cmd.process
- , determinePackagesToAdd
- ])
-
- function determinePackagesToAdd(type, activePackages, activeOptions) {
- options = ENDER.util.merge(activeOptions, options)
- activePackages = ENDER.util.unique(ENDER.get.special(options).concat(activePackages))
-
- async.waterfall([
- async.apply(ENDER.file.constructDependencyTree, activePackages, 'node_modules')
- , function (tree, callback) { ENDER.file.flattenDependencyTree(tree, null, callback) }
- , ENDER.file.validatePaths
- , function (activePackages, uniqueActivePackageNames) { installPackages(type, activePackages, uniqueActivePackageNames) }
- ])
- }
-
- function installPackages(type, activePackages, uniqueActivePackageNames) {
- uniqueActivePackageNames = uniqueActivePackageNames.concat(ENDER.get.special(options))
- newPackages = ENDER.util.reject(newPackages, uniqueActivePackageNames)
- newPackages = ENDER.util.unique(newPackages)
-
- if (!newPackages.length) {
- return console.log('Specified packages already installed.')
- }
-
- uniqueActivePackageNames = ENDER.util.unique(uniqueActivePackageNames.concat(newPackages))
- context = ENDER.cmd.getContext(type, uniqueActivePackageNames, options.context)
-
- async.waterfall([
- async.apply(ENDER.npm.install, newPackages, options)
- , async.apply(ENDER.file.assemble, uniqueActivePackageNames, options)
- , writeSource
- ])
-
- function writeSource(source) {
- async.parallel([
- async.apply(ENDER.file.output, source, options.output, context, options)
- , async.apply(ENDER.file.uglify, source, options.output, context, options)
- ], callback)
- }
- }
-
- }
-
- , remove: function (packagesForRemoval, options, callback) {
- if (!packagesForRemoval.length) {
- return console.log('Error: you must specify a package to remove.'.yellow)
- }
-
- packagesForRemoval = options.sans ? packagesForRemoval : ENDER.get.special(options).concat(packagesForRemoval)
-
- async.waterfall([
- async.apply(ENDER.get.buildHistory, options.use)
- , ENDER.cmd.process
- , removePackages
- ])
-
- function removePackages(type, activePackages, activeOptions) {
- options = ENDER.util.merge(activeOptions, options)
- packagesForRemoval = ENDER.npm.stripVersions(packagesForRemoval)
- activePackages = ENDER.npm.stripVersions(ENDER.util.unique(ENDER.get.special(options).concat(activePackages)))
- packagesForRemoval = ENDER.util.unique(ENDER.util.keep(packagesForRemoval, activePackages))
- packagesForRemoval = ENDER.util.reject(packagesForRemoval, ENDER.get.special(options))
-
- if (!packagesForRemoval.length) {
- console.log('Nothing to uninstall.')
- return callback && callback()
- }
-
- activePackages = ENDER.util.reject(activePackages, packagesForRemoval, true)
- context = ENDER.cmd.getContext(type, ENDER.util.unique(ENDER.cmd.normalize(activePackages), options.context))
-
- async.waterfall([
- async.apply(ENDER.npm.uninstall, packagesForRemoval)
- , async.apply(ENDER.file.assemble, activePackages, options)
- , writeSource
- ])
- }
-
- function writeSource(source) {
- async.parallel([
- async.apply(ENDER.file.output, source, options.output, context, options)
- , async.apply(ENDER.file.uglify, source, options.output, context, options)
- ], callback)
- }
- }
-
- , info: function (packages, options) {
- async.waterfall([
- async.apply(ENDER.get.buildHistory, options.use)
- , ENDER.cmd.process
- , analyzePackages
- ])
-
- function analyzePackages(type, activePackages, activeOptions) {
- options = ENDER.util.merge(activeOptions, options)
- activePackages = ENDER.util.unique(activePackages)
-
- async.series([
- async.apply(ENDER.file.prettyPrintEnderSize, type, options.use)
- , async.apply(ENDER.npm.prettyPrintDependencies, activePackages)
- ])
- }
- }
-
- , refresh: function (type, options) {
- console.log('refreshing build...')
-
- async.waterfall([
- async.apply(ENDER.get.buildHistory, options.use)
- , ENDER.cmd.process
- , refreshBuild
- ])
-
- function refreshBuild(activeType, activePackages, activeOptions) {
- options = ENDER.util.merge(activeOptions, options)
- type = typeof type == 'string' ? type : activeType
- context = ENDER.cmd.getContext(type, activePackages, options.context)
- API[type](activePackages, options);
- }
- }
-
- , help: function (type) {
- if (type.length) {
- console.log(ENDER.docs[type[0]])
- } else {
- console.log(ENDER.docs.overview)
- }
- }
-
- , version: function (args, options, callback) {
- fs.readFile(path.resolve(__dirname, '../package.json'), 'utf-8', function (err, data) {
- if (err)
- throw err
- console.log('Active Version: v' + JSON.parse(data).version)
- callback && callback()
- })
- }
-
- , compile: function (files, options) {
- var enderfile = options.use ? options.use.replace(/(\.js)?$/, '.js') : 'ender.js'
- , outfile = options.output ? options.output.replace(/(\.js)?$/, '.js')
- : enderfile.replace(/\.js$/, '-app.js')
-
- console.log('Compiling', enderfile, 'with', files.join(' '))
- console.log('This might take a minute...'.yellow)
-
- files.unshift(enderfile)
-
- async.waterfall([
- async.apply(ENDER.closure.compile, files, outfile)
- , async.apply(fs.readFile, outfile)
- , ENDER.file.gzip
- , function (data) {
- var size = (Math.round((data.length / 1024) * 10) / 10) + ' kB';
- console.log('Success! Your compiled source is', (size).cyan, 'and available at', outfile.green)
- }
- ])
- }
-
- }
-
-// ALIAS CLI WITH EXTRA METHODS
-// ============================
-
-ENDER.util.merge(API, {
- 'set': API.add
-, 'rm': API.remove
-, 'list': API.info
-, 'ls': API.info
-})
-
-// EXPOSE EXEC FOR CLI
-// ===================
-
-module.exports.exec = function (cmd, callback) {
-
- API.welcome()
-
- ENDER.cmd.process(cmd, function(err, type, args, options) {
-
- if (options.help) {
- args = [type]
- type = 'help'
- } else if (type == 'build' && !args.length) {
- args.push('.')
- }
-
- context = ENDER.cmd.getContext(type, args, options.context)
-
- if (API[type]) {
- API[type](args, options, callback)
- } else {
- console.log('sorry, but the method ' + type.yellow + ' doesn\'t exist ' + ':('.cyan)
- }
-
- });
-
-}
View
186 lib/ender.npm.js
@@ -1,186 +0,0 @@
-/*NPM METHODS*/
-var path = require('path')
- , fs = require('fs')
- , npm = require('npm')
- , async = require('async')
- , ENDER = { file: require('./ender.file') }
-
-ENDER.npm = module.exports = {
-
- prettyPrintDependencies: function (packages, callback) {
- console.log('Active packages:')
-
- ENDER.file.constructDependencyTree(packages, 'node_modules', function (err, tree) {
- ENDER.file.flattenDependencyTree(tree, null, function (err, flattenedPackages, uniquePackages) {
- ENDER.npm.recurseOverDependencies(tree, [flattenedPackages, uniquePackages])
- })
- })
- }
-
- , stripVersions: function (packages) {
- return packages.map(function (package) { return package.replace(/@.*/, '') })
- }
-
- , recurseOverDependencies: function (tree, packageTypes, pos, dep, posStack, treeStack) {
- var keys = Object.keys(tree)
- , mid = ''
- , packageName
- , packageDependencies
- , isLast
- , isTree
- , prefix
- , head
- , tail
-
- pos = pos || 0
- dep = dep || 0
- posStack = posStack || []
- treeStack = treeStack || []
- packageName = keys[pos]
- packageDependencies = tree[packageName]
- isLast = (keys.length - 1) == pos
- isTree = typeof packageDependencies == 'object'
- prefix = treeStack.map(function (tree, i) {
- return (posStack[i] == (Object.keys(tree).length - 1)) ? ' ' : '| '
- }).join('')
- head = isLast ? '' : ''
- tail = isTree ? '' : ''
-
- if (!packageName) {
- // this is here for breathing room
- return console.log(' ');
- }
-
- ENDER.npm.desc(packageName, packageTypes, function (name, desc) {
- var connector = head + mid + tail
- , msg
-
- if (!~packageDependencies) {
- msg = (prefix + connector + ' ' + name + (desc ? ' - ' + desc : '')).grey
- } else {
- msg = prefix + connector + ' ' + name.yellow + (desc ? ' - ' + desc : '')
- }
-
- if (isTree) {
- posStack.push(pos)
- treeStack.push(tree)
- dep++
- pos = 0
- tree = packageDependencies
- } else if (!isLast) {
- pos++
- } else if (treeStack.length) {
- do {
- pos = posStack.pop()
- tree = treeStack.pop()
- } while (treeStack.length && (Object.keys(tree).length - 1) == pos)
- pos++
- dep--
- } else {
- pos++
- }
- console.log(msg);
- ENDER.npm.recurseOverDependencies(tree, packageTypes, pos, dep, posStack, treeStack);
- });
- }
-
- , desc: function (package, packageTypes, callback) {
- var packagePath = path.join('node_modules', packageTypes[0][packageTypes[1].indexOf(package)].replace(/\//g, '/node_modules/'))
- , location = path.join(packagePath, 'package.json')
-
- path.exists(location, function(exists) {
- if (exists) {
- fs.readFile(location, 'utf-8', function (err, data) {
- if (err) return console.log('something went wrong trying to read file at ' + location)
- var packageJSON = JSON.parse(data)
- , name = packageJSON.name + '@' + packageJSON.version
- , desc = packageJSON.description
- callback && callback(name, desc)
- });
- } else {
- callback && callback('UNMET DEPENDENCY! '.red + package, 'Please install with ' + ('$ ender add ' + package).yellow)
- }
- });
- }
-
- , install: function (packages, options, callback) {
- ENDER.file.createDir('node_modules', function (err) {
- if (err) {
- if (options.debug) throw err
- return callback(err)
- }
- console.log('installing packages: "' + packages.join(' ') + '"...')
- console.log('this can take a minute...'.yellow)
- npm.load({ logfd: 2, outfd: 1 }, function (err) {
- if (err) {
- if (options.debug) throw err
- return console.log('something went wrong trying to load npm!'.red)
- }
- npm.commands.install(packages, function (err, data) {
- if (err) {
- if (options.debug) throw err
- return console.log('something went wrong installing your packages!'.red)
- }
-
- var localInstall = packages.some(function (item) {
- // this is a hack because of REEEIDD! DAMN YOU REEIIDD!
- // https://github.com/isaacs/npm/commit/8b7bf5ab0c214b739b5fd6af07003cac9e5fc712
- return path.resolve(item) == npm.prefix
- })
-
- if (localInstall) {
- npm.commands.install([], complete)
- } else {
- complete.apply(this, arguments)
- }
-
- function complete (err, data) {
- if (err) {
- if (options.debug) throw err
- console.log('invalid package specified... please check your spelling and try again.'.red)
- return callback && callback(err)
- }
- console.log('successfully finished installing packages')
- callback && callback()
- }
- })
- })
- })
- }
-
- , uninstall: function (packages, callback) {
- console.log('uninstalling ' + packages.join(' ').yellow)
- npm.load({ logfd: 2, outfd: 1 }, function (err) {
- if (err) {
- callback(err)
- return console.log('something went wrong trying to load npm!')
- }
- npm.commands.uninstall(packages, function (err) {
- if (err) {
- callback(err)
- return console.log('something went wrong uninstalling your packages!'.red)
- }
- callback()
- })
- })
- }
-
- , search: function (keywords, callback) {
- console.log('searching NPM registry...'.grey)
-
- npm.load({ logfd: 2, outfd: 1 }, function (err) {
- if (err) {
- callback(err)
- return console.log('something went wrong trying to load npm!')
- }
- npm.commands.search(keywords, function (err, result) {
- if (err) {
- callback(err)
- return console.log('something went wrong searching npm!'.red)
- }
- callback(result)
- });
- });
- }
-
-}
View
140 lib/ender.search.js
@@ -1,140 +0,0 @@
-var ENDER = {
- npm: require('./ender.npm')
-, search: module.exports
-}
-
-module.exports = function (terms, options) {
- ENDER.npm.search(terms, function (data) {
- var primary = []
- , secondary = []
- , secLength
- , results
- , which
- , meta
- , k
- , i
-
- for (i in data) {
- if (k = data[i].keywords) {
- which = secondary
- for (var j = k.length; j--;) {
- if (k[j] == 'ender') {
- which = primary
- break
- }
- }
- which.push(data[i])
- }
- }
-
- //white spacceee
- console.log(' ')
-
- if (!primary.length && !secondary.length) {
- return console.log('sorry, we couldn\'t find anything. :('.yellow)
- }
-
- if (primary.length) {
- console.log('Ender tagged results:'.yellow)
- console.log('---------------------')
- primary = rankRelevance(terms, primary)
- primary.forEach(function (item) {
- processItem(item, terms)
- })
- }
-
- if (secondary.length) {
- secLength = (options.max || 8) - primary.length
- if (secLength > 0) {
- secondary = rankRelevance(terms, secondary)
- meta = secondary.length > secLength ? ' (' + secLength + ' of ' + secondary.length + ')' : ''
- console.log('NPM general results:'.yellow + meta.grey)
- console.log('--------------------\n')
- secondary.slice(0, secLength).forEach(function (item) {
- processItem(item, terms)
- })
- }
- }
- })
-}
-
-function rankRelevance(args, data) {
- var sorted = []
- , priority = ['name', 'keywords', 'description']
- , args = args.map(function (arg) { return escapeRegExp(arg) })
- , regex
-
- // args as exact phrase for name
- regexp = new RegExp("^" + args.join("\\s") + "$")
- sortByRegExp(regexp, data, sorted, ["name"])
-
- // args as phrase anywhere
- regexp = new RegExp("\\b" + args.join("\\s") + "\\b", "i")
- sortByRegExp(regexp, data, sorted, priority)
-
- // args as keywords anywhere (ex: useful for case when express matches expresso)
- regexp = new RegExp("\\b" + args.join("\\b\|\\b") + "\\b", "i")
- sortByRegExp(regexp, data, sorted, priority)
-
- // we don't really care about relevance at this point :P
- return sorted.concat(data)
-}
-
-function sortByRegExp(regex, array, ranked, priority) {
- for (var i = 0; i < priority.length; i++) {
- var p = priority[i]
- for (var j = 0; j < array.length; j++) {
- if (typeof array[j][p] == 'string' && regex.test(array[j][p])) {
- ranked.push(array.splice(j, 1)[0])
- j--
- } else if (array[j][p] && typeof array[j][p] != 'string') {
- for (var m = 0; m < array[j][p].length; m++) {
- if (regex.test(array[j][p][m])) {
- ranked.push(array.splice(j, 1)[0])
- j--
- break
- }
- }
- }
- }
- }
-}
-
-function processItem(item, terms) {
- var reg = new RegExp('(' + terms.map(function (item) { return escapeRegExp(item) }).join('|') + ')', 'ig')
- , maintainers = ''
- , title = item.name
- , dots
- , last
-
- if (item.description) {
- dots = item.description.length > 80 ? '...' : ''
- title += ' - ' + item.description.substring(0, 80) + dots
- }
-
- console.log('+ ' + title.replace(reg, '$1'.cyan))
-
- if (item.maintainers && item.maintainers.length) {
- item.maintainers = item.maintainers.map(function (maintainer) {
- return maintainer.replace(/^=/, '@')
- })
-
- if (item.maintainers.length > 1) {
- last = item.maintainers.splice(-1)[0]
- maintainers = item.maintainers.join(', ')
- maintainers += ' & ' + last
- } else {
- maintainers = item.maintainers[0]
- }
-
- }
-
- console.log(' by ' + maintainers.replace(reg, '$1'.cyan) + '\n')
-}
-
-function escapeRegExp(string){
- // Credit: XRegExp 0.6.1 (c) 2007-2008 Steven Levithan <http://stevenlevithan.com/regex/xregexp/> MIT License
- return string.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, function (match) {
- return '\\' + match
- })
-}
View
65 lib/ender.util.js
@@ -1,65 +0,0 @@
-/* UTILITY METHODS */
-var version = /@.*/
-
-module.exports = {
-
- unique: function (arr) {
- var hash = {}
- , result = []
- , key
- , i
- , l
-
- for (i = 0, l = arr.length; i <l; i++) {
- key = arr[i].replace(version, '')
- hash[key] = arr[i]
- }
-
- for (i in hash) {
- if (hash.hasOwnProperty(i)) {
- result.push(hash[i])
- }
- }
-
- return result
- }
-
- , reject: function (a, b, ignoreVer) {
- var i
- if (ignoreVer) {
- return a.filter(function (item) {
- for (i = b.length; i--;) {
- if (b[i].replace(version, '') == item.replace(version, '')) {
- return false
- }
- }
- return true
- })
- } else {
- return a.filter(function (item) {
- return (b.indexOf(item) == -1)
- })
- }
- }
-
- , keep: function (a, b) {
- return a.filter(function (item) {
- return (b.indexOf(item) != -1)
- })
- }
-
- , merge: function (a, b) {
- for (var k in b) {
- a[k] = b[k]
- }
- return a
- }
-
- , containsAll: function (a, b) {
- for (var i = b.length; i--;) {
- if (a.indexOf(b[i]) == -1) return false
- }
- return true
- }
-
-}
View
41 lib/errors.js
@@ -0,0 +1,41 @@
+/*!
+ * ENDER - The open module JavaScript framework
+ *
+ * Copyright (c) 2011-2012 @ded, @fat, @rvagg and other contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+/******************************************************************************
+ * A collection of custom errors to return where we know the cause of the error
+ * and can tell the user about it. Any error that is returned that isn't an
+ * instance of EnderError has an unknown cause (the aim should be to wrap
+ * everything in an EnderError type so we can explain the errors better).
+ */
+
+var errno = require('errno')
+ , EnderError = errno.custom.createError('EnderError')
+
+module.exports.FilesystemError = errno.custom.FilesystemError
+module.exports.EnderError = EnderError
+module.exports.BuildParseError = errno.custom.createError('BuildParseError', EnderError)
+module.exports.JSONParseError = errno.custom.createError('JSONParseError', EnderError)
+module.exports.ChildProcessError = errno.custom.createError('ChildProcessError', EnderError)
+module.exports.CompressionError = errno.custom.createError('CompressionError', EnderError)
View
51 lib/main-add.js
@@ -0,0 +1,51 @@
+/*!
+ * ENDER - The open module JavaScript framework
+ *
+ * Copyright (c) 2011-2012 @ded, @fat, @rvagg and other contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+/******************************************************************************
+ * 'Add' executable module, for `ender add <packages> [--use <file>]`.
+ * This module first parses the build command in the ender.js file in CWD or
+ * the file or the file provided on the --use option.
+ * The build command from the ender.js build is then modified to add the
+ * packages specified on the commandline and is then passed to the Build
+ * module which does all the hard work.
+ */
+
+var argsParser = require('ender-args-parser')
+ , util = require('./util')
+ , parseContext = require('./parse-context')
+ , mainBuild = require('./main-build')
+
+ , exec = function (options, out, callback) {
+ var filename = util.getInputFilenameFromOptions(options)
+ ; delete options.use // don't want --use showing up in the 'Build:' context string
+ parseContext(filename, function (err, context) {
+ if (err) return callback(err) // err wrapped in SourceBuild.parseContext()
+ // merge commandline args with the build command in ender.js
+ options = argsParser.extend(context.options, options)
+ mainBuild.exec(options, out, callback)
+ })
+ }
+
+module.exports.exec = exec
View
65 lib/main-build-util.js
@@ -0,0 +1,65 @@
+/*!
+ * ENDER - The open module JavaScript framework
+ *
+ * Copyright (c) 2011-2012 @ded, @fat, @rvagg and other contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+/******************************************************************************
+ * Simple utilities for main-build
+ */
+
+var packageUtil = require('ender-repository').util
+ , DependencyGraph = require('ender-dependency-graph')
+
+ // unique packages by proper name
+var uniquePackages = function (packages) {
+ var have = []
+
+ return packages.filter(function (p) {
+ var name = packageUtil.cleanName(p)
+
+ if (have.indexOf(name) == -1) {
+ have.push(name)
+ return true
+ }
+ })
+ }
+
+ , isRootPackage = function (options, p) {
+ if (options.noop || options.sans) return false
+ return packageUtil.cleanName(p) === DependencyGraph.getClientPackageName(options)
+ }
+
+ // given a list of packages, provide a sanitised list without duplicates and with
+ // the root package at the start.
+ , packageList = function (options) {
+ var packages = options.packages && options.packages.length ? options.packages : [ '.' ]
+
+ if (!options.noop && !options.sans) packages = [ DependencyGraph.getClientPackageName(options) ].concat(packages)
+ return uniquePackages(packages)
+ }
+
+module.exports = {
+ packageList : packageList
+ , uniquePackages : uniquePackages
+ , isRootPackage : isRootPackage
+}
View
76 lib/main-build.js
@@ -0,0 +1,76 @@
+/*!
+ * ENDER - The open module JavaScript framework
+ *
+ * Copyright (c) 2011-2012 @ded, @fat, @rvagg and other contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+/******************************************************************************
+ * 'Build' executable module, for `ender build <packages> [...]`.
+ * This module should serve to control the build process with the details.
+ * Most of the hard work in figuring out what to put together is done in the
+ * main-build-util module, the SourceBuild and SourcePackage objects then do
+ * the assembling work while the write module outputs the results.
+ */
+
+var builder = require('ender-builder')
+ , install = require('ender-installer')
+ , mainInfo = require('./main-info')
+ , buildUtil = require('./main-build-util')
+
+ , handle = function (options, packages, out, installedPackages, dependencyGraph, callback) {
+ if (out && installedPackages) out.installedFromRepository(installedPackages.length)
+ builder(options, packages, dependencyGraph, function (err, outputFilename) {
+ if (err) return callback(err) // wrapped in write.js
+
+ out.finishedAssembly()
+
+ // delegate to main-info to print details about the build, we can prime it with
+ // the tree and options so it doesn't have to do that work itself
+ if (!options.quiet) {
+ mainInfo.generateAndPrint(
+ options
+ , out
+ , outputFilename
+ , options
+ , dependencyGraph.localizePackageList(packages)
+ , dependencyGraph
+ , callback
+ )
+ }
+ })
+ }
+
+ , exec = function (options, out, callback) {
+ var packages = buildUtil.packageList(options)
+
+ out.buildInit(packages)
+
+ // install takes care of collecting and organising dependencies for us and simply returns
+ // a DependencyTree object that we can use to assemble a build
+ install(options, packages, function (err, installedPackages, dependencyGraph) {
+ if (err) return callback(err) // wrapped in repository.js
+
+ handle(options, packages, out, installedPackages, dependencyGraph, callback)
+ })
+ }
+
+module.exports.exec = exec
View
113 lib/main-compile.js
@@ -0,0 +1,113 @@
+/*!
+ * ENDER - The open module JavaScript framework
+ *
+ * Copyright (c) 2011-2012 @ded, @fat, @rvagg and other contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is furnished
+ * to do so, subject to the following conditions:
+ *