[Pkg-javascript-commits] [node-browserify-lite] 01/03: Imported Upstream version 0.0.1

Andrew Kelley andrewrk-guest at moszumanska.debian.org
Fri Oct 3 19:04:00 UTC 2014


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

andrewrk-guest pushed a commit to branch master
in repository node-browserify-lite.

commit 01c7d52e5a4d885682ccedbe68ff88ecb6d1354a
Author: Andrew Kelley <superjoe30 at gmail.com>
Date:   Fri Oct 3 18:43:01 2014 +0000

    Imported Upstream version 0.0.1
---
 .gitignore   |   1 +
 LICENSE      |  23 +++++
 README.md    |  11 +++
 cli.js       |  22 +++++
 index.js     | 312 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 package.json |  24 +++++
 test.js      |  79 +++++++++++++++
 7 files changed, 472 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..07e6e47
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/node_modules
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..0bbb53e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,23 @@
+The MIT License (Expat)
+
+Copyright (c) 2014 Andrew Kelley
+
+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.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3a44701
--- /dev/null
+++ b/README.md
@@ -0,0 +1,11 @@
+# browserify-lite
+
+browserify, minus some of the advanced features and heavy dependencies.
+
+ * No builtin Node.js shims.
+ * Naive AST tokenization for require instead of true AST parsing.
+   - Require statements must be outside all braces. This includes functions,
+     control statements, and objects.
+ * Only supports a single entry file and the `--outfile` parameter,
+   nothing else.
+ * Minimal dependencies.
diff --git a/cli.js b/cli.js
new file mode 100755
index 0000000..14fc7d8
--- /dev/null
+++ b/cli.js
@@ -0,0 +1,22 @@
+#!/usr/bin/node
+
+var fs = require('fs');
+var browserifyLite = require('./');
+
+var entrySourcePath = process.argv[2];
+var outputFileParam = process.argv[3];
+var outBundlePath = process.argv[4];
+
+if (outputFileParam !== '--outfile') {
+  console.error("Expected second param to be --outfile");
+  process.exit(1);
+}
+
+if (!outBundlePath || !entrySourcePath) {
+  console.error("Expected first arg to be source path and third arg to be out bundle path.");
+  process.exit(1);
+}
+
+browserifyLite.createBundle(entrySourcePath, outBundlePath, function(err) {
+  if (err) throw err;
+});
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..211097b
--- /dev/null
+++ b/index.js
@@ -0,0 +1,312 @@
+var fs = require('fs');
+var path = require('path');
+var Pend = require('pend');
+
+exports.extractRequires = extractRequires;
+exports.createBundle = createBundle;
+
+function createBundle(entrySourcePath, outBundlePath, cb) {
+  // data structure that is filled up with canonical source path as the key,
+  // source code as the value.
+  var sources = {};
+
+  // describes the dependency graph. key is canonical source path, value is
+  // array of canonical source path dependencies
+  var deps = {};
+
+  // each file has its own map of how require statements resolve.
+  var depMap = {};
+
+  var sourceQueue = [];
+
+  requireResolve(entrySourcePath, process.cwd(), function(err, resolvedPath) {
+    if (err) return cb(err);
+    sourceQueue.push(resolvedPath);
+    collectDependencies(function(err) {
+      if (err) return cb(err);
+      render(resolvedPath, function(err, output) {
+        if (err) return cb(err);
+        fs.writeFile(outBundlePath, output, cb);
+      });
+    });
+  });
+
+  function collectDependencies(cb) {
+    var canonicalSourcePath = sourceQueue.shift();
+    if (!canonicalSourcePath) return cb();
+    if (sources[canonicalSourcePath]) return collectDependencies(cb);
+
+    fs.readFile(canonicalSourcePath, {encoding: 'utf8'}, function(err, source) {
+      if (err) return cb(err);
+      sources[canonicalSourcePath] = source;
+      deps[canonicalSourcePath] = {};
+      depMap[canonicalSourcePath] = {};
+
+      var pend = new Pend();
+      extractRequires(source, function(err, requireList) {
+        if (err) return cb(err);
+        requireList.forEach(function(requireItem) {
+          pend.go(function(cb) {
+            requireResolve(requireItem, path.dirname(canonicalSourcePath), function(err, canonicalDepPath) {
+              if (err) return cb(err);
+              deps[canonicalSourcePath][canonicalDepPath] = true;
+              depMap[canonicalSourcePath][requireItem] = canonicalDepPath;
+              sourceQueue.push(canonicalDepPath);
+              cb();
+            });
+          });
+        });
+        pend.wait(function(err) {
+          if (err) return cb(err);
+          collectDependencies(cb);
+        });
+      });
+
+    });
+  }
+
+  function render(entrySourcePath, cb) {
+    var modules = Object.keys(sources);
+    var aliases = {};
+    modules.forEach(function(canonicalSourcePath, index) {
+      aliases[canonicalSourcePath] = index;
+    });
+    modules.forEach(function(canonicalSourcePath, index) {
+      var thisDepMap = depMap[canonicalSourcePath]
+      for (var depSourcePath in thisDepMap) {
+        thisDepMap[depSourcePath] = aliases[thisDepMap[depSourcePath]];
+      }
+    });
+
+    var out =
+      "(function(modules, cache, entry) {\n" +
+      "  req(entry);\n" +
+      "  function req(name) {\n" +
+      "    if (cache[name]) return cache[name].exports;\n" +
+      "    var m = cache[name] = {exports: {}};\n" +
+      "    modules[name][0].call(m.exports, modRequire, m, m.exports);\n" +
+      "    return m.exports;\n" +
+      "    function modRequire(alias) {\n" +
+      "      var id = modules[name][1][alias];\n" +
+      "      if (!id) throw new Error(\"Cannot find module \" + alias);\n" +
+      "      return req(id);\n" +
+      "    }\n" +
+      "  }\n" +
+      "})({";
+
+    modules.forEach(function(canonicalSourcePath) {
+      out += aliases[canonicalSourcePath] + ": [function(require,module,exports){\n";
+      out += sources[canonicalSourcePath];
+      out += "\n}, " + JSON.stringify(depMap[canonicalSourcePath]) + "],";
+    });
+
+    out += "}, {}, " + aliases[entrySourcePath] + ");\n";
+
+    cb(null, out);
+  }
+}
+
+
+function tokenizeSource(source) {
+  var tokens = [];
+  var inQuote = false;
+  var braceCount = 0;
+  var quoteType;
+  var qEscape = false;
+  var token = "";
+  var inLineComment = false;
+  var inMultiLineComment = false;
+  var startComment = false;
+  var endComment = false;
+  for (var i = 0; i < source.length; i += 1) {
+    var c = source[i];
+    if (inQuote) {
+      if (qEscape) {
+        token += c;
+        qEscape = false;
+      } else if (c === "\\") {
+        qEscape = true;
+      } else if (c === quoteType) {
+        inQuote = false;
+        if (braceCount === 0) {
+          tokens.push(token);
+        }
+        token = "";
+      } else {
+        token += c;
+      }
+    } else if (inLineComment) {
+      if (c === "\n") {
+        inLineComment = false;
+      }
+    } else if (inMultiLineComment) {
+      if (c === '*') {
+        endComment = true;
+      } else if (c === '/') {
+        if (endComment) {
+          inMultiLineComment = false;
+          endComment = false;
+        }
+      } else {
+        endComment = false;
+      }
+    } else if (c === "\"" || c === "'") {
+      startComment = false;
+      if (token) tokens.push(token);
+      token = "";
+      inQuote = true;
+      quoteType = c;
+      qEscape = false;
+    } else if (c === '{') {
+      startComment = false;
+      if (token) tokens.push(token);
+      token = "";
+      braceCount += 1;
+    } else if (c === '}') {
+      startComment = false;
+      braceCount -= 1;
+    } else if (c === '/') {
+      if (startComment) {
+        if (token) tokens.push(token);
+        token = "";
+        inLineComment = true;
+        startComment = false;
+      } else {
+        startComment = true;
+      }
+    } else if (c === '*' && startComment) {
+      if (token) tokens.push(token);
+      token = "";
+      inMultiLineComment = true;
+      startComment = false;
+    } else if (braceCount === 0) {
+      if (/\W/.test(c)) {
+        if (token) tokens.push(token);
+        token = "";
+      }
+      if (/\S/.test(c)) {
+        token += c;
+      }
+    } else {
+      startComment = false;
+    }
+  }
+  if (token) tokens.push(token);
+  return tokens;
+}
+
+var stateCount = 0;
+var STATE_WANT_REQUIRE = stateCount++;
+var STATE_WANT_LPAREN = stateCount++;
+var STATE_WANT_STR = stateCount++;
+var STATE_WANT_RPAREN = stateCount++;
+function extractRequires(source, cb) {
+  var tokens = tokenizeSource(source);
+
+  var requiresList = [];
+  var state = STATE_WANT_REQUIRE;
+  var requireName;
+
+  for (var i = 0; i < tokens.length; i += 1) {
+    var token = tokens[i];
+    if (state === STATE_WANT_REQUIRE && token === 'require') {
+      state = STATE_WANT_LPAREN;
+    } else if (state === STATE_WANT_LPAREN && token === '(') {
+      state = STATE_WANT_STR;
+    } else if (state === STATE_WANT_STR) {
+      requireName = token;
+      state = STATE_WANT_RPAREN;
+    } else if (state === STATE_WANT_RPAREN && token === ')') {
+      state = STATE_WANT_REQUIRE;
+      requiresList.push(requireName);
+    }
+  }
+  cb(null, requiresList);
+}
+
+function requireResolve(pkg, basedir, cb) {
+  if (/^[.\/]/.test(pkg)) {
+    requireResolvePath(path.resolve(basedir, pkg), cb);
+  } else {
+    requireResolveModule(pkg, basedir, cb);
+  }
+}
+
+function requireResolveModule(pkg, basedir, cb) {
+  var globalSearchPaths = process.env.NODE_PATH ? process.env.NODE_PATH.split(path.delimiter) : [];
+
+  var localSearchPaths = [];
+  var parts = basedir.split(path.sep);
+  var it = "/";
+  for (var i = 0; i < parts.length; i += 1) {
+    it = path.join(it, parts[i]);
+    localSearchPaths.unshift(path.join(it, "node_modules"));
+  }
+
+  var searchPaths = localSearchPaths.concat(globalSearchPaths);
+  var index = 0;
+
+  trySearchPath();
+
+  function trySearchPath() {
+    var searchPath = searchPaths[index];
+    if (!searchPath) return cb(new Error("module not found"));
+
+    requireResolvePath(path.resolve(searchPath, pkg), function(err, resolvedFilename) {
+      if (!err) return cb(null, resolvedFilename);
+      index += 1;
+      trySearchPath();
+    });
+  }
+}
+
+function requireResolvePath(filename, cb) {
+  resolveFile(filename, function(err, resolvedFilename) {
+    if (!err) return cb(null, resolvedFilename);
+    resolveFile(filename + '.js', function(err, resolvedFilename) {
+      if (!err) return cb(null, resolvedFilename);
+      resolveFile(filename + '.json', function(err, resolvedFilename) {
+        if (!err) return cb(null, resolvedFilename);
+        resolveDirectory(filename, cb);
+      });
+    });
+  });
+}
+
+function resolveFile(filename, cb) {
+  fs.stat(filename, function(err, stat) {
+    if (err) return cb(err);
+    if (stat.isDirectory()) return cb(new Error("directory"));
+    cb(null, filename);
+  });
+}
+
+function resolveDirectory(dirname, cb) {
+  var packageJsonPath = path.resolve(dirname, "package.json");
+  fs.readFile(packageJsonPath, {encoding: 'utf8'}, function(err, packageJsonStr) {
+    var packageJson;
+    try {
+      packageJson = JSON.parse(packageJsonStr);
+    } catch (err) {
+      cb(err);
+      return;
+    }
+    var filename;
+    if (packageJson.main) {
+      filename = path.resolve(dirname, packageJson.main);
+      resolveFile(filename, tryIndex);
+    } else {
+      tryIndex(new Error("no main found in package.json"));
+    }
+
+    function tryIndex(err) {
+      if (!err) return cb(null, filename);
+      filename = path.resolve(dirname, "index.js");
+      resolveFile(filename, function(err) {
+        if (!err) return cb(null, filename);
+        filename = path.resolve(dirname, "index.json");
+        resolveFile(filename, cb);
+      });
+    }
+  });
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..896c789
--- /dev/null
+++ b/package.json
@@ -0,0 +1,24 @@
+{
+  "name": "browserify-lite",
+  "version": "0.0.1",
+  "description": "browserify, minus some of the advanced features and heavy dependencies.",
+  "main": "index.js",
+  "scripts": {
+    "test": "node test.js"
+  },
+  "bin": {
+    "browserify-lite": "./cli.js"
+  },
+  "author": "Andrew Kelley <superjoe30 at gmail.com>",
+  "license": "MIT",
+  "dependencies": {
+    "pend": "~1.1.3"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/andrewrk/browserify-lite.git"
+  },
+  "bugs": {
+    "url": "https://github.com/andrewrk/browserify-lite/issues"
+  }
+}
diff --git a/test.js b/test.js
new file mode 100644
index 0000000..a791fbb
--- /dev/null
+++ b/test.js
@@ -0,0 +1,79 @@
+var assert = require('assert');
+var browserifyLite = require('./');
+
+var extractRequiresTests = [
+  {
+    name: "basic",
+    source: "require('./code')",
+    output: [
+      "./code"
+    ],
+  },
+  {
+    name: "multiple",
+    source:
+"var EventEmitter = require('./event_emitter');\n" +
+"var inherits = require('./inherits');\n" +
+"var uuid = require('./uuid');\n" +
+"var MusicLibraryIndex = require('music-library-index');\n" +
+"var keese = require(\"keese\");\n" +
+"var curlydiff = require('curlydiff');\n",
+    output: [
+      "./event_emitter",
+      "./inherits",
+      "./uuid",
+      "music-library-index",
+      "keese",
+      "curlydiff",
+    ],
+  },
+  {
+    name: "trick",
+    source: "require('./code');\nvar a = \"require('foo');\";\nrequire(\"../morecode\");",
+    output: [
+      "./code",
+      "../morecode",
+    ],
+  },
+  {
+    name: "unescape",
+    source: "require('./code');\nvar a = \"require(\\\"foo\\\");\";\nrequire(\"../morecode\");",
+    output: [
+      "./code",
+      "../morecode",
+    ],
+  },
+  {
+    name: "spaces",
+    source: "var foo = require ( 'derp ' ) ;\n",
+    output: [
+      "derp ",
+    ],
+  },
+  {
+    name: "ignore braces",
+    source: "var foo = require('derp'); { require('ignore-this'); } require('this-ok')\n",
+    output: [
+      "derp",
+      "this-ok",
+    ],
+  },
+  {
+    name: "ignore comments",
+    source: "/* var foo = require('derp');*/ { require('ignore-this'); } require('this-ok') // require('also-ignore-this'); \n require('this-also-ok')",
+    output: [
+      "this-ok",
+      "this-also-ok",
+    ],
+  },
+];
+
+process.stderr.write("extract requires tests:\n");
+extractRequiresTests.forEach(function(extractRequiresTest) {
+  process.stderr.write(extractRequiresTest.name + "...");
+  browserifyLite.extractRequires(extractRequiresTest.source, function(err, requiresList) {
+    if (err) throw err;
+    assert.deepEqual(extractRequiresTest.output, requiresList);
+    process.stderr.write("OK\n");
+  });
+});

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



More information about the Pkg-javascript-commits mailing list