[Pkg-javascript-commits] [node-dryice] 01/01: Imported Upstream version 0.4.10

Leo Iannacone l3on-guest at moszumanska.debian.org
Wed Apr 30 10:15:00 UTC 2014


This is an automated email from the git hooks/post-receive script.

l3on-guest pushed a commit to branch master
in repository node-dryice.

commit 66f7c2632e8b7b1c585ae1962c572aa03c8f471e
Author: Leo Iannacone <l3on at ubuntu.com>
Date:   Wed Apr 30 11:59:05 2014 +0200

    Imported Upstream version 0.4.10
---
 LICENSE                    |  202 ++++++++
 README.md                  |  346 +++++++++++++
 lib/dryice/index.js        | 1149 ++++++++++++++++++++++++++++++++++++++++++++
 lib/dryice/mini_require.js |  190 ++++++++
 package.json               |   23 +
 5 files changed, 1910 insertions(+)

diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..6074b6c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,346 @@
+DryIce
+======
+
+DryIce is a CommonJS/RequireJS packaging tool for browser scripts.
+
+It is basically just a copy function. It takes input from a set of input files,
+which can be specified in various ways, optionally filters them and outputs them
+to something else.
+
+DryIce is licensed under the Apache License version 2
+
+
+Why?
+----
+
+RequireJS has a build tool which is nice and works well, but it requires Rhino
+and therefore Java. With DryIce, your whole build process can be in JavaScript.
+
+DryIce produces a single file output that can include binary files (by base64
+encoding them)
+
+
+How to install DryIce
+---------------------
+
+    sudo npm install dryice
+
+
+How does it work?
+-----------------
+
+To copy a single file:
+
+    copy({
+      source: 'foo.txt',
+      dest: 'bar.txt'
+    });
+
+To cat a bunch of files together:
+
+    copy({
+      source: [ 'file1.js', 'file2.js' ],
+      dest: 'output.js'
+    });
+
+To cat together all the files in a directory:
+
+    copy({
+      source: { root:'src' },
+      dest: 'built.js'
+    });
+
+As above, but only use the JavaScript files:
+
+    copy({
+      source: { root:'src', include:/.*\.js$/ },
+      dest: 'built.js'
+    });
+
+As above, but exclude tests:
+
+    copy({
+      source: { root:'src', include:/.*\.js$/: exclude:/test/ },
+      dest: 'built.js'
+    });
+
+If your set of files is very custom:
+
+    copy({
+      source: function() {
+        var files = [ 'file1.js' ];
+        if (baz) files.push('file2.js');
+        return files;
+      },
+      dest: 'built.js'
+    });
+
+We can filter the files on the way:
+
+    copy({
+      source: /src/.*\.js$/,
+      filter: copy.filter.uglifyjs,
+      dest: 'built.js'
+    });
+
+This includes running multiple custom filters:
+
+    copy({
+      source: 'src/index.html',
+      filter: [
+        function(data) {
+          return data.replace(/Sun/, 'Oracle');
+        },
+        htmlCompressor
+      ],
+      dest: 'war/index.html'
+    });
+
+Results can be stored and then used/reused:
+
+    var sources = copy.createDataObject();
+    copy({
+      source: { root: 'src1' },
+      dest: sources
+    });
+    copy({
+      source: { root: 'src2' },
+      dest: sources
+    });
+    copy({
+      source: sources,
+      dest: 'sources-uncompressed.js'
+    });
+    copy({
+      source: sources,
+      filter: copy.filter.uglifyjs,
+      dest: 'sources.js'
+    });
+
+Data objects are just JS objects with a 'value' member, so you can do all sorts
+of things with them:
+
+    var test = copy.createDataObject();
+    copy({
+      source: 'README.txt',
+      dest: test
+    });
+    console.log(test.value);
+
+Or:
+
+    copy({
+      source: { value: 'Hello, World!' },
+      dest: 'basic.txt'
+    });
+
+And you can mix and match your inputs:
+
+    copy({
+      source: [
+        'somefile.txt',
+        thingDataObject,
+        { root: 'src', include: /.*\.js$/ },
+        function() { return 'wibble.sh'; }
+      ],
+      dest: 'mess.bin'
+    });
+
+Common JS project dependency tracking:
+
+    var project = copy.createCommonJsProject({
+        roots: [
+            '/path/to/source/tree/lib',
+            '/some/other/project/lib'
+        ]
+    });
+    copy({
+        source: copy.source.commonjs({
+            project: project,
+            require: [ 'main', 'plugin/main' ]
+        }),
+        dest: ''
+    });
+
+This digs around in the project source trees specified in the project for
+modules named in the 'require' statement. When it finds them it looks through
+them for require statements, and finds those, and so on.
+
+
+Formal Parameter Description
+----------------------------
+
+The copy function takes a single parameter which is an object with 2 or 3
+members: `source`, `dest` and optionally `filter`.
+
+### source
+
+There are 6 ways to specify the input source(s)
+
+* A *string* is expected to point to a filename.
+  At some stage we may allow them to point at directories too, however this
+  can be achieved today using a find object (see below)
+
+* A *find object* points to a directory with 2 optional RegExps specifying what
+  to exclude and include. e.g.
+
+    { root: '/' }                       -> The entire filesystem
+    { root: 'src', include: /.*\.js$/ } -> All the JavaScript files in 'src'
+    { root: 'src', exclude: /test/ }    -> All non-test files under 'src'
+
+* A *data object* - something with a 'value' property.
+  The implementation of `copy.createDataObject()` is simply
+  `return { value: '' };`. We've batted around some ideas which involve making
+  `copy.createDataObject()` smarter than it currently is, so it is advised to
+  use this method rather than doing it yourself.
+
+* A *based object*. A based object is one with `base` and `path` members. They
+  are roughly the same as the string baseObj.base + baseObj.path. Based objects
+  are important when using CommonJS filters, because it tells the filter where
+  the root of the hierarchy is, which lets us know the module name.
+  For example:
+
+    { base: '/etc', path:PATH } where BASE+PATH = filename
+
+* An *array* containing input source entries. The array does not have to be
+  homogeneous.
+
+* A *function* which returns any input source entries.
+
+### filter
+
+The filter member is optional. If it exists, it should contain either a function
+or an array of functions. The function should have the following signature:
+
+    function filter(value, location) {
+      ..
+      return 'some string';
+    }
+
+Where the parameters are as follows:
+
+* value. Either a string or a node Buffer. Most filters will work only with
+  strings, so they should begin:
+
+      if (typeof value !== 'string') {
+          value = value.toString();
+      }
+
+  Some filters will only work with Buffers (for example the base64 encoding
+  filter) so they should begin:
+
+      if (typeof value === 'string') {
+          throw new Error('base64 filter needs to be the first in a filter set');
+      }
+
+  At some stage we may allow filters to be marked up as to their requirements.
+
+* location. This will be (where possible) a based object or it could be a
+  string if a based object is not available. It will be common to use one of the
+  following idioms to work on a filename:
+
+      if (location.base) {
+          location = location.path;
+      }
+
+  or
+
+      if (location.base) {
+          location = location.base + location.path;
+      }
+
+There are 2 points in a copy run where filters could be used, either before the
+individual sources are concatenated, or after. Some filters should be used in
+before (like common-js munging filters) and some afterwards (like compressors).
+
+The default is to run filters after concatenation (when the location parameter
+will be undefined). To run filters before concatenation, the filter should be
+marked with `onRead = true`. For example:
+
+    function makeBlank(value, location) {
+      return '';
+    }
+    makeBlank.onRead = true;
+
+DryIce currently comes with 4 filters:
+
+* _copy.filter.uglifyjs_: Calls uglify on the input.
+* _copy.filter.addDefines_: Wraps the input to inline files fetched using
+  RequireJSs text import feature.
+* _copy.filter.base64_: Similar to addDefines, but assumes the input is
+  binary and should be base64 encoded.
+* _copy.filter.moduleDefines_: Replaces define lines to include the module name
+  e.g. `define(function(export, require, module) { ... });` is turned into
+  `define('module/name', function(export, require, module) { ... });`
+
+
+### dest
+
+The dest property should be either a filename to which the output should be
+written (existing files will be over-written without warning), or a data object
+to which the data should be appended.
+
+CommonJS Projects
+-----------------
+
+CommonJS projects take a single object with the following properties:
+
+* `roots`: This is required. An array of directories that should be searched for
+  your required modules and dependencies.
+
+* `ignores`: This is optional. An array of modules or dependencies that are
+  required by your project that you would not like to be included in the
+  build. For example, if you were making a build which did not need to support
+  IE, you could do something like the following
+
+        copy.createCommonJsProject({
+            roots: [ '/path/to/project' ],
+            ignores: [ 'dom/ie-compat', 'event/ie-compat' ]
+        });
+
+  then wherever you had `require('dom/ie-compat')` or
+  `require('event/ie-compat')` inside your build, `undefined` would be returned
+  by `require`.
+
+Where (is the project going)?
+-----------------------------
+
+DryIce is useful in combining scripts for the browser, but it could also be
+used in a similar role on the server, we just need to enable 'pass through
+requires'.
+
+There are some tweaks we'd still like to make to enable more filters and
+multiple destinations:
+
+To recursively copy a directory:
+
+    copy({ source: 'foo', destDir: 'bar' });
+
+To rename files as we copy them:
+
+    copy({
+      source: { root:'src', include:/.*\.png$/ },
+      destDir: { root:'built', replace:/png$/, with:'png.bak' }
+    });
+
+To create a tarball (this is only missing the targz filter):
+
+    var version = copy.createDataObject();
+    copy({ source: 'VERSION.txt', dest: version });
+    copy({
+      source: { root:'.' },
+      filter: [ targz ],
+      dest: 'scp://example.com/upload/myproject-' + version + '.tar.gz'
+    });
+
+I don't suppose you would ever actually want to do this, but in theory you
+could even do this:
+
+    copy({
+      source: { root:'src', include:/.*\.java$/ },
+      filter: javac,
+      destDir: { root:'classes', replace:/java$/, with:'class' }
+    });
+
+(Actually there would be issues with ordering that would make this hard, and
+Ant/Maven/etc is probably better. This is an illustration dammit!)
diff --git a/lib/dryice/index.js b/lib/dryice/index.js
new file mode 100644
index 0000000..b391558
--- /dev/null
+++ b/lib/dryice/index.js
@@ -0,0 +1,1149 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var fs = require("fs");
+var path = require("path");
+var ujs = require("uglify-js");
+
+if (!fs.existsSync) {
+  fs.existsSync = path.existsSync;
+}
+
+/**
+ * See https://github.com/mozilla/dryice for usage instructions.
+ */
+function copy(obj) {
+  var filters = copy.filterFactory(obj.filter);
+  var source = copy.sourceFactory(obj.source, filters);
+  var dest = copy.destFactory(obj.dest, filters);
+  dest.processSource(source);
+}
+
+/**
+ * A Location is a base and a path which together point to a file or directory.
+ * It's useful to be able to know in copy operations relative to some project
+ * root to be able to remember where in a destination the file should go
+ */
+function Location(base, somePath) {
+  if (base == null) {
+    throw new Error('base == null');
+  }
+  this.base = base;
+  this.path = somePath;
+}
+
+Location.prototype.isLocation = true;
+
+Object.defineProperty(Location.prototype, 'fullname', {
+  get: function() {
+    return path.join(this.base, this.path);
+  }
+});
+
+Object.defineProperty(Location.prototype, 'dirname', {
+  get: function() {
+    return path.dirname(this.fullname);
+  }
+});
+
+/**
+ * Select the correct implementation of Source for the given source property
+ */
+copy.sourceFactory = function(source, filters) {
+  if (source == null) {
+    throw new Error('Missing source');
+  }
+
+  if (source.isSource) {
+    return source;
+  }
+
+  if (typeof source === 'string') {
+    if (copy.isDirectory(source)) {
+      return new copy.DirectorySource(source, null, null, filters);
+    }
+    else {
+      return new copy.FileSource(new Location('', source), filters);
+    }
+  }
+
+  if (Array.isArray(source)) {
+    return new copy.ArraySource(source, filters);
+  }
+
+  if (typeof source === 'function') {
+    return new copy.FunctionSource(source, filters);
+  }
+
+  if (source.root != null) {
+    if (source.require != null) {
+      var project = new CommonJsProject([ source.root ]);
+      return new copy.CommonJsSource(project, source.require, filters);
+    }
+
+    return new copy.DirectorySource(source.root, source.include, source.exclude, filters);
+  }
+
+  if (source.base != null && source.path != null) {
+    return new copy.FileSource(new Location(source.base, source.path), filters);
+  }
+
+  if (typeof source.value === 'string') {
+    return new copy.ValueSource(source.value, null, filters);
+  }
+
+  if (source.project != null && source.require != null) {
+    return new copy.CommonJsSource(source.project, source.require, filters);
+  }
+
+  throw new Error('Can\'t handle type of source: ' + typeof source);
+};
+
+copy.debug = false;
+
+/**
+ * Abstract Source.
+ * Concrete implementations of Source should define the 'get' property.
+ */
+copy.Source = function() {
+};
+
+/**
+ * @return Either another source, an array of other sources or a string value
+ * when there is nothing else to dig into
+ */
+Object.defineProperty(copy.Source.prototype, 'get', {
+  get: function() {
+    throw new Error('Source.get is not implemented');
+  }
+});
+
+copy.Source.prototype.isSource = true;
+
+copy.Source.prototype._runFilters = function(value, location) {
+  this._filters.forEach(function(filter) {
+    if (filter.onRead) {
+      value = filter(value, location);
+    }
+  }, this);
+  return value;
+};
+
+/**
+ * Default encoding for all sources
+ */
+copy.Source.prototype.encoding = 'utf8';
+
+/**
+ * An ArraySource is simply an array containing things that can resolve to
+ * implementations of Source when passed to copy.sourceFactory()
+ */
+copy.ArraySource = function(array, filters) {
+  copy.Source.call(this);
+  this._array = array;
+  this._filters = filters;
+};
+
+copy.ArraySource.prototype = Object.create(copy.Source.prototype);
+
+Object.defineProperty(copy.ArraySource.prototype, 'get', {
+  get: function() {
+    return this._array.map(function(member) {
+      return copy.sourceFactory(member, this._filters);
+    }, this);
+  }
+});
+
+/**
+ * A FunctionSource is something that can be called to resolve to another
+ * Source implementation
+ */
+copy.FunctionSource = function(func, filters) {
+  copy.Source.call(this);
+  this._func = func;
+  this._filters = filters;
+};
+
+copy.FunctionSource.prototype = Object.create(copy.Source.prototype);
+
+Object.defineProperty(copy.FunctionSource.prototype, 'get', {
+  get: function() {
+    return copy.sourceFactory(this._func(), this._filters);
+  }
+});
+
+/**
+ * A Source that finds files under a given directory with specified include /
+ * exclude patterns.
+ * @param root The root in the filesystem under which the files exist
+ * @param filterOrInclude
+ */
+copy.DirectorySource = function(root, filterOrInclude, exclude, filters) {
+  copy.Source.call(this);
+  this._filters = filters;
+
+  this.root = root;
+  if (this.root instanceof CommonJsProject) {
+    this.root = this.root.roots;
+  }
+
+  if (Array.isArray(this.root)) {
+    this.root.map(function(r) {
+      return ensureTrailingSlash(r);
+    });
+  }
+
+  if (typeof filterOrInclude === 'function') {
+    this._searchFilter = filterOrInclude;
+  }
+  else {
+    this._searchFilter = this._createFilter(filterOrInclude, exclude);
+  }
+};
+
+copy.DirectorySource.prototype = Object.create(copy.Source.prototype);
+
+Object.defineProperty(copy.DirectorySource.prototype, 'get', {
+  get: function() {
+    return this._findMatches(this.root, '/');
+  }
+});
+
+copy.DirectorySource.prototype._findMatches = function(root, path) {
+  var sources = [];
+
+  if (Array.isArray(root)) {
+    root.forEach(function(r) {
+      var matches = this._findMatches(r, path);
+      sources.push.apply(sources, matches);
+    }, this);
+    return sources;
+  }
+
+  root = ensureTrailingSlash(root);
+  path = ensureTrailingSlash(path);
+
+  if (copy.isDirectory(root + path)) {
+    fs.readdirSync(root + path).forEach(function(entry) {
+      var stat = fs.statSync(root + path + entry);
+      if (stat.isFile()) {
+        if (this._searchFilter(path + entry)) {
+          var location = new Location(root, path + entry);
+          sources.push(new copy.FileSource(location, this._filters));
+        }
+      }
+      else if (stat.isDirectory()) {
+        var matches = this._findMatches(root, path + entry);
+        sources.push.apply(sources, matches);
+      }
+    }, this);
+  }
+
+  return sources;
+};
+
+copy.DirectorySource.prototype._createFilter = function(include, exclude) {
+  return function(pathname) {
+    function noPathMatch(pattern) {
+      return !pattern.test(pathname);
+    }
+    if (include instanceof RegExp) {
+      if (noPathMatch(include)) {
+        return false;
+      }
+    }
+    if (typeof include === 'string') {
+      if (noPathMatch(new RegExp(include))) {
+        return false;
+      }
+    }
+    if (Array.isArray(include)) {
+      if (include.every(noPathMatch)) {
+        return false;
+      }
+    }
+
+    function pathMatch(pattern) {
+      return pattern.test(pathname);
+    }
+    if (exclude instanceof RegExp) {
+      if (pathMatch(exclude)) {
+        return false;
+      }
+    }
+    if (typeof exclude === 'string') {
+      if (pathMatch(new RegExp(exclude))) {
+        return false;
+      }
+    }
+    if (Array.isArray(exclude)) {
+      if (exclude.some(pathMatch)) {
+        return false;
+      }
+    }
+
+    return true;
+  };
+};
+
+/**
+ * A FileSource gets data directly from a file. It has 2 parts to the filename,
+ * a base and path members, where filename = base + path.
+ * FileSources are important when using CommonJS filters, because it tells the
+ * filter where the root of the hierarchy is, which lets us know the module
+ * name.
+ * If there is no base to the filename, use a base of ''.
+ */
+copy.FileSource = function(location, filters) {
+  copy.Source.call(this);
+  this.location = location;
+  this.name = location.fullname;
+  this._filters = filters;
+};
+
+copy.FileSource.prototype = Object.create(copy.Source.prototype);
+
+Object.defineProperty(copy.FileSource.prototype, 'get', {
+  get: function() {
+    var read = fs.readFileSync(this.name);
+    return this._runFilters(read, this.location);
+  }
+});
+
+/**
+ *
+ */
+copy.ValueSource = function(value, location, filters) {
+  copy.Source.call(this);
+  this._value = value;
+  this._location = location;
+  this._filters = filters;
+};
+
+copy.ValueSource.prototype = Object.create(copy.Source.prototype);
+
+Object.defineProperty(copy.ValueSource.prototype, 'get', {
+  get: function() {
+    return this._runFilters(this._value, this._location);
+  }
+});
+
+/**
+ * Read modules from a CommonJS Project using a require property.
+ */
+copy.CommonJsSource = function(project, require, filters) {
+  copy.Source.call(this);
+  this._project = project;
+  this._filters = filters;
+
+  if (!project instanceof CommonJsProject) {
+    throw new Error('commonjs project should be a CommonJsProject');
+  }
+
+  if (typeof require === 'string') {
+    this._require = [ require ];
+  }
+  else if (Array.isArray(require)) {
+    this._require = require;
+  }
+  else {
+    throw new Error('Expected commonjs args to have string/array require.');
+  }
+};
+
+copy.CommonJsSource.prototype = Object.create(copy.Source.prototype);
+
+Object.defineProperty(copy.CommonJsSource.prototype, 'get', {
+  get: function() {
+    this._require.forEach(function(moduleName) {
+      this._project.require(moduleName);
+    }, this);
+    return this._project.getCurrentModules().map(function(location) {
+      return new copy.FileSource(location, this._filters);
+    }.bind(this));
+  }
+});
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+copy.filterFactory = function(filter) {
+  if (filter == null) {
+    return [];
+  }
+
+  if (typeof filter === 'function') {
+    return [ filter ];
+  }
+
+  if (Array.isArray(filter)) {
+    return filter;
+  }
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Select the correct implementation of Destination for the given dest property
+ */
+copy.destFactory = function(dest, filters) {
+  if (dest == null) {
+    throw new Error('Missing dest');
+  }
+
+  if (dest.isDestination) {
+    return dest;
+  }
+
+  if (dest.value != null) {
+    return new copy.ValueDestination(dest, filters);
+  }
+
+  if (typeof dest === 'string') {
+    if (copy.isDirectory(dest)) {
+      return new copy.DirectoryDestination(dest, filters);
+    }
+    else {
+      return new copy.FileDestination(dest, filters);
+    }
+  }
+
+  if (Array.isArray(dest)) {
+    return new copy.ArrayDestination(dest, filters);
+  }
+
+  throw new Error('Can\'t handle type of dest: ' + typeof dest);
+};
+
+/**
+ * Abstract Destination.
+ * Concrete implementations of Destination should define the 'processSource'
+ * function.
+ */
+copy.Destination = function() {
+};
+
+copy.Destination.prototype.isDestination = true;
+
+/**
+ * @return Either another dest, an array of other sources or a string value
+ * when there is nothing else to dig into
+ */
+copy.Destination.prototype.processSource = function(source) {
+  throw new Error('Destination.processSource() is not implemented');
+};
+
+/**
+ * Helper function to convert an input source to a single string value
+ */
+copy.Destination.prototype._sourceToOutput = function(source) {
+  var data = source.get;
+
+  if (data.isSource) {
+    return this._sourceToOutput(data);
+  }
+
+  if (Array.isArray(data)) {
+    var value = '';
+    data.forEach(function(s) {
+      value += this._sourceToOutput(s);
+    }, this);
+    return value;
+  }
+
+  if (typeof data === 'string') {
+    return data;
+  }
+
+  // i.e. a Node Buffer
+  if (typeof data.toString === 'function') {
+    return data.toString();
+  }
+
+  throw new Error('Unexpected value from source.get');
+};
+
+copy.Destination.prototype._runFilters = function(value) {
+  this._filters.forEach(function(filter) {
+    if (!filter.onRead) {
+      value = filter(value);
+    }
+  }, this);
+  return value;
+};
+
+/**
+ * A Destination that concatenates the sources and writes them to a single
+ * output file.
+ */
+copy.FileDestination = function(filename, filters) {
+  this._filename = filename;
+  this._filters = filters;
+};
+
+copy.FileDestination.prototype = Object.create(copy.Destination.prototype);
+
+copy.FileDestination.prototype.processSource = function(source) {
+  var data = this._sourceToOutput(source);
+  data = this._runFilters(data);
+  copy._writeToFile(this._filename, data);
+};
+
+/**
+ * A Destination that copies the sources to new files in an alternate directory
+ * structure.
+ */
+copy.DirectoryDestination = function(dirname, filters) {
+  this.name = dirname;
+  this._filters = filters;
+};
+
+copy.DirectoryDestination.prototype = Object.create(copy.Destination.prototype);
+
+copy.DirectoryDestination.prototype.processSource = function(source) {
+  var data = source.get;
+  if (typeof data === 'string') {
+    throw new Error('Can\'t write raw data to a directory');
+  }
+  else if (data.isSource) {
+    var destfile = path.join(this.name, data.location.path);
+    var output = this._runFilters(data.get);
+    copy._writeToFile(destfile, output, data.encoding);
+  }
+  else if (Array.isArray(data)) {
+    data.forEach(function(s) {
+      var destfile = path.join(this.name, s.location.path);
+      var output = this._runFilters(s.get);
+      copy._writeToFile(destfile, output, s.encoding);
+    }, this);
+  }
+  else {
+    throw new Error('data is not a source, string, nor can it be converted');
+  }
+};
+
+/**
+ * ArrayDestination is a Destination that can feed sources to a number of child
+ * Destinations.
+ */
+copy.ArrayDestination = function(array, filters) {
+  this._array = array;
+  this._filters = filters;
+};
+
+copy.ArrayDestination.prototype = Object.create(copy.Destination.prototype);
+
+copy.ArrayDestination.prototype.processSource = function(source) {
+  this._array.forEach(function(member) {
+    var dest = copy.destFactory(member, this._filters);
+    dest.processSource(source);
+  }, this);
+};
+
+/**
+ * A Destination that concatenates the sources and writes them to a single
+ * value object.
+ */
+copy.ValueDestination = function(value, filters) {
+  this._value = value;
+  this._filters = filters;
+};
+
+copy.ValueDestination.prototype = Object.create(copy.Destination.prototype);
+
+copy.ValueDestination.prototype.processSource = function(source) {
+  var data = this._sourceToOutput(source);
+  data = this._runFilters(data);
+  this._value.value += data;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Check to see if fullPath refers to a directory
+ */
+copy.isDirectory = function(fullPath) {
+  return fs.existsSync(fullPath) && fs.statSync(fullPath).isDirectory();
+};
+
+copy._writeToFile = function(filename, data, encoding) {
+  if (fs.existsSync(filename)) {
+    if (!fs.statSync(filename).isFile()) {
+      throw new Error('Refusing to remove non file: ' + filename);
+    }
+    fs.unlinkSync(filename);
+  }
+  var parent = path.dirname(filename);
+  if (!fs.existsSync(parent)) {
+    copy.mkdirSync(parent, 0755);
+  }
+  fs.writeFileSync(filename, data, encoding);
+  if (copy.debug) {
+    console.log('- wrote ' + data.length + ' bytes to ' + filename);
+  }
+};
+
+copy.mkdirSync = function(dirname, mode) {
+  if (copy.isDirectory(dirname)) {
+    return;
+  }
+  var parent = path.dirname(dirname);
+  if (!fs.existsSync(parent)) {
+    copy.mkdirSync(parent, mode);
+  }
+  if (!fs.existsSync(dirname)) {
+    fs.mkdirSync(dirname, mode);
+  }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * A holder is an in-memory store of a result of a copy operation.
+ * <pre>
+ * var holder = copy.createDataObject();
+ * copy({ source: 'x.txt', dest: holder });
+ * copy({ source: 'y.txt', dest: holder });
+ * copy({ source: holder, dest: 'z.txt' });
+ * </pre>
+ */
+copy.createDataObject = function() {
+  return { value: '' };
+};
+
+/**
+ * Read mini_require.js to go with the required modules.
+ */
+copy.getMiniRequire = function() {
+  return {
+    value: fs.readFileSync(__dirname + '/mini_require.js').toString('utf8')
+  };
+};
+
+/**
+ * Keep track of the files in a project
+ */
+function CommonJsProject(opts) {
+  this.roots = opts.roots;
+  this.aliases = opts.aliases;
+  this.textPluginPattern = opts.textPluginPattern || /^text!/;
+
+  opts.roots = this.roots.map(function(root) {
+    if (!copy.isDirectory(root)) {
+      throw new Error('Each commonjs root should be a directory: ' + root);
+    }
+    return ensureTrailingSlash(root);
+  }, this);
+
+  // A module is a Location that also has dep
+  this.currentModules = {};
+  this.ignoredModules = {};
+}
+
+CommonJsProject.prototype.report = function() {
+  var reply = 'CommonJS project at ' + this.roots.join(', ') + '\n';
+
+  reply += '- Required modules:\n';
+  var moduleNames = Object.keys(this.currentModules);
+  if (moduleNames.length > 0) {
+    moduleNames.forEach(function(module) {
+      var deps = Object.keys(this.currentModules[module].deps).length;
+      reply += '  - ' + module + ' (' + deps +
+          (deps === 1 ? ' dependency' : ' dependencies') + ')\n';
+    }, this);
+  }
+  else {
+    reply += '  - None\n';
+  }
+
+  reply += '- Ignored modules:\n';
+  var ignoredNames = Object.keys(this.ignoredModules);
+  if (ignoredNames.length > 0) {
+    ignoredNames.forEach(function(moduleName) {
+      reply += '  - ' + moduleName + '\n';
+    }, this);
+  }
+  else {
+    reply += '  - None\n';
+  }
+
+  return reply;
+};
+
+/**
+ * Create an experimental GraphML string declaring the node dependencies.
+ */
+CommonJsProject.prototype.getDependencyGraphML = function() {
+  var nodes = '';
+  var edges = '';
+  var moduleNames = Object.keys(this.currentModules);
+  moduleNames.forEach(function(moduleName) {
+    nodes += '    <node id="' + moduleName + '">\n';
+    nodes += '      <data key="d0">\n';
+    nodes += '        <y:ShapeNode>\n';
+    nodes += '           <y:NodeLabel textColor="#000000">' + moduleName + '</y:NodeLabel>\n';
+    nodes += '        </y:ShapeNode>\n';
+    nodes += '      </data>\n';
+    nodes += '    </node>\n';
+    var deps = Object.keys(this.currentModules[moduleName].deps);
+    deps.forEach(function(dep) {
+        edges += '    <edge source="' + moduleName + '" target="' + dep + '"/>\n';
+    });
+  }, this);
+
+  var reply = '<?xml version="1.0" encoding="UTF-8"?>\n';
+  reply += '<graphml\n';
+  reply += '    xmlns="http://graphml.graphdrawing.org/xmlns/graphml"\n';
+  reply += '    xmlns:y="http://www.yworks.com/xml/graphml"\n';
+  reply += '    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n';
+  reply += '    xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns/graphml http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd"\n';
+  reply += '    >\n';
+  reply += '  <key id="d0" for="node" yfiles.type="nodegraphics"/>\n';
+  reply += '  <key id="d1" for="edge" yfiles.type="edgegraphics"/>\n';
+  reply += '  <graph id="commonjs" edgedefault="undirected">\n';
+  reply += nodes;
+  reply += edges;
+  reply += '  </graph>\n';
+  reply += '</graphml>\n';
+  return reply;
+};
+
+CommonJsProject.prototype.assumeAllFilesLoaded = function() {
+  Object.keys(this.currentModules).forEach(function(moduleName) {
+    this.ignoredModules[moduleName] = this.currentModules[moduleName];
+  }, this);
+  this.currentModules = {};
+};
+
+CommonJsProject.prototype.clone = function() {
+  var clone = new CommonJsProject({
+    roots: this.roots,
+    textPluginPattern: this.textPluginPattern
+  });
+
+  clone.aliases = this.aliases;
+
+  Object.keys(this.currentModules).forEach(function(moduleName) {
+    clone.currentModules[moduleName] = this.currentModules[moduleName];
+  }, this);
+
+  Object.keys(this.ignoredModules).forEach(function(moduleName) {
+    clone.ignoredModules[moduleName] = this.ignoredModules[moduleName];
+  }, this);
+
+  return clone;
+};
+
+CommonJsProject.prototype.addRoot = function(root) {
+  this.roots.push(root);
+};
+
+function findModuleAt(module, base, somePath) {
+  if (base == null) {
+    throw new Error('base == null for ' + somePath);
+  }
+  // Checking for absolute requires and relative requires that previously
+  // had been resolved to absolute paths.
+  if (/^\//.test(somePath)) {
+    if (isFile(somePath)) {
+      console.log('Warning - using location with base = "/"');
+      return new Location('/', somePath);
+    }
+  }
+
+  if (isFile(path.join(base, somePath))) {
+    if (module) {
+      console.log('- Found several matches for ' + somePath +
+          ' (ignoring 2nd)');
+      console.log('  - ' + module.fullname);
+      console.log('  - ' + path.join(base, somePath));
+    }
+    else {
+      module = new Location(base, somePath);
+    }
+  }
+
+  return module;
+}
+
+function relative(pathA, pathB) {
+  pathA = pathA.split(/[\/\\]+/);
+  pathB = pathB.split(/[\/\\]+/);
+  var aLen = pathA.length;
+  var bLen = pathB.length;
+
+  // Increment i to the first place where the paths diverge.
+  for (var i = 0; i < aLen && i < bLen && pathA[i] === pathB[i]; i++) {
+  }
+
+  // Remove the redundant parts of the paths.
+  function isntEmptyString(s) {
+    return s !== '';
+  }
+  pathA = pathA.slice(i).filter(isntEmptyString);
+  pathB = pathB.slice(i).filter(isntEmptyString);
+
+  var result = [];
+  for (i = 0; i < pathA.length; i++) {
+    result.push('..');
+  }
+  return result.concat(pathB).join('/');
+}
+
+function normalizeRequire(module, moduleName) {
+  if (moduleName.indexOf("!") !== -1) {
+    var chunks = moduleName.split("!");
+    return normalizeRequire(module, chunks[0]) + "!" +
+        normalizeRequire(module, chunks[1]);
+  }
+
+  if (moduleName.charAt(0) == ".") {
+    var requirersDirectory = module.dirname;
+    var pathToRequiredModule = path.join(requirersDirectory, moduleName);
+    // The call to `define` which makes the module being
+    // relatively required isn't the full relative path,
+    // but the path relative from the base.
+    return relative(module.base, pathToRequiredModule);
+  }
+  else {
+    return moduleName;
+  }
+}
+
+function findRequires(module) {
+  var code = fs.readFileSync(module.fullname).toString();
+  var ast;
+  try {
+    ast = ujs.parser.parse(code, false);
+  }
+  catch (ex) {
+    console.error('- Failed to compile ' + module.path + ': ' + ex);
+    return;
+  }
+
+  var reply = [];
+  var walkers = {
+    call: function(expr, args) {
+      // If anyone redefines 'require' we won't notice. We could maintain a
+      // list of declared variables in the current scope so we can detect this.
+      // A similar system could have us tracking calls to require via a
+      // different name. that was a useful escape system, but now we detect
+      // computed requires, it's not needed.
+      if (expr[1] === 'define') {
+        var params = null;
+        if (args[0][0] === 'array') {
+          params = args[0][1];
+        }
+        else if (args[0][0] === 'string' && args[1][0] == 'array') {
+          params = args[1][1];
+        }
+        else {
+          console.log('- ' + module.path + ' has define(...) ' +
+              'with non-array parameter. Ignoring requirement.');
+          return;
+        }
+
+        if (params) {
+          for (var i = 0; i < params.length; i++) {
+            param = params[i];
+            if (param[0] === 'string') {
+              reply.push(normalizeRequire(module, param[1]));
+            }
+            else {
+              console.log('- ' + module.path + ' has define(...) ' +
+                  'with non-string parameter. Ignoring requirement.');
+            }
+          }
+        }
+      }
+      if (expr[1] === 'require') {
+        if (args[0][0] === 'string') {
+          reply.push(normalizeRequire(module, args[0][1]));
+        }
+        else {
+          console.log('- ' + module.path + ' has require(...) ' +
+              'with non-string parameter. Ignoring requirement.');
+        }
+      }
+    }
+  };
+
+  var walker = ujs.uglify.ast_walker();
+  walker.with_walkers(walkers, function() {
+    return walker.walk(ast);
+  });
+
+  return reply;
+}
+
+CommonJsProject.prototype.require = function(moduleName) {
+  var module = this.currentModules[moduleName];
+  if (module) {
+    return module;
+  }
+  module = this.ignoredModules[moduleName];
+  if (module) {
+    return module;
+  }
+
+  // Apply aliases on module path.
+  if (this.aliases) {
+    var parts = moduleName.split("/");
+    var moduleName = parts.pop();
+
+    var self = this;
+    var resolved = parts.map(function(part) {
+    var alias = self.aliases[part];
+      return alias ? alias : part;
+    });
+
+    var moduleUrl = ensureTrailingSlash(resolved.join("/"));
+    moduleName = moduleUrl + moduleName;
+  }
+
+  // Find which of the packages it is in
+  this.roots.forEach(function(base) {
+    if (this.textPluginPattern.test(moduleName)) {
+      var modulePath = moduleName.replace(this.textPluginPattern, '');
+      module = findModuleAt(module, base, modulePath);
+      if (module) {
+        module.isText = true;
+      }
+    } else {
+      module = findModuleAt(module, base, moduleName + '.js');
+      if (!module) {
+        module = findModuleAt(module, base, moduleName + '/index.js');
+      }
+    }
+  }, this);
+
+  if (!module) {
+    console.error('Failed to find module: ' + moduleName);
+    return;
+  }
+
+  module.deps = {};
+  this.currentModules[moduleName] = module;
+
+  if (!module.isText) {
+    // require() all this modules requirements
+    findRequires(module).forEach(function(moduleName) {
+      module.deps[moduleName] = 1;
+      this.require(moduleName);
+    }, this);
+  }
+};
+
+CommonJsProject.prototype.getCurrentModules = function() {
+  return Object.keys(this.currentModules).map(function(moduleName) {
+    return this.currentModules[moduleName];
+  }, this);
+};
+
+/**
+ *
+ */
+copy.createCommonJsProject = function(opts) {
+  return new CommonJsProject(opts);
+};
+
+/**
+ * Different types of source
+ */
+copy.source = {};
+
+/**
+ * @deprecated
+ */
+copy.source.commonjs = function(obj) {
+  console.log('copy.source.commonjs is deprecated, ' +
+      'pass { project:... includes:...} directly as a source');
+  return obj;
+};
+
+/**
+ * File filters
+ */
+copy.filter = {};
+
+copy.filter.debug = function(input, source) {
+  source = source || 'unknown';
+  module = source.path ? source.path : source;
+  return input;
+};
+copy.filter.debug.onRead = true;
+
+/**
+ * Compress the given input code using UglifyJS.
+ *
+ * @param string input
+ * @return string output
+ */
+copy.filter.uglifyjs = function(input) {
+  if (typeof input !== 'string') {
+    input = input.toString();
+  }
+
+  var opt = copy.filter.uglifyjs.options;
+  var ast;
+  try {
+    ast = ujs.parser.parse(input, opt.parse_strict_semicolons);
+  }
+  catch (ex) {
+    console.error('- Failed to compile code: ' + ex);
+    return input;
+  }
+
+  if (opt.mangle) {
+    ast = ujs.uglify.ast_mangle(ast, opt.mangle_toplevel);
+  }
+
+  if (opt.squeeze) {
+    ast = ujs.uglify.ast_squeeze(ast, opt.squeeze_options);
+    if (opt.squeeze_more) {
+      ast = ujs.uglify.ast_squeeze_more(ast);
+    }
+  }
+
+  return ujs.uglify.gen_code(ast, opt.beautify);
+};
+copy.filter.uglifyjs.onRead = false;
+/**
+ * UglifyJS filter options.
+ */
+copy.filter.uglifyjs.options = {
+  parse_strict_semicolons: false,
+
+  /**
+   * The beautify argument used for process.gen_code(). See the UglifyJS
+   * documentation.
+   */
+  beautify: false,
+  mangle: true,
+  mangle_toplevel: false,
+  squeeze: true,
+
+  /**
+   * The options argument used for process.ast_squeeze(). See the UglifyJS
+   * documentation.
+   */
+  squeeze_options: {},
+
+  /**
+   * Tells if you want to perform potentially unsafe compression.
+   */
+  squeeze_more: false
+};
+
+/**
+ * A filter to munge CommonJS headers
+ */
+copy.filter.addDefines = function(input, source) {
+  if (typeof input !== 'string') {
+    input = input.toString();
+  }
+
+  if (!source) {
+    throw new Error('Missing filename for moduleDefines');
+  }
+
+  var module = source.isLocation ? source.path : source;
+
+  input = input.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
+  input = '"' + input.replace(/\n/g, '\\n" +\n  "') + '"';
+
+  return 'define("text!' + module + '", [], ' + input + ');\n\n';
+};
+copy.filter.addDefines.onRead = true;
+
+/**
+ * Like addDefines, but adds base64 encoding
+ */
+copy.filter.base64 = function(input, source) {
+  if (typeof input === 'string') {
+    throw new Error('base64 filter needs to be the first in a filter set');
+  }
+
+  if (!source) {
+    throw new Error('Missing filename for moduleDefines');
+  }
+
+  var module = source.isLocation ? source.path : source;
+
+  if (module.substr(-4) === '.png') {
+    input = 'data:image/png;base64,' + input.toString('base64');
+  }
+  else if (module.substr(-4) === '.gif') {
+    input = 'data:image/gif;base64,' + input.toString('base64');
+  }
+  else {
+    throw new Error('Only gif/png supported by base64 filter: ' + source);
+  }
+
+  return 'define("text!' + module + '", [], "' + input + '");\n\n';
+};
+copy.filter.base64.onRead = true;
+
+/**
+ * Munge define lines to add module names
+ */
+copy.filter.moduleDefines = function(input, source) {
+  if (!source) {
+    console.log('- Source without filename passed to moduleDefines().' +
+        ' Skipping addition of define(...) wrapper.');
+    return input;
+  }
+
+  if (source.isText) {
+    return copy.filter.addDefines(input, source);
+  }
+
+  if (typeof input !== 'string') {
+    input = input.toString();
+  }
+
+  var deps = source.deps ? Object.keys(source.deps) : [];
+  deps = deps.length ? (", '" + deps.join("', '") + "'") : "";
+
+  var module = source.isLocation ? source.path : source;
+  module = module.replace(/\.js$/, '');
+
+  return input.replace(/\bdefine\s*\(\s*function\s*\(require,\s*exports,\s*module\)\s*\{/,
+      "define('" + module + "', ['require', 'exports', 'module' " + deps + "], function(require, exports, module) {");
+};
+copy.filter.moduleDefines.onRead = true;
+
+/**
+ * Why does node throw an exception for statSync(), especially when it has no
+ * exists()?
+ */
+function isFile(fullPath) {
+  return fs.existsSync(fullPath) && fs.statSync(fullPath).isFile();
+}
+
+/**
+ * Add a trailing slash to s directory path if needed
+ */
+function ensureTrailingSlash(filename) {
+  if (filename.length > 0 && filename.substr(-1) !== '/') {
+    filename += '/';
+  }
+  return filename;
+}
+
+
+exports.copy = copy;
diff --git a/lib/dryice/mini_require.js b/lib/dryice/mini_require.js
new file mode 100644
index 0000000..82b1fd4
--- /dev/null
+++ b/lib/dryice/mini_require.js
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2012, Mozilla Foundation and contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Define a module along with a payload.
+ * @param moduleName Name for the payload
+ * @param deps Ignored. For compatibility with CommonJS AMD Spec
+ * @param payload Function with (require, exports, module) params
+ */
+function define(moduleName, deps, payload) {
+  if (typeof moduleName != "string") {
+    throw new Error("Error: Module name is not a string");
+  }
+
+  if (arguments.length == 2) {
+    payload = deps;
+  }
+  else {
+    payload.deps = deps;
+  }
+
+  if (define.debugDependencies) {
+    console.log("define: " + moduleName + " -> " + payload.toString()
+        .slice(0, 40).replace(/\n/, '\\n').replace(/\r/, '\\r') + "...");
+  }
+
+  if (moduleName in define.modules) {
+    throw new Error("Error: Redefining module: " + moduleName);
+  }
+
+  // Mark the payload so we know we need to call it to get the real module
+  payload.__uncompiled = true;
+  define.modules[moduleName] = payload;
+}
+
+/**
+ * The global store of un-instantiated modules
+ */
+define.modules = {};
+
+/**
+ * Should we console.log on module definition/instantiation/requirement?
+ */
+define.debugDependencies = false;
+
+
+(function() {
+
+/**
+ * We invoke require() in the context of a Domain so we can have multiple
+ * sets of modules running separate from each other.
+ * This contrasts with JSMs which are singletons, Domains allows us to
+ * optionally load a CommonJS module twice with separate data each time.
+ * Perhaps you want 2 command lines with a different set of commands in each,
+ * for example.
+ */
+function Domain() {
+  this.modules = {};
+
+  if (define.debugDependencies) {
+    this.depth = "";
+  }
+}
+
+/**
+ * Lookup module names and resolve them by calling the definition function if
+ * needed.
+ * There are 2 ways to call this, either with an array of dependencies and a
+ * callback to call when the dependencies are found (which can happen
+ * asynchronously in an in-page context) or with a single string an no
+ * callback where the dependency is resolved synchronously and returned.
+ * The API is designed to be compatible with the CommonJS AMD spec and
+ * RequireJS.
+ * @param deps A name, or array of names for the payload
+ * @param callback Function to call when the dependencies are resolved
+ * @return The module required or undefined for array/callback method
+ */
+Domain.prototype.require = function(config, deps, callback) {
+  if (arguments.length <= 2) {
+    callback = deps;
+    deps = config;
+    config = undefined;
+  }
+
+  if (Array.isArray(deps)) {
+    var params = deps.map(function(dep) {
+      return this.lookup(dep);
+    }, this);
+    if (callback) {
+      callback.apply(null, params);
+    }
+    return undefined;
+  }
+  else {
+    return this.lookup(deps);
+  }
+};
+
+/**
+ * Lookup module names and resolve them by calling the definition function if
+ * needed.
+ * @param moduleName A name for the payload to lookup
+ * @return The module specified by aModuleName or null if not found
+ */
+Domain.prototype.lookup = function(moduleName) {
+  if (moduleName in this.modules) {
+    var module = this.modules[moduleName];
+    if (define.debugDependencies) {
+      console.log(this.depth + " Using module: " + moduleName);
+    }
+    return module;
+  }
+
+  if (!(moduleName in define.modules)) {
+    throw new Error("Missing module: " + moduleName);
+  }
+
+  var module = define.modules[moduleName];
+
+  if (define.debugDependencies) {
+    console.log(this.depth + " Compiling module: " + moduleName);
+  }
+
+  if (module.__uncompiled) {
+    if (define.debugDependencies) {
+      this.depth += ".";
+    }
+
+    var exports = {};
+    try {
+      var params = module.deps.map(function(dep) {
+        if (dep === "require") {
+          return this.require.bind(this);
+        }
+        if (dep === "exports") {
+          return exports;
+        }
+        if (dep === "module") {
+          return { id: moduleName, uri: "" };
+        }
+        return this.lookup(dep);
+      }.bind(this));
+
+      var reply = module.apply(null, params);
+      module = (reply !== undefined) ? reply : exports;
+    }
+    catch (ex) {
+      console.error("Error using module: " + moduleName, ex);
+      throw ex;
+    }
+
+    if (define.debugDependencies) {
+      this.depth = this.depth.slice(0, -1);
+    }
+  }
+
+  // cache the resulting module object for next time
+  this.modules[moduleName] = module;
+
+  return module;
+};
+
+/**
+ * Expose the Domain constructor and a global domain (on the define function
+ * to avoid exporting more than we need. This is a common pattern with
+ * require systems)
+ */
+define.Domain = Domain;
+define.globalDomain = new Domain();
+
+})();
+
+/**
+ * Expose a default require function which is the require of the global
+ * sandbox to make it easy to use.
+ */
+var require = define.globalDomain.require.bind(define.globalDomain);
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..03512d6
--- /dev/null
+++ b/package.json
@@ -0,0 +1,23 @@
+{
+  "name": "dryice",
+  "description": "A CommonJS/RequireJS packaging tool for browser scripts",
+  "keywords": [ "build", "commonjs", "requirejs" ],
+  "version": "0.4.10",
+  "homepage": "https://github.com/joewalker/dryice",
+  "author": "Joe Walker <joe at getahead.org>",
+  "contributors": [ ],
+  "repository": {
+    "type": "git",
+    "url": "http://github.com/mozilla/dryice.git"
+  },
+  "bugs": { "url": "http://github.com/mozilla/dryice/issues" },
+  "directories": { "lib" : "./lib" },
+  "main": "./lib/dryice/index.js",
+  "engines": { "node" : ">=0.6.0" },
+  "licenses": [
+    { "type": "Apache-2.0", "url": "http://www.apache.org/licenses/LICENSE-2.0" }
+  ],
+  "dependencies": {
+    "uglify-js": "~1.3.4"
+  }
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-dryice.git



More information about the Pkg-javascript-commits mailing list