[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