<commit_before>'use strict';
var Ractive = require('ractive');
var htmlExtReg = /\.html$/i;
var path = require('path');
var fs = require('fs');
var env = process.env.NODE_ENV || 'development';
var glob = require('glob');
var unary = require('fn-unary');
var errto = require('errto');
var async = require('async');
var rewrite = require('rev-rewriter');
var assign = require('lodash-node/modern/objects/assign');

exports.getPartials = getPartials;
exports.cRevPost = cRevPost;
exports.rewriteComponentSource = rewriteComponentSource;

function cRevPost(component) {
    component = component || '';
    return function (assetFilePath) {
        var prefix = component ? {
            '.js': '/js/',
            '.css': '/css/'
        }[path.extname(assetFilePath)] || '/img/' : '/assets/';
        return component + prefix + assetFilePath;
    };
}

function rewriteComponentSource(filePath, source) {
    var index, component;
    if ((index = filePath.indexOf('/ccc/')) > -1) {
        component = filePath.match(/\/ccc\/[^\/]+/)[0];
        source = rewrite({
            assetPathPrefix: '/js/',
            revPost: cRevPost(component)
        }, source);
        source = rewrite({
            assetPathPrefix: '/css/',
            revPost: cRevPost(component)
        }, source);
        source = rewrite({
            assetPathPrefix: '/img/',
            revPost: cRevPost(component)
        }, source);
        return source;
    }
    return source;
}

function getPartials(appRoot, files, cb) { //TODO: production 优化，cache
    var partialsRoot = path.join(appRoot, 'partials');
    if (typeof files === 'function') {
        cb = files;
        files = null;
    }

    var gotFiles = errto(cb, function (files) {
        async.reduce(files, {}, function (partials, filename, next) {
            var filePath = path.join(partialsRoot, filename);
            fs.readFile(filePath, 'utf-8', errto(next, function (
                content) {
                partials[filename.replace(htmlExtReg, '')
                    .replace(/\/+/g, '.')] =
                    rewriteComponentSource(filePath,
                        content);
                next(null, partials);
            }));
        }, cb);
    });

    if (files) {
        gotFiles(null, files);
    } else {
        fs.exists(partialsRoot, function (exists) {
            if (!exists) {
                cb(null, {});
            } else {
                glob('**/*.html', {
                    cwd: partialsRoot
                }, gotFiles);
            }

        });
    }

}

function replaceLibJs(html, options) {
    var settings = options.settings;
    var appRoot = (settings || {})
        .appRoot;

    if (appRoot && settings.assetsDirName) {
        var libs = [];
        try {
            libs = JSON.parse(fs.readFileSync(path.join(appRoot,
                settings.assetsDirName,
                'js',
                'lib.json'), 'utf-8'));
        } catch (err) {
            if (err.code !== 'ENOENT') {
                throw err;
            }
        }
        libs = libs.map(function (lib) {
            return path.resolve(path.join(appRoot,
                'assets', 'js'), lib)
                .substring(appRoot.length);
        });
        var libJsReplaced;
        html = html.replace(
            /(<script\s+src=["']?)\/assets\/js\/lib.js(["']?><\/script>)/g,
            function (all, p1, p2) {
                if (libJsReplaced) {
                    return "";
                } else {
                    libJsReplaced = true;
                    return p1 + libs.join(p2 + p1) +
                        p2;
                }
            });
    }
    return html;
}
exports.engine = function (filePath, options, fn) {
    fs.readFile(filePath, 'utf-8', errto(fn, function (template) {
        template = rewrite({
            revPost: cRevPost('')
        }, template);
        template = rewriteComponentSource(filePath, template);
        var partials = options.partials;
        var match = filePath.match(/\/ccc\/[^\/]+\/views\//);
        if (match) {
            var componentsRoot = (filePath.substring(0, match.index) +
                match[0])
                .replace(/\/views\/$/, '');
            if (componentsRoot !== options.settings.subAppRoot) {
                getPartials(componentsRoot, errto(fn, function (
                    conponentsPartials) {
                    assign(partials, conponentsPartials);
                    render();
                }));
            } else {
                render();
            }
        } else {
            render();
        }

        function render() {
            var html = new Ractive({
                partials: partials,
                template: template, //TODO: production 优化，cache
                data: options
            })
                .toHTML();
            fn(null, replaceLibJs(html, options));
        }
    }));
};

function getReqPath(req) {
    return req.path.replace(/^\/|\/$/g, '');
}

exports.middleware = function () {
    return function (req, res, next) {
        var reqPath = getReqPath(req);
        if (res.viewPath) {
            reqPath = res.viewPath;
        }
        if (reqPath[0] === '/') {
            reqPath = reqPath.substring(1);
        }
        var ext = path.extname(reqPath);
        if (ext && ext !== '.html') {
            return next();
        }
        return res.render(reqPath);
    };
};

exports.argmentApp = function (app, opts) {
    app.set('view engine', 'html');
    app.engine('html', exports.engine);
    app.set('appRoot', opts.appRoot);
    app.set('assetsDirName', opts.assetsDirName);
    app.set('views', [].concat(app.get('views'))
        .concat(glob.sync('ccc/*/views/', {
                cwd: opts.appRoot
            })
            .map(unary(path.join.bind(path, opts.appRoot))))
        .filter(Boolean));
    app.use(function (req, res, next) {
        var _render = res.render;
        // 让 res.viewPath 支持 express-promise
        res.render = function (name, options, fn) {
            var res = this;
            var app = res.app;
            if (!name) {
                name = getReqPath(this.req);
            }
            if ('function' === typeof options) {
                fn = options;
                options = {};
            }
            options = options || {};
            var appLocals = {};
            if (app.locals.__proto__) { // support sub-app, but not sub-sub-app
                assign(appLocals, app.locals.__proto__);
            }
            assign(appLocals, app.locals);

            var opts = assign({}, appLocals, res.locals, options);
            var view;
            var cache = app.cache;
            // set .cache unless explicitly provided
            opts.cache = opts.cache ? app.enabled('view cache') :
                opts.cache;

            view = (opts.cache && cache[name]) || new(app.get('view'))(name, {
                defaultEngine: app.get('view engine'),
                root: app.get('views'),
                engines: app.engines
            });

            // default callback to respond
            fn = fn || function (err, str) {
                if (err) {
                    return res.req.next(err);
                }
                res[res.headersSent ? 'end' : 'send'](str);
            };

            if (!view.path) {
                return res.req.next();
            }

            var rushHeads = [].concat(app.locals.rushHeads)
                .concat(res.locals.rushHeads)
                .concat(options.rushHeads)
                .filter(Boolean);

            if (rushHeads.length) {
                res.statusCode = 200;
                res.set('Content-Type', 'text/html; charset=utf-8');

                res.write(rushHeads.join(''));
            }

            var partials;
            getPartials(app.set('appRoot'), errto(fn, function (
                appPartials) {
                if (res.app.set('subAppRoot')) {
                    getPartials(res.app.set('subAppRoot'),
                        errto(
                            fn, function (subAppPartials) {
                                partials = assign(appPartials,
                                    subAppPartials);
                                render();
                            }));
                } else {
                    partials = appPartials;
                    render();
                }
            }));

            function render() {
                if (res.locals.partials) {
                    assign(partials, res.locals.partials);
                }
                if (options.partials) {
                    assign(partials, options.partials);
                }
                opts.partials = partials;
                res.locals = {};
                _render.call(res, view.path, opts, fn);
            }

        };
        next();
    });
    if (opts.appendMiddleware !== false) {
        app.use(exports.middleware());
    }
};<commit_msg>fix rushHeads with sub-apps<commit_after>'use strict';
var Ractive = require('ractive');
var htmlExtReg = /\.html$/i;
var path = require('path');
var fs = require('fs');
var env = process.env.NODE_ENV || 'development';
var glob = require('glob');
var unary = require('fn-unary');
var errto = require('errto');
var async = require('async');
var rewrite = require('rev-rewriter');
var assign = require('lodash-node/modern/objects/assign');

exports.getPartials = getPartials;
exports.cRevPost = cRevPost;
exports.rewriteComponentSource = rewriteComponentSource;

function cRevPost(component) {
    component = component || '';
    return function (assetFilePath) {
        var prefix = component ? {
            '.js': '/js/',
            '.css': '/css/'
        }[path.extname(assetFilePath)] || '/img/' : '/assets/';
        return component + prefix + assetFilePath;
    };
}

function rewriteComponentSource(filePath, source) {
    var index, component;
    if ((index = filePath.indexOf('/ccc/')) > -1) {
        component = filePath.match(/\/ccc\/[^\/]+/)[0];
        source = rewrite({
            assetPathPrefix: '/js/',
            revPost: cRevPost(component)
        }, source);
        source = rewrite({
            assetPathPrefix: '/css/',
            revPost: cRevPost(component)
        }, source);
        source = rewrite({
            assetPathPrefix: '/img/',
            revPost: cRevPost(component)
        }, source);
        return source;
    }
    return source;
}

function getPartials(appRoot, files, cb) { //TODO: production 优化，cache
    var partialsRoot = path.join(appRoot, 'partials');
    if (typeof files === 'function') {
        cb = files;
        files = null;
    }

    var gotFiles = errto(cb, function (files) {
        async.reduce(files, {}, function (partials, filename, next) {
            var filePath = path.join(partialsRoot, filename);
            fs.readFile(filePath, 'utf-8', errto(next, function (
                content) {
                partials[filename.replace(htmlExtReg, '')
                    .replace(/\/+/g, '.')] =
                    rewriteComponentSource(filePath,
                        content);
                next(null, partials);
            }));
        }, cb);
    });

    if (files) {
        gotFiles(null, files);
    } else {
        fs.exists(partialsRoot, function (exists) {
            if (!exists) {
                cb(null, {});
            } else {
                glob('**/*.html', {
                    cwd: partialsRoot
                }, gotFiles);
            }

        });
    }

}

function replaceLibJs(html, options) {
    var settings = options.settings;
    var appRoot = (settings || {})
        .appRoot;

    if (appRoot && settings.assetsDirName) {
        var libs = [];
        try {
            libs = JSON.parse(fs.readFileSync(path.join(appRoot,
                settings.assetsDirName,
                'js',
                'lib.json'), 'utf-8'));
        } catch (err) {
            if (err.code !== 'ENOENT') {
                throw err;
            }
        }
        libs = libs.map(function (lib) {
            return path.resolve(path.join(appRoot,
                'assets', 'js'), lib)
                .substring(appRoot.length);
        });
        var libJsReplaced;
        html = html.replace(
            /(<script\s+src=["']?)\/assets\/js\/lib.js(["']?><\/script>)/g,
            function (all, p1, p2) {
                if (libJsReplaced) {
                    return "";
                } else {
                    libJsReplaced = true;
                    return p1 + libs.join(p2 + p1) +
                        p2;
                }
            });
    }
    return html;
}
exports.engine = function (filePath, options, fn) {
    fs.readFile(filePath, 'utf-8', errto(fn, function (template) {
        template = rewrite({
            revPost: cRevPost('')
        }, template);
        template = rewriteComponentSource(filePath, template);
        var partials = options.partials;
        var match = filePath.match(/\/ccc\/[^\/]+\/views\//);
        if (match) {
            var componentsRoot = (filePath.substring(0, match.index) +
                match[0])
                .replace(/\/views\/$/, '');
            if (componentsRoot !== options.settings.subAppRoot) {
                getPartials(componentsRoot, errto(fn, function (
                    conponentsPartials) {
                    assign(partials, conponentsPartials);
                    render();
                }));
            } else {
                render();
            }
        } else {
            render();
        }

        function render() {
            var html = new Ractive({
                partials: partials,
                template: template, //TODO: production 优化，cache
                data: options
            })
                .toHTML();
            fn(null, replaceLibJs(html, options));
        }
    }));
};

function getReqPath(req) {
    return req.path.replace(/^\/|\/$/g, '');
}

exports.middleware = function () {
    return function (req, res, next) {
        var reqPath = getReqPath(req);
        if (res.viewPath) {
            reqPath = res.viewPath;
        }
        if (reqPath[0] === '/') {
            reqPath = reqPath.substring(1);
        }
        var ext = path.extname(reqPath);
        if (ext && ext !== '.html') {
            return next();
        }
        return res.render(reqPath);
    };
};

exports.argmentApp = function (app, opts) {
    app.set('view engine', 'html');
    app.engine('html', exports.engine);
    app.set('appRoot', opts.appRoot);
    app.set('assetsDirName', opts.assetsDirName);
    app.set('views', [].concat(app.get('views'))
        .concat(glob.sync('ccc/*/views/', {
                cwd: opts.appRoot
            })
            .map(unary(path.join.bind(path, opts.appRoot))))
        .filter(Boolean));
    app.use(function (req, res, next) {
        var _render = res.render;
        // 让 res.viewPath 支持 express-promise
        res.render = function (name, options, fn) {
            var res = this;
            var app = res.app;
            if (!name) {
                name = getReqPath(this.req);
            }
            if ('function' === typeof options) {
                fn = options;
                options = {};
            }
            options = options || {};
            var appLocals = {};
            if (app.locals.__proto__) { // support sub-app, but not sub-sub-app
                assign(appLocals, app.locals.__proto__);
            }
            assign(appLocals, app.locals);

            var opts = assign({}, appLocals, res.locals, options);
            var view;
            var cache = app.cache;
            // set .cache unless explicitly provided
            opts.cache = opts.cache ? app.enabled('view cache') :
                opts.cache;

            view = (opts.cache && cache[name]) || new(app.get('view'))(name, {
                defaultEngine: app.get('view engine'),
                root: app.get('views'),
                engines: app.engines
            });

            // default callback to respond
            fn = fn || function (err, str) {
                if (err) {
                    return res.req.next(err);
                }
                res[res.headersSent ? 'end' : 'send'](str);
            };

            if (!view.path) {
                return res.req.next();
            }

            var rushHeads = [].concat(appLocals.rushHeads)
                .concat(res.locals.rushHeads)
                .concat(options.rushHeads)
                .filter(Boolean);

            if (rushHeads.length) {
                res.statusCode = 200;
                res.set('Content-Type', 'text/html; charset=utf-8');

                res.write(rushHeads.join(''));
            }

            var partials;
            getPartials(app.set('appRoot'), errto(fn, function (
                appPartials) {
                if (res.app.set('subAppRoot')) {
                    getPartials(res.app.set('subAppRoot'),
                        errto(
                            fn, function (subAppPartials) {
                                partials = assign(appPartials,
                                    subAppPartials);
                                render();
                            }));
                } else {
                    partials = appPartials;
                    render();
                }
            }));

            function render() {
                if (res.locals.partials) {
                    assign(partials, res.locals.partials);
                }
                if (options.partials) {
                    assign(partials, options.partials);
                }
                opts.partials = partials;
                res.locals = {};
                _render.call(res, view.path, opts, fn);
            }

        };
        next();
    });
    if (opts.appendMiddleware !== false) {
        app.use(exports.middleware());
    }
};
<|endoftext|>


<commit_before>var stylelint = require('stylelint');

var ruleName = 'sh-waqar/declaration-use-variable';

var messages = stylelint.utils.ruleMessages(ruleName, {
    expected: function expected(h) {
        return 'Expected variable for \"' + h + '\".';
    }
});

/**
 * Compares the declaration with regex pattern
 * to verify the usage of variable
 *
 * @param  {string} val
 * @return {bool}
 */
function checkValue(val) {
    // Regex for checking
    // scss variable starting with '$'
    // map-get function in scss
    // less variable starting with '@'
    // custom properties starting with '--' or 'var'
    // color functions starting with 'color'
    var regEx = /^(\$)|(map-get)|(\@)|(--)|(var)|(color)/g;

    return regEx.test(val);
}

/**
 * Checks the defined property in (css|scss|less) with the
 * test string or regex defined in stylelint config
 *
 * @param  {string} value
 * @param  {string|regex} comparison
 * @return {bool}
 */
function testAgaintString(value, comparison) {
    var comparisonIsRegex = comparison[0] === "/" && comparison[comparison.length - 1] === "/";

    // if value is a variable do not run check
    // and return, since it would be a variable declaration
    // not a style property declaration
    if (checkValue(value)) return;

    if (comparisonIsRegex) {
        var valueMatches = new RegExp(comparison.slice(1, -1)).test(value);
        return valueMatches;
    }

    return value == comparison;
}

/**
 * Checks the test expression with css declaration
 *
 * @param  {string} value
 * @param  {string|array} comparison
 * @return {bool}
 */
function checkProp(value, comparison) {
    if (Array.isArray(comparison)) {
        for (var input of comparison) {
            if (testAgaintString(value, input)) return true;
        }
        return false;
    } else {
        return testAgaintString(value, comparison);
    }
}

module.exports = stylelint.createPlugin(ruleName, function(options) {
    options = options || '';

    return function(root, result) {
        var validOptions = stylelint.utils.validateOptions({
            ruleName: ruleName,
            result: result,
            actual: options,
        });

        if (!validOptions) {
            return;
        }

        root.walkDecls(function(statement) {
            if (checkProp(statement.prop, options) && !checkValue(statement.value)) {
                stylelint.utils.report({
                    ruleName: ruleName,
                    result: result,
                    node: statement,
                    message: messages.expected(statement.prop)
                });
            }
        });
    };
});

module.exports.ruleName = ruleName;
module.exports.messages = messages;
<commit_msg>Fix support of color() functions<commit_after>var stylelint = require('stylelint');

var ruleName = 'sh-waqar/declaration-use-variable';

var messages = stylelint.utils.ruleMessages(ruleName, {
    expected: function expected(h) {
        return 'Expected variable for \"' + h + '\".';
    }
});

/**
 * Compares the declaration with regex pattern
 * to verify the usage of variable
 *
 * @param  {string} val
 * @return {bool}
 */
function checkValue(val) {
    // Regex for checking
    // scss variable starting with '$'
    // map-get function in scss
    // less variable starting with '@'
    // custom properties starting with '--' or 'var'
    var regEx = /^(\$)|(map-get)|(\@)|(--)|(var)/g;

    // color functions starting with 'color('
    if (val.indexOf('color(') > -1) {
      return true;
    }
    return regEx.test(val);
}

/**
 * Checks the defined property in (css|scss|less) with the
 * test string or regex defined in stylelint config
 *
 * @param  {string} value
 * @param  {string|regex} comparison
 * @return {bool}
 */
function testAgaintString(value, comparison) {
    var comparisonIsRegex = comparison[0] === "/" && comparison[comparison.length - 1] === "/";

    // if value is a variable do not run check
    // and return, since it would be a variable declaration
    // not a style property declaration
    if (checkValue(value)) return;

    if (comparisonIsRegex) {
        var valueMatches = new RegExp(comparison.slice(1, -1)).test(value);
        return valueMatches;
    }

    return value == comparison;
}

/**
 * Checks the test expression with css declaration
 *
 * @param  {string} value
 * @param  {string|array} comparison
 * @return {bool}
 */
function checkProp(value, comparison) {
    if (Array.isArray(comparison)) {
        for (var input of comparison) {
            if (testAgaintString(value, input)) return true;
        }
        return false;
    } else {
        return testAgaintString(value, comparison);
    }
}

module.exports = stylelint.createPlugin(ruleName, function(options) {
    options = options || '';

    return function(root, result) {
        var validOptions = stylelint.utils.validateOptions({
            ruleName: ruleName,
            result: result,
            actual: options,
        });

        if (!validOptions) {
            return;
        }

        root.walkDecls(function(statement) {
            if (checkProp(statement.prop, options) && !checkValue(statement.value)) {
                stylelint.utils.report({
                    ruleName: ruleName,
                    result: result,
                    node: statement,
                    message: messages.expected(statement.prop)
                });
            }
        });
    };
});

module.exports.ruleName = ruleName;
module.exports.messages = messages;
<|endoftext|>


<commit_before>var self = require('sdk/self');
const {
	Cc, Ci, Cu
} = require("chrome");

var Zotero = Cc["@zotero.org/Zotero;1"].getService(Ci.nsISupports).wrappedJSObject;

var buttons = require('sdk/ui/button/action');
var tabs = require("sdk/tabs");
var tab_utils = require("sdk/tabs/utils");
var utils = require('sdk/window/utils');
var {
	viewFor
} = require("sdk/view/core");
var {
	setTimeout
} = require("sdk/timers");
var preferences = require("sdk/simple-prefs").prefs;

/*
 * Add import button to Firefox toolbar.
 */
var importButton = buttons.ActionButton({
	id: "import-button",
	label: "Import references into JabRef",
	icon: {
		"16": "./JabRef-icon-16.png",
		"48": "./JabRef-icon-48.png"
	},
	onClick: handleImportClick,
});

/*
 * Get the underlying document of the tab.
 */
function getDocumentForTab(tab) {
	var lowLevelTab = viewFor(tab);
	// Get the ContentDocument of the tab
	var browser = tab_utils.getBrowserForTab(lowLevelTab);
	return browser.contentDocument;
}

/*
 * Import items found on the present website.
 */
function handleImportClick(state) {
	// Get active tab
	var activeTab = tabs.activeTab;
	var doc = getDocumentForTab(activeTab);

	// Create and show panel
	var panel = require("sdk/panel").Panel({
		width: 330,
		height: 150,
		contentURL: "./progressPanel.html"
	});
	panel.port.on('winsize', function(data) {
		panel.resize(330, data.height);
	});
	panel.show({
		position: importButton
	});

	// Detect and import bibliographic items
	startImport(doc, panel);
}

/*
 * Detects contained bibliographic items and sends them to JabRef.
 */
function startImport(doc, panel) {
	// Look for translators which are able to handle the current website
	var translate = new Zotero.Translate.Web();
	translate.setDocument(doc);
	translate.setHandler("translators", function(obj, item) {
		detectAndExportReferenceItems(obj, item, panel)
	});

	translate.getTranslators(false); // false = return only the first translator
}

/*
 * Called when a translator is found (search initiated by Zotero.Translate.getTranslators()).
 * Uses the translator to search for bibliographic items and export them.
 */
function detectAndExportReferenceItems(translate, translators, panel) {
	var items = [];
	translate.setTranslator(translators[0]);

	translate.clearHandlers("itemDone");
	translate.clearHandlers("done");
	translate.clearHandlers("attachmentProgress");

	translate.setHandler("itemDone", function(obj, dbItem, item) {
		// Prepare attachment data
		var attachments = [];
		for (var i = item.attachments.length - 1; i >= 0; i--) {
			attachments.push({
				attachmentId: JSON.stringify(item.attachments[i]).hashCode(),
				title: item.attachments[i].title,
				imageSrc: Zotero.Utilities.determineAttachmentIcon(item.attachments[i]),
			});
		};
		var finishedItem = {
			title: item.title,
			attachments: attachments,
			imageSrc: Zotero.ItemTypes.getImageSrc(item.itemType)
		};
		// Pass parsed item to progress window
		panel.port.emit("show", finishedItem);

		// Remember that this item was finished
		items.push(dbItem);
	});

	translate.setHandler("done", function() {
		// Translation is done, so export the discovered items
		exportItems(items);

		// Hide panel in 1 sec
		setTimeout(function() {
			panel.hide();
		}, 1000);
	});

	translate.setHandler("attachmentProgress", function(obj, attachment, progress, error) {
		// Notify progress window about the attachment download
		panel.port.emit("updateProgress", {
			attachmentId: JSON.stringify(attachment).hashCode(),
			progress: progress
		});
	});

	// Run translator
	translate.translate();
	//translate.translate(false); // this would not save the items to the zotero database
}

/*
 * Exports the given items to JabRef.
 */
function exportItems(items) {
	if (items.length <= 0)
		return;

	// translate() deletes items array; this is why we save a cloned array here
	var copyItems = items.slice(0);

	// Create a new temporary file
	var file = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties).get("TmpD", Ci.nsIFile);
	file.append("zotero_export.bib");
	file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);

	// Prepare export
	var exportTranslator = new Zotero.Translate.Export();
	//exportTranslator.setTranslator('9cb70025-a888-4a29-a210-93ec52da40d4'); // BibTeX
	exportTranslator.setTranslator('b6e39b57-8942-4d11-8259-342c46ce395f'); // BibLaTeX
	exportTranslator.setItems(items);
	exportTranslator.setLocation(file);

	exportTranslator.clearHandlers("done");
	exportTranslator.setHandler("done", function(obj, returnValue) {
		importIntoJabRef(file);
	});

	// Perform export
	exportTranslator.translate();

	// Delete saved items from zotero database, so we don't leave any traces
	deleteItemsFromZoteroDatabase(copyItems);
}

/*
 * Sends the given bib file to JabRef.
 */
function importIntoJabRef(file) {
	// Get JabRef executable
	var jabRef = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
	jabRef.initWithPath(preferences.jabRefPath);
	// Start JabRef
	var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
	process.init(jabRef);
	var args = ["--importToOpen", file.path];
	process.run(false, args, args.length);
}

/*
 * Delete items from Zotero db.
 */
function deleteItemsFromZoteroDatabase(items) {
	for (i = 0; i < items.length; i++) {
		Zotero.Items.erase(items[i].id);
	}
}

/*
 * Listen for tab content loads in order to enable/disable the import button.
 */
tabs.on('ready', function(tab) {
	var doc = getDocumentForTab(tab);

	// Search for translators
	var translate = new Zotero.Translate.Web();
	translate.setDocument(doc);
	translate.setHandler("translators", function(obj, translators) {
		if (!translators.length) {
			// No translators found, so disable button
			importButton.state(tab, {
				disabled: true,
				// We have to change the icon to gray since disabled=true does not gray-out the button (this is a bug https://bugzilla.mozilla.org/show_bug.cgi?id=1167559)
				icon: {
					"16": "./JabRef-icon-16-gray.png",
					"48": "./JabRef-icon-48-gray.png"
				},
				label: "Import references into JabRef: no references found on website."
			});
		} else {
			// Translators found, so update label
			importButton.state(tab, {
				label: "Import references into JabRef using " + translators[0].label
			});
		}
	});
	translate.getTranslators(false);
});

/*
 * Get hashcode of string
 * Code from http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
 */
String.prototype.hashCode = function() {
	var hash = 0;
	if (this.length == 0) return hash;
	for (i = 0; i < this.length; i++) {
		char = this.charCodeAt(i);
		hash = ((hash << 5) - hash) + char;
		hash = hash & hash; // Convert to 32bit integer
	}
	return hash;
}
<commit_msg>Fix #18: downloaded files are present<commit_after>var self = require('sdk/self');
const {
	Cc, Ci, Cu
} = require("chrome");

var Zotero = Cc["@zotero.org/Zotero;1"].getService(Ci.nsISupports).wrappedJSObject;

var buttons = require('sdk/ui/button/action');
var tabs = require("sdk/tabs");
var tab_utils = require("sdk/tabs/utils");
var utils = require('sdk/window/utils');
var {
	viewFor
} = require("sdk/view/core");
var {
	setTimeout
} = require("sdk/timers");
var preferences = require("sdk/simple-prefs").prefs;

/*
 * Add import button to Firefox toolbar.
 */
var importButton = buttons.ActionButton({
	id: "import-button",
	label: "Import references into JabRef",
	icon: {
		"16": "./JabRef-icon-16.png",
		"48": "./JabRef-icon-48.png"
	},
	onClick: handleImportClick,
});

/*
 * Get the underlying document of the tab.
 */
function getDocumentForTab(tab) {
	var lowLevelTab = viewFor(tab);
	// Get the ContentDocument of the tab
	var browser = tab_utils.getBrowserForTab(lowLevelTab);
	return browser.contentDocument;
}

/*
 * Import items found on the present website.
 */
function handleImportClick(state) {
	// Get active tab
	var activeTab = tabs.activeTab;
	var doc = getDocumentForTab(activeTab);

	// Create and show panel
	var panel = require("sdk/panel").Panel({
		width: 330,
		height: 150,
		contentURL: "./progressPanel.html"
	});
	panel.port.on('winsize', function(data) {
		panel.resize(330, data.height);
	});
	panel.show({
		position: importButton
	});

	// Detect and import bibliographic items
	startImport(doc, panel);
}

/*
 * Detects contained bibliographic items and sends them to JabRef.
 */
function startImport(doc, panel) {
	// Look for translators which are able to handle the current website
	var translate = new Zotero.Translate.Web();
	translate.setDocument(doc);
	translate.setHandler("translators", function(obj, item) {
		detectAndExportReferenceItems(obj, item, panel)
	});

	translate.getTranslators(false); // false = return only the first translator
}

/*
 * Called when a translator is found (search initiated by Zotero.Translate.getTranslators()).
 * Uses the translator to search for bibliographic items and export them.
 */
function detectAndExportReferenceItems(translate, translators, panel) {
	var items = [];
	translate.setTranslator(translators[0]);

	translate.clearHandlers("itemDone");
	translate.clearHandlers("done");
	translate.clearHandlers("attachmentProgress");

	translate.setHandler("itemDone", function(obj, dbItem, item) {
		// Prepare attachment data
		var attachments = [];
		for (var i = item.attachments.length - 1; i >= 0; i--) {
			attachments.push({
				attachmentId: JSON.stringify(item.attachments[i]).hashCode(),
				title: item.attachments[i].title,
				imageSrc: Zotero.Utilities.determineAttachmentIcon(item.attachments[i]),
			});
		};
		var finishedItem = {
			title: item.title,
			attachments: attachments,
			imageSrc: Zotero.ItemTypes.getImageSrc(item.itemType)
		};
		// Pass parsed item to progress window
		panel.port.emit("show", finishedItem);

		// Remember that this item was finished
		items.push(dbItem);
	});

	translate.setHandler("done", function() {
		// Translation is done, so export the discovered items
		exportItems(items);

		// Hide panel in 1 sec
		setTimeout(function() {
			panel.hide();
		}, 1000);
	});

	translate.setHandler("attachmentProgress", function(obj, attachment, progress, error) {
		// Notify progress window about the attachment download
		panel.port.emit("updateProgress", {
			attachmentId: JSON.stringify(attachment).hashCode(),
			progress: progress
		});
	});

	// Run translator
	translate.translate();
	//translate.translate(false); // this would not save the items to the zotero database
}

/*
 * Exports the given items to JabRef.
 */
function exportItems(items) {
	if (items.length <= 0)
		return;

	// translate() deletes items array; this is why we save a cloned array here
	var copyItems = items.slice(0);

	// Create a new temporary file
	var file = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties).get("TmpD", Ci.nsIFile);
	file.append("zotero_export.bib");
	file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);

	// Prepare export
	var exportTranslator = new Zotero.Translate.Export();
	//exportTranslator.setTranslator('9cb70025-a888-4a29-a210-93ec52da40d4'); // BibTeX
	exportTranslator.setTranslator('b6e39b57-8942-4d11-8259-342c46ce395f'); // BibLaTeX
	exportTranslator.setItems(items);
	exportTranslator.setLocation(file);

	exportTranslator.clearHandlers("done");
	exportTranslator.setHandler("done", function(obj, returnValue) {
		importIntoJabRef(file);
	});

	// Perform export
	exportTranslator.translate();

	// Delete saved items from zotero database, so we don't leave any traces
	deleteItemsFromZoteroDatabase(copyItems);
}

/*
 * Sends the given bib file to JabRef.
 */
function importIntoJabRef(file) {
	// Get JabRef executable
	var jabRef = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
	jabRef.initWithPath(preferences.jabRefPath);
	// Start JabRef
	var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
	process.init(jabRef);
	var args = ["--importToOpen", file.path];
	process.run(false, args, args.length);
}

/*
 * Delete items from Zotero db.
 */
function deleteItemsFromZoteroDatabase(items) {
	for (i = 0; i < items.length; i++) {
		// Zotero also will delete the attachments if we delete the item
		// so we trick Zotero and mark the attachments as linked so they are not deleted
		var attachments = items[i].getAttachments();
		for (var i in attachments) {
			var attachment = Zotero.Items.get(attachments[i]);
			attachment.attachmentLinkMode = Zotero.Attachments.LINK_MODE_LINKED_URL;
			attachment.save();
		}

		Zotero.Items.erase(items[i].id);
	}
}

/*
 * Listen for tab content loads in order to enable/disable the import button.
 */
tabs.on('ready', function(tab) {
	var doc = getDocumentForTab(tab);

	// Search for translators
	var translate = new Zotero.Translate.Web();
	translate.setDocument(doc);
	translate.setHandler("translators", function(obj, translators) {
		if (!translators.length) {
			// No translators found, so disable button
			importButton.state(tab, {
				disabled: true,
				// We have to change the icon to gray since disabled=true does not gray-out the button (this is a bug https://bugzilla.mozilla.org/show_bug.cgi?id=1167559)
				icon: {
					"16": "./JabRef-icon-16-gray.png",
					"48": "./JabRef-icon-48-gray.png"
				},
				label: "Import references into JabRef: no references found on website."
			});
		} else {
			// Translators found, so update label
			importButton.state(tab, {
				label: "Import references into JabRef using " + translators[0].label
			});
		}
	});
	translate.getTranslators(false);
});

/*
 * Get hashcode of string
 * Code from http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
 */
String.prototype.hashCode = function() {
	var hash = 0;
	if (this.length == 0) return hash;
	for (i = 0; i < this.length; i++) {
		char = this.charCodeAt(i);
		hash = ((hash << 5) - hash) + char;
		hash = hash & hash; // Convert to 32bit integer
	}
	return hash;
}
<|endoftext|>


<commit_before>// This will check if the node version you are running is the required
// Node version, if it isn't it will throw the following error to inform
// you.
if (process.version.slice(1).split(".")[0] < 8) throw new Error("Node 8.0.0 or higher is required. Update Node on your system.");

// Load up the discord.js library
const Discord = require("discord.js");
// We also load the rest of the things we need in this file:
const { promisify } = require("util");
const readdir = promisify(require("fs").readdir);
const Enmap = require("enmap");
const EnmapLevel = require("enmap-level");

// This is your client. Some people call it `bot`, some people call it `self`,
// some might call it `cootchie`. Either way, when you see `client.something`,
// or `bot.something`, this is what we're refering to. Your client.
const client = new Discord.Client();

// Here we load the config file that contains our token and our prefix values.
client.config = require("./config.js");
// client.config.token contains the bot's token
// client.config.prefix contains the message prefix

// Require our logger
client.logger = require("./util/Logger");

// Let's start by getting some useful functions that we'll use throughout
// the bot, like logs and elevation features.
require("./modules/functions.js")(client);

// Aliases and commands are put in collections where they can be read from,
// catalogued, listed, etc.
client.commands = new Enmap();
client.aliases = new Enmap();

// Now we integrate the use of Evie's awesome Enhanced Map module, which
// essentially saves a collection to disk. This is great for per-server configs,
// and makes things extremely easy for this purpose.
client.settings = new Enmap({provider: new EnmapLevel({name: "settings"})});

// We're doing real fancy node 8 async/await stuff here, and to do that
// we need to wrap stuff in an anonymous function. It's annoying but it works.

const init = async () => {

  // Here we load **commands** into memory, as a collection, so they're accessible
  // here and everywhere else.
  const cmdFiles = await readdir("./commands/");
  client.logger.log(`Loading a total of ${cmdFiles.length} commands.`);
  cmdFiles.forEach(f => {
    if (!f.endsWith(".js")) return;
    const response = client.loadCommand(f);
    if (response) console.log(response);
  });

  // Then we load events, which will include our message and ready event.
  const evtFiles = await readdir("./events/");
  client.logger.log(`Loading a total of ${evtFiles.length} events.`);
  evtFiles.forEach(file => {
    const eventName = file.split(".")[0];
    const event = require(`./events/${file}`);
    // This line is awesome by the way. Just sayin'.
    client.on(eventName, event.bind(null, client));
    const mod = require.cache[require.resolve(`./events/${file}`)];
    delete require.cache[require.resolve(`./events/${file}`)];
    for (let i = 0; i < mod.parent.children.length; i++) {
      if (mod.parent.children[i] === mod) {
        mod.parent.children.splice(i, 1);
        break;
      }
    }
  });

  // Generate a cache of client permissions for pretty perms
  client.levelCache = {};
  for (let i = 0; i < client.config.permLevels.length; i++) {
    const thisLevel = client.config.permLevels[i];
    client.levelCache[thisLevel.name] = thisLevel.level;
  }

  // Here we login the client.
  client.login(client.config.token);

// End top-level async/await function.
};

init();
<commit_msg>Made this actually work<commit_after>// This will check if the node version you are running is the required
// Node version, if it isn't it will throw the following error to inform
// you.
if (Number(process.version.slice(1).split(".")[0]) < 8) throw new Error("Node 8.0.0 or higher is required. Update Node on your system.");

// Load up the discord.js library
const Discord = require("discord.js");
// We also load the rest of the things we need in this file:
const { promisify } = require("util");
const readdir = promisify(require("fs").readdir);
const Enmap = require("enmap");
const EnmapLevel = require("enmap-level");

// This is your client. Some people call it `bot`, some people call it `self`,
// some might call it `cootchie`. Either way, when you see `client.something`,
// or `bot.something`, this is what we're refering to. Your client.
const client = new Discord.Client();

// Here we load the config file that contains our token and our prefix values.
client.config = require("./config.js");
// client.config.token contains the bot's token
// client.config.prefix contains the message prefix

// Require our logger
client.logger = require("./util/Logger");

// Let's start by getting some useful functions that we'll use throughout
// the bot, like logs and elevation features.
require("./modules/functions.js")(client);

// Aliases and commands are put in collections where they can be read from,
// catalogued, listed, etc.
client.commands = new Enmap();
client.aliases = new Enmap();

// Now we integrate the use of Evie's awesome Enhanced Map module, which
// essentially saves a collection to disk. This is great for per-server configs,
// and makes things extremely easy for this purpose.
client.settings = new Enmap({provider: new EnmapLevel({name: "settings"})});

// We're doing real fancy node 8 async/await stuff here, and to do that
// we need to wrap stuff in an anonymous function. It's annoying but it works.

const init = async () => {

  // Here we load **commands** into memory, as a collection, so they're accessible
  // here and everywhere else.
  const cmdFiles = await readdir("./commands/");
  client.logger.log(`Loading a total of ${cmdFiles.length} commands.`);
  cmdFiles.forEach(f => {
    if (!f.endsWith(".js")) return;
    const response = client.loadCommand(f);
    if (response) console.log(response);
  });

  // Then we load events, which will include our message and ready event.
  const evtFiles = await readdir("./events/");
  client.logger.log(`Loading a total of ${evtFiles.length} events.`);
  evtFiles.forEach(file => {
    const eventName = file.split(".")[0];
    const event = require(`./events/${file}`);
    // This line is awesome by the way. Just sayin'.
    client.on(eventName, event.bind(null, client));
    const mod = require.cache[require.resolve(`./events/${file}`)];
    delete require.cache[require.resolve(`./events/${file}`)];
    for (let i = 0; i < mod.parent.children.length; i++) {
      if (mod.parent.children[i] === mod) {
        mod.parent.children.splice(i, 1);
        break;
      }
    }
  });

  // Generate a cache of client permissions for pretty perms
  client.levelCache = {};
  for (let i = 0; i < client.config.permLevels.length; i++) {
    const thisLevel = client.config.permLevels[i];
    client.levelCache[thisLevel.name] = thisLevel.level;
  }

  // Here we login the client.
  client.login(client.config.token);

// End top-level async/await function.
};

init();
<|endoftext|>


<commit_before>'use strict';

module.exports = compiler;

var handlebars = require('handlebars');
var hashmaps = require('neuron-hashmaps');
var node_path = require('path');
var semver = require('semver');
var pkg = require('neuron-pkg');

function compiler (options) {
  return new Compiler(options || {});
}

// @param {Object} options
// - pkg `Object` object of cortex.json
// - shrinkWrap `Object` object of cortex-shrinkwrap.json
// - cwd `path` the root directories of current project.
// - path `path` path of the current template file
// X - built_root `path` the root directories of packages to be built into
// - ext `String='.js'` the extension of module files, default to `'.js'`
function Compiler (options) {
  this.facade_counter = 0;

  this._check_option(options, 'pkg');
  this._check_option(options, 'shrinkWrap');
  this._check_option(options, 'cwd');
  this._check_option(options, 'path');
  this._check_option(options, 'built_root');
  this.ext = options.ext || '.js';

  this.cwd = node_path.resolve(this.cwd);
  this.path = node_path.resolve(this.cwd, this.path);
  // this.built_root = node_path.resolve(this.cwd, this.built_root);

  this.neuron_hashmaps = hashmaps(options.shrinkWrap);

  this.register('facade', this._facade_handler, this);
  this.register('href', this._href_handler, this);
}

Compiler.prototype._check_option = function(options, key, message) {
  if (!message) {
    message = '`options.' + key + '` must be specified';
  }
  if (!options[key]) {
    throw new Error(message);
  }
  this[key] = options[key];
};

// Register a custom helper
// @param {String} helper
// @param {function(title, options)} handler
// - title
// - options
Compiler.prototype.register = function(helper, handler, context) {
  if (context) {
    handler = handler.bind(context);
  }
  handlebars.registerHelper(helper, handler);
  return this;
};

// Comple the template
Compiler.prototype.compile = function(template) {
  return handlebars.compile(template);
};

Compiler.prototype._config_path = function() {
  // built_root/
  //          |-- <name>
  //                  |-- <version>
  //                              |-- dir/to/template
  //                                                |-- <path.basename>
  // ------------------------------------------------------------------
  //                              |         |
  var dir = node_path.dirname(this.path);
  var relative_to_cwd = node_path.relative(dir, this.cwd);
  return node_path.join('..', '..', relative_to_cwd);
};

Compiler.prototype._facade_handler = function(title, options) {
  var output = '';
  if (this.facade_counter ++ === 0) {
    output += this._neuron_framework();
  }

  output += [
    '<script>',
      'facade({',
        'mod:"' + this._facade_mod(title) + '"',
      '});',
    '</script>'
  ].join('');

  return output;
};

// a.html
// {{href ./b.html}}
// {{href b/b.html}}
Compiler.prototype._href_handler = function(title, options) {
  html
};

// Suppose current package:
// name: foo
// version: 0.2.0
// Then,
// 1.
// facade(foo) -> facade(foo@0.2.0)
// 2.
// facade() -> facade(foo@0.2.0)
// 3.
// facade(foo/abc) -> facade(foo@0.2.0/abc)
// 4.
// facade(foo@1.2.3) -> check if 1.2.3 exists in current shrinkwrap, otherwise -> throw
Compiler.prototype._facade_mod = function(title) {
  var name = this.pkg.name;
  var version = this.pkg.version;

  // facade() -> current package
  if (!title || Object(title) === title) {
    return pkg.format({
      name: name,
      version: version
    });
  }

  var obj = pkg(title);

  // if the facade uses the current package, force the version
  if (obj.name === name) {
    obj.version = version;
  }

  if (obj.version) {
    return pkg.format(obj);
  }

  // 'a' -> 'a@latest'
  obj.range = obj.range || 'latest';

  var is_range_valid = semver.validRange(obj.range) || obj.range === 'latest';

  var facade_pkg = pkg.format({
    name: obj.name,
    range: obj.range
  });

  if (!is_range_valid) {
    throw new Error(
      'Facade: invalid version "' + facade_pkg + '", make sure you have install it.\n' +
      'Or you might as well specify the explicit version of "' + facade_name + '".'
    );
  }

  // parse ranges
  obj.version = this._parse_range(obj.name, obj.range);
  if (!obj.version) {
    throw new Error('Facade: invalid range "' + facade_pkg + '", make sure your have `cortex install --save` it.');
  }

  return pkg.format(obj);
};

Compiler.prototype._parse_range = function(name, range) {
  var ranges = this.neuron_hashmaps.ranges;
  return ranges[name] && ranges[name][range];
};

Compiler.prototype._neuron_framework = function() {
  return this._output_engines() + this._neuron_config();
};

Compiler.prototype._output_engines = function() {
  var self = this;
  return this.neuron_hashmaps
  .engines(this.pkg.name, this.pkg.version)
  .map(function (engine) {
    var src = self._normalize(engine.name, engine.version);
    return '<script src="' + src + '"></script>';
  })
  .join('');
};

Compiler.prototype._neuron_config = function() {
  return '' + [
    '<script>',
    'neuron.config({',
      'ranges:'  + JSON.stringify(this.neuron_hashmaps.ranges) + ',',
      'depTree:' + JSON.stringify(this.neuron_hashmaps.depTree) + ',',
      'path:"' + this._config_path() + '"',
    '});',
    '</script>'
  ].join('');
};

Compiler.prototype._normalize = function(name, version) {
  return node_path.join(this.root, name, version, name + this.ext);
};
<commit_msg>UNTESTED! index: complete href tag; #2<commit_after>'use strict';

module.exports = compiler;

var handlebars = require('handlebars');
var hashmaps = require('neuron-hashmaps');
var node_path = require('path');
var semver = require('semver');
var pkg = require('neuron-pkg');
var node_url = require('url');

function compiler (options) {
  return new Compiler(options || {});
}

// @param {Object} options basic information of the template, not userdata.
// Including:
// - information of the template
// - global configurations of the environment
// Properties:
// - pkg `Object` object of cortex.json
// - shrinkWrap `Object` object of cortex-shrinkwrap.json
// - cwd `path` the root directories of current project.
// - path `path` path of the current template file
// X - built_root `path` the root directories of packages to be built into
// - ext `String='.js'` the extension of module files, default to `'.js'`
function Compiler (options) {
  this.facade_counter = 0;

  this._check_option(options, 'pkg');
  this._check_option(options, 'shrinkWrap');
  this._check_option(options, 'cwd');
  this._check_option(options, 'path');
  this._check_option(options, 'built_root');
  this.ext = options.ext || '.js';
  this.href_root = options.href_root;

  this.cwd = node_path.resolve(this.cwd);
  this.path = node_path.resolve(this.cwd, this.path);

  this.neuron_hashmaps = hashmaps(options.shrinkWrap);

  this.register('facade', this._facade_handler, this);
  this.register('href', this._href_handler, this);
}

Compiler.prototype._check_option = function(options, key, message) {
  if (!message) {
    message = '`options.' + key + '` must be specified';
  }
  if (!options[key]) {
    throw new Error(message);
  }
  this[key] = options[key];
};

// Register a custom helper
// @param {String} helper
// @param {function(title, options)} handler
// - title
// - options
Compiler.prototype.register = function(helper, handler, context) {
  if (context) {
    handler = handler.bind(context);
  }
  handlebars.registerHelper(helper, handler);
  return this;
};

// Comple the template
Compiler.prototype.compile = function(template) {
  return handlebars.compile(template);
};

Compiler.prototype._config_path = function() {
  // built_root/
  //          |-- <name>
  //                  |-- <version>
  //                              |-- dir/to/template
  //                                                |-- <path.basename>
  // ------------------------------------------------------------------
  //                              |         |
  var dir = node_path.dirname(this.path);
  var relative_to_cwd = node_path.relative(dir, this.cwd);
  return node_path.join('..', '..', relative_to_cwd);
};

Compiler.prototype._facade_handler = function(title, options) {
  var output = '';
  if (this.facade_counter ++ === 0) {
    output += this._neuron_framework();
  }

  output += [
    '<script>',
      'facade({',
        'mod:"' + this._facade_mod(title) + '"',
      '});',
    '</script>'
  ].join('');

  return output;
};

// a.html
// {{href ./b.html}}
// {{href b/b.html}}
Compiler.prototype._href_handler = function(title, options) {
  var link = title;
  if (!link) {
    throw new Error('invalid argument for helper `href`.');
  }

  // './b.html'
  // normal -> './b.html'
  // hybrid -> 'protocol://efte/<name>/<relative>/b.html'
  if (this.href_root) {
    link = this._hybrid_href(title);
  }
};

Compiler.prototype._is_relative = function(path) {
  return path === '.'
    || path.indexOf('./') === 0
    || this._is_parent_path(path);
};

Compiler.prototype._is_parent_path = function(path) {
  return path === '..'
    || path.indexOf('../') === 0;
};

// TODO: -> config
Compiler.prototype._hybrid_href = function(title) {
  var name = this.pkg.name;
  var template_relative = node_path.relative(this.cwd, this.path);
  var dir_relative = node_path.dirname(template_relative);
  var link_relative = node_path.join(dir_relative, title);
  // dir: 'template/'
  // title: '../../b.html'
  // -> allow to use a resource outside current repo? NO!
  // Then:
  // title: '../template/../../b.html' ? NO!
  if (this._is_parent_path(link_relative)) {
    throw new Error('You should never link to a resource outside current project.');
  }

  return node_url.resolve(this.href_root, link_relative);
};

// Suppose current package:
// name: foo
// version: 0.2.0
// Then,
// 1.
// facade(foo) -> facade(foo@0.2.0)
// 2.
// facade() -> facade(foo@0.2.0)
// 3.
// facade(foo/abc) -> facade(foo@0.2.0/abc)
// 4.
// facade(foo@1.2.3) -> check if 1.2.3 exists in current shrinkwrap, otherwise -> throw
Compiler.prototype._facade_mod = function(title) {
  var name = this.pkg.name;
  var version = this.pkg.version;

  // facade() -> current package
  if (!title || Object(title) === title) {
    return pkg.format({
      name: name,
      version: version
    });
  }

  var obj = pkg(title);
  // if the facade uses the current package, force the version
  if (obj.name === name) {
    obj.version = version;
  }

  if (obj.version) {
    return pkg.format(obj);
  }

  // 'a' -> 'a@latest'
  obj.range = obj.range || 'latest';

  var is_range_valid = semver.validRange(obj.range) || obj.range === 'latest';

  var facade_pkg = pkg.format({
    name: obj.name,
    range: obj.range
  });

  if (!is_range_valid) {
    throw new Error(
      'Facade: invalid version "' + facade_pkg + '", make sure you have install it.\n' +
      'Or you might as well specify the explicit version of "' + facade_name + '".'
    );
  }

  // parse ranges
  obj.version = this._parse_range(obj.name, obj.range);
  if (!obj.version) {
    throw new Error('Facade: invalid range "' + facade_pkg + '", make sure your have `cortex install --save` it.');
  }

  return pkg.format(obj);
};

Compiler.prototype._parse_range = function(name, range) {
  var ranges = this.neuron_hashmaps.ranges;
  return ranges[name] && ranges[name][range];
};

Compiler.prototype._neuron_framework = function() {
  return this._output_engines() + this._neuron_config();
};

Compiler.prototype._output_engines = function() {
  var self = this;
  return this.neuron_hashmaps
  .engines(this.pkg.name, this.pkg.version)
  .map(function (engine) {
    var src = self._normalize(engine.name, engine.version);
    return '<script src="' + src + '"></script>';
  })
  .join('');
};

Compiler.prototype._neuron_config = function() {
  return '' + [
    '<script>',
    'neuron.config({',
      'ranges:'  + JSON.stringify(this.neuron_hashmaps.ranges) + ',',
      'depTree:' + JSON.stringify(this.neuron_hashmaps.depTree) + ',',
      'path:"' + this._config_path() + '"',
    '});',
    '</script>'
  ].join('');
};

Compiler.prototype._normalize = function(name, version) {
  return node_path.join(this.root, name, version, name + this.ext);
};
<|endoftext|>


<commit_before>/*!
 * micromatch <https://github.com/jonschlinkert/micromatch>
 *
 * Copyright (c) 2014-2015, Jon Schlinkert.
 * Licensed under the MIT license.
 */

'use strict';

var path = require('path');
var filenameRe = require('filename-regex');
var diff = require('arr-diff');
var braces = require('braces');
var win32 = process.platform === 'win32';

/**
 * The main function. Pass an array of filepaths,
 * and a string or array of glob patterns
 *
 * @param  {Array|String} `files`
 * @param  {Array|String} `patterns`
 * @param  {Object} `opts`
 * @return {Array} Array of matches
 */

function micromatch(files, patterns, opts) {
  if (!files || !patterns) {
    return [];
  }

  files = arrayify(files);
  opts = opts || {};

  if (typeof patterns === 'string') {
    return match(files, patterns, opts);
  }

  var len = patterns.length;
  var neg = [], res = [];
  var i = 0;

  while (len--) {
    var glob = patterns[i++];
    if (glob.charCodeAt(0) === 33) {
      neg.push.apply(neg, match(files, glob.slice(1), opts));
    } else {
      res.push.apply(res, match(files, glob, opts));
    }
  }

  return diff(res, neg);
}

/**
 * Pass an array of files and a glob pattern as a string.
 *
 * This function is called by the main `micromatch` function
 * If you only need to pass a single pattern you might get
 * very minor speed improvements using this function.
 *
 * @param  {Array} `files`
 * @param  {Array} `pattern`
 * @param  {Object} `options`
 * @return {Array}
 */

function match(files, pattern, options) {
  if (typeof files !== 'string' && !Array.isArray(files)) {
    throw new Error('micromatch.match() expects a string or array.');
  }

  var opts = options || {};
  files = arrayify(files);

  var negate = opts.negate || pattern.charAt(0) === '!';
  if (negate) {
    pattern = pattern.slice(1);
  }

  opts.hasGlobstar = /\*\*/.test(pattern);
  var regex = makeRe(pattern, opts);

  var len = files.length;
  var res = [];
  var i = 0;

  while (i < len) {
    var file = files[i++];
    var fp = unixify(file, opts);

    if (!isMatch(fp, regex, opts)) {
      continue;
    }
    res.push(fp);
  }

  if (negate) {
    return diff(files, res);
  }

  if (opts.nonull && !res.length) {
    return pattern;
  }
  return res;
}

/**
 * Returns true if the filepath matches the given
 * pattern.
 */

function isMatch(fp, pattern, opts) {
  if (!(pattern instanceof RegExp)) {
    return makeRe(pattern).test(fp);
  }

  if (opts.matchBase) {
    var matches = filenameRe().exec(fp);
    if (pattern.test(matches[0])) {
      return true;
    }
  }

  return pattern.test(fp);
}

/**
 * Filter files with the given pattern.
 *
 * @param  {String|Array} `pattern`
 * @param  {Array} `files`
 * @param  {Options} `opts`
 * @return {Array}
 */

function filter(pattern, opts) {
  var re = !(pattern instanceof RegExp)
    ? makeRe(pattern, opts)
    : pattern;

  return function (files) {
    if (typeof files === 'string') {
      return isMatch(files, pattern, opts);
    }

    var res = files.slice();
    var len = files.length;

    while (len--) {
      if (!isMatch(files[len], pattern, opts)) {
        res.splice(len, 1);
      }
    }
    return res;
  };
}

/**
 * Filter files with the given pattern.
 *
 * @param  {String|Array} `pattern`
 * @param  {Array} `files`
 * @param  {Options} `opts`
 * @return {Array}
 */

function expand(pattern, opts) {
  var res = files.slice();
  var len = files.length;

  while (len--) {
    if (!isMatch(files[len], pattern, opts)) {
      res.splice(len, 1);
    }
  }
  return res;
}

/**
 * Convert a file path to a unix path.
 */

function unixify(fp, opts) {
  if (opts && opts.normalize || win32 || path.sep === '\\') {
    return fp.replace(/[\\\/]+/g, '/');
  }
  return fp;
}

/**
 * Special patterns to be converted to regex.
 * Heuristics are used to simplify patterns
 * and speed up processing.
 */

function esc(str) {
  return str
    .replace(/\?/g, '%~')
    .replace(/\*/g, '%%');
}

var dot         = '\\.';
var box         = '[^/]';
var dots        = dot + '{1,2}';
var slashQ      = esc(box + '*?');
var lookahead   = esc('(?=.)');
var start       = '(?:^|\\/)';
var end         = '(?:\\/|$)';

function unesc(str) {
  return str.replace(/%~/g, '?')
    .replace(/%%/g, '*');
}

function dotstarbase(dotfile) {
  var re = dotfile ? (start + '(?:' + dots + ')' + end) : dot;
  return esc('(?!' + re + ')' + lookahead);
}

function doublestar() {
  return '(?:(?!' + start + dot + ').)*?';
}

function stardot(dotfile) {
  return dotstarbase(dotfile) + slashQ;
}

/**
 * Create a regular expression for matching
 * file paths.
 *
 * @param  {String} glob
 * @param  {Object} options
 * @return {RegExp}
 */

function makeGlob(glob, options) {
  var opts = options || {};

  // reset cache, recompile regex if options change
  optsCache = typeof optsCache !== 'undefined'
    ? optsCache
    : opts;

  if (!equal(optsCache, opts)) {
    cache = glob;
    globRe = null;
  }

  // reset cache, recompile regex if glob changes
  cache = typeof cache !== 'undefined'
    ? cache
    : glob;

  if (cache !== glob) {
    glob = unixify(glob, opts);
    cache = glob;
    globRe = null;
  }

  // if `true`, then we can just return
  // the regex that was previously cached
  if (globRe instanceof RegExp) {
    return globRe;
  }

  function replace(re, str) {
    glob = glob.replace(re, str);
  }

  function unescape() {
    glob = unesc(glob);
  }

  var negate = glob.charCodeAt(0) === 33; /* '!' */
  if (negate) {
    glob = glob.slice(1);
  }

  var parens = glob.indexOf('(');
  var square = glob.indexOf('[');

  if (parens !== -1) {
    glob = extglob(glob, opts);
  }

  // see if there is at least one star
  var twoStars = glob.indexOf('**');
  var flags = opts.flags || '';

  if (twoStars === 0 && glob.length === 2 && !opts.dot) {
    glob = doublestar();
  } else {

    var oneStar = glob.indexOf('*');

    // expandBraces `{1..5}` braces
    if (glob.indexOf('{') !== -1 && !opts.nobraces) {
      glob = expandBraces(glob, options);
    }

    // escaped stars
    replace(/\\\*/g, esc('\\*'));

    // windows drives
    replace(/^(\w):([\\\/]+?)/gi, lookahead + '$1:$2');
    replace(/\[/g, dotstarbase(opts.dot) + '[');

    // glob stars
    if (twoStars !== -1) {
      replace(/\*\*\//g, esc('.*\\/?'));
      replace(/\*\*/g, esc('.*'));
    }

    // question marks
    replace(/\?\./g, esc('?\\.'));
    replace(/\?:/g, esc('?:'));

    // consecutive `?` chars
    replace(/[^?]\?/g, '\\/'+ dotstarbase(opts.dot) + box)
    // .replace(/[^?]\?/g, '\\/.%%' + box)
    // replace(/\?/g, box)
    replace(/\?/g, '.');

    replace(/\//g, '\\/');

    if (oneStar !== -1) {
      // last chars are '/*'
      replace(/\/\*$/g, '\\/' + stardot(opts.dot));
      // last char is '*', no slashes
      replace(/(?!\/)\*$/g, slashQ);
      //=> '^.*'
      replace(/\*/g, stardot(opts.dot));
    }

    replace(/\.(\w+|$)/g, '\\.$1');
    replace(/\[\^\\\/\]/g, box);
    replace(/[\\]+\//g, '\\/');
    unescape();
  }

  if (opts.nocase) flags += 'i';

  // cache regex
  globRe = new RegExp(globRegex(glob, negate), flags);
  // console.log(globRe)
  return globRe;
}

function makeRe(glob, options) {
  return makeGlob(glob, options);
}

/**
 * Create the regex to do the matching. If
 * the leading character in the `glob` is `!`
 * a negation regex is returned.
 *
 * @param {String} `glob`
 * @param {String} `flags`
 */

function globRegex(glob, negate) {
  glob = ('(?:' + glob + ')$');
  glob = negate
    ? ('(?!^' + glob + ').*$')
    : glob;
  return '^' + glob;
}

/**
 * Match exglob patterns:
 *  - `?(...)` match zero or one of the given patterns.
 *  - `*(...)` match zero or more of the given patterns.
 *  - `+(...)` match one or more of the given patterns.
 *  - `@(...)` match one of the given patterns.
 *  - `!(...)` match anything except one of the given patterns.
 */

/**
 * Create the regex to do the matching. If
 * the leading character in the `glob` is `!`
 * a negation regex is returned.
 *
 * @param {String} `glob`
 * @param {String} `flags`
 */

function extglob(glob, opts) {
  return glob.replace(/(\.)?([?*+@!])(\(([^)]*)\))/, function (match, $1, $2, $3, $4) {
    if (!$2 || !$3 || !$4 || $4.indexOf('{') !== -1) {
      return match;
    }
    var res;

    if ($2 === '?') {
      res = '(?:' + $4 + ')?';
    }

    if ($2 === '*' || $2 === '+') {
      res = ($1 ? esc('\\.(?:') : esc('(?:')) + $4 + ')';
    }

    if ($2 === '!') {
    console.log(arguments)
      res = ($1 ? esc('\\.(?:(?!') : esc('((?!')) + $4 + esc(').*?)');
    }

    return res || match;
  });
}

/**
 * Expand braces in the given glob pattern.
 *
 * We only need to use the [braces] lib when
 * patterns are nested.
 *
 * @param  {String} `glob`
 * @return {String}
 */

function expandBraces(glob, options) {
  options = options || {};
  options.makeRe = options.makeRe || true;
  var a = glob.match(/[\{\(\[]/g);
  var b = glob.match(/[\}\)\]]/g);
  if (a && b && (a.length !== b.length)) {
    options.makeRe = false;
  }
  return braces(glob, options).join('|');
}

/**
 * Return true if object A is equal (enough)
 * to object B. Used for options caching. All
 * we need to know is if the object has changed
 * in any way.
 *
 * @param {Object} a
 * @param {Object} b
 * @return {Boolean}
 */

function equal(a, b) {
  if (!b) return false;
  for (var prop in b) {
    if (!a.hasOwnProperty(prop)) {
      return false;
    }
    if (a[prop] !== b[prop]) {
      return false;
    }
  }
  return true;
}

/**
 * Coerce `val` to an array
 *
 * @param  {*} val
 * @return {Array}
 */

function arrayify(val) {
  return !Array.isArray(val)
    ? [val]
    : val;
}

/**
 * Results cache
 */

var globRe;
var cache;
var optsCache;

/**
 * Expose `micromatch`
 */

module.exports = micromatch;

/**
 * Expose `micromatch.match`
 */

module.exports.match = match;

/**
 * Expose `micromatch.isMatch`
 */

module.exports.isMatch = isMatch;

/**
 * Expose `micromatch.makeRe`
 */

module.exports.makeRe = makeRe;

/**
 * Expose `micromatch.braces`
 */

module.exports.braces = braces;

/**
 * Expose `micromatch.filter`
 */

module.exports.filter = filter;
<commit_msg>try different negation strategies, add matchKeys method<commit_after>/*!
 * micromatch <https://github.com/jonschlinkert/micromatch>
 *
 * Copyright (c) 2014-2015, Jon Schlinkert.
 * Licensed under the MIT license.
 */

'use strict';

var win32 = process.platform === 'win32';
var path = require('path');
var fileRe = require('filename-regex');
var extend = require('extend-shallow');
var braces = require('braces');
var diff = require('arr-diff');
var parse = require('./lib/parse');

/**
 * The main function. Pass an array of filepaths,
 * and a string or array of glob patterns
 *
 * @param  {Array|String} `files`
 * @param  {Array|String} `patterns`
 * @param  {Object} `opts`
 * @return {Array} Array of matches
 */

function micromatch(files, patterns, opts) {
  if (!files || !patterns) {
    return [];
  }

  files = arrayify(files);
  opts = opts || {};

  if (typeof patterns === 'string') {
    return match(files, patterns, opts);
  }

  var len = patterns.length;
  var neg = [], res = [];
  var i = 0;

  // while (len--) {
  //   var glob = patterns[i++];
  //   var negated = glob.charCodeAt(0) === 33; /* ! */
  //   if (opts.inclusive) {
  //     return files.filter(filter(glob, {negated: negated}));

  //   } else {
  //     if (negated) {
  //       neg.push.apply(neg, match(files, glob.slice(1), opts));
  //     } else {
  //       res.push.apply(res, match(files, glob, opts));
  //     }
  //   }
  // }

  while (len--) {
    var glob = patterns[i++];
    if (glob.charCodeAt(0) === 33) {
      neg.push.apply(neg, match(files, glob.slice(1), opts));
    } else {
      res.push.apply(res, match(files, glob, opts));
    }
  }
  return diff(res, neg);
}

/**
 * Pass an array of files and a glob pattern as a string.
 *
 * This function is called by the main `micromatch` function
 * If you only need to pass a single pattern you might get
 * very minor speed improvements using this function.
 *
 * @param  {Array} `files`
 * @param  {Array} `pattern`
 * @param  {Object} `options`
 * @return {Array}
 */

function match(files, pattern, opts) {
  if (typeof files !== 'string' && !Array.isArray(files)) {
    throw new Error('micromatch.match() expects a string or array.');
  }

  files = arrayify(files);
  opts = opts || {};

  var negate = opts.negate || false;
  if (opts.nonegate !== true) {
    negate = pattern.charAt(0) === '!';
    if (negate) {
      pattern = pattern.slice(1);
    }
  }

  var regex = !(pattern instanceof RegExp)
    ? makeRe(pattern, opts)
    : pattern;

  var len = files.length;
  var res = [];
  var i = 0;

  while (i < len) {
    var file = files[i++];
    var fp = unixify(file, opts);

    if (!isMatch(fp, regex, opts)) { continue; }
    res.push(fp);
  }

  if (negate) { return diff(files, res); }

  if (opts.nonull && !res.length) {
    return pattern;
  }
  return res;
}

/**
 * Returns true if the filepath matches the given
 * pattern.
 */

function isMatch(fp, pattern, opts) {
  opts = opts || {};

  if (!(pattern instanceof RegExp)) {
    pattern = makeRe(pattern, opts);
  }

  if (opts.matchBase) {
    var matches = fileRe().exec(fp);

    // don't return if not `true`
    if (pattern.test(matches[0])) {
      return true;
    }
  }
  return pattern.test(fp);
}

// function isMatch(fp, pattern, opts) {
//   if (!(pattern instanceof RegExp)) {
//     return makeRe(pattern).test(fp);
//   }

//   if (opts.matchBase) {
//     var matches = fileRe().exec(fp);
//     if (pattern.test(matches[0])) {
//       return true;
//     }
//   }

//   return pattern.test(fp);
// }

/**
 * Filter files with the given pattern.
 *
 * @param  {String|Array} `pattern`
 * @param  {Array} `files`
 * @param  {Options} `opts`
 * @return {Array}
 */

function filter(pattern, opts) {
  opts = opts || {};

  pattern = !(pattern instanceof RegExp)
    ? makeRe(pattern, opts)
    : pattern;

  return function (files) {
    if (typeof files === 'string') {
      var m1 = isMatch(files, pattern, opts);
      if (opts.inclusive && m1 !== false) {
        return true;
      }
      return m1;
    }

    var res = files.slice();
    var len = files.length;
    var m2;

    while (len--) {
      m2 = isMatch(files[len], pattern, opts);
      if (m2) {
        continue;
      }
      res.splice(len, 1);
    }

    return res;
  };
}

/**
 * Filter the keys in an object.
 *
 * @param  {*} val
 * @return {Array}
 */

function matchKeys(pattern, obj, options) {
  var re = !(pattern instanceof RegExp)
    ? makeRe(pattern, options)
    : pattern;

  var keys = Object.keys(obj);
  var len = keys.length;
  var res = {};

  while (len--) {
    var key = keys[len];
    if (re.test(key)) {
      res[key] = obj[key];
    }
  }
  return res;
}

/**
 * Create and cache a regular expression for matching
 * file paths.
 *
 * @param  {String} glob
 * @param  {Object} options
 * @return {RegExp}
 */

function makeRe(glob, options) {
  var opts = options || {};
  var flags = opts.flags || '';

  // reset cache, recompile regex if options change
  optsCache = typeof optsCache !== 'undefined'
    ? optsCache
    : opts;

  if (!equal(optsCache, opts)) {
    cache = glob;
    globRe = null;
  }

  // reset cache, recompile regex if glob changes
  cache = typeof cache !== 'undefined'
    ? cache
    : glob;

  if (cache !== glob) {
    glob = unixify(glob, opts);
    cache = glob;
    globRe = null;
  }

  // if `true`, then we can just return
  // the regex that was previously cached
  if (globRe instanceof RegExp) {
    return globRe;
  }

  if (opts.nocase) { flags += 'i'; }

  var parsed = parse(glob, opts);
  opts.negated = opts.negated || parsed.negated || false;
  glob = wrapGlob(parsed.glob, opts.negated);

  // cache regex
  globRe = new RegExp(glob, flags);
  return globRe;
}

/**
 * Create the regex to do the matching. If
 * the leading character in the `glob` is `!`
 * a negation regex is returned.
 *
 * @param {String} `glob`
 * @param {String} `flags`
 */

function wrapGlob(glob, negate) {
  glob = baseGlob(glob, negate);
  if (negate) {
    glob = negateGlob(glob, negate);
  }
  return '^' + glob;
}

function baseGlob(glob) {
  return '(?:' + glob + ')$';
}

function negateGlob(glob) {
  return '(?!^' + glob + ').*$';
}

/**
 * Return true if object A is equal (enough)
 * to object B. Used for options caching. All
 * we need to know is if the object has changed
 * in any way.
 *
 * @param {Object} a
 * @param {Object} b
 * @return {Boolean}
 */

function equal(a, b) {
  if (!b) return false;
  for (var prop in b) {
    if (!a.hasOwnProperty(prop)) {
      return false;
    }
    if (a[prop] !== b[prop]) {
      return false;
    }
  }
  return true;
}

/**
 * Convert a file path to a unix path.
 */

function unixify(fp, opts) {
  if (opts && opts.normalize || win32 || path.sep === '\\') {
    return fp.replace(/[\\\/]+/g, '/');
  }
  return fp;
}

/**
 * Coerce `val` to an array
 *
 * @param  {*} val
 * @return {Array}
 */

function arrayify(val) {
  return !Array.isArray(val)
    ? [val]
    : val;
}

/**
 * Results cache
 */

var globRe;
var cache;
var optsCache;

// no, this isn't permanent. I will organize
// the following when the API is locked.

/**
 * Expose `micromatch`
 */

module.exports = micromatch;

/**
 * Expose `micromatch.match`
 */

module.exports.match = match;

/**
 * Expose `micromatch.isMatch`
 */

module.exports.isMatch = isMatch;

/**
 * Expose `micromatch.makeRe`
 */

module.exports.makeRe = makeRe;

/**
 * Expose `micromatch.braces`
 */

module.exports.braces = braces;

/**
 * Expose `micromatch.filter`
 */

module.exports.filter = filter;

/**
 * Expose `micromatch.expand`
 */

module.exports.expand = expand;

/**
 * Expose `micromatch.matchKeys`
 */

module.exports.matchKeys = matchKeys;
<|endoftext|>


<commit_before>"use strict";

var EventEmitter  = require('events').EventEmitter,
    path          = require('path'),
    q             = require('kew'),
    utils         = require('lodash'),
    resolve       = require('browser-resolve'),
    builtins      = require('browser-builtins'),
    aggregate     = require('stream-aggregate-promise'),
    DGraph        = require('dgraph').Graph,
    watchGraph    = require('dgraph-live'),
    cssImportTr   = require('dgraph-css-import'),
    cssBundler    = require('./bundlers/css'),
    jsBundler     = require('./bundlers/js'),
    common        = require('./common');

/**
 * Compose bundle
 *
 * @param {Array.<String|Module>} entries
 * @param {Options} opts
 */
function Composer(entries, opts) {
  opts = opts || {};

  this.entries = [];

  this.opts = opts;
  this.basedir = opts.basedir || process.cwd();

  this._entries = utils.memoize(this._entries);
  this._graph = utils.memoize(this._graph);
  this._graphIndex = utils.memoize(this._graphIndex);

  [].concat(entries)
    .filter(Boolean)
    .forEach(this._addEntry.bind(this));
}

utils.assign(Composer.prototype, EventEmitter.prototype, {

  /**
   * Add entry
   *
   * @param {Module|String} entry
   * @private
   */
  _addEntry: function(entry) {
    if (utils.isString(entry))
      entry = {id: entry};

    if (utils.isBoolean(entry.expose))
      entry.expose = entry.id;

    this.entries.push(entry);
  },

  /**
   * Resolve single module
   *
   * @private
   */
  _resolve: function(mod) {
    var promise = q.defer(),
        parent = {filename: path.join(mod.basedir || this.basedir, '_fake.js')};
    resolve(mod.id, parent, promise.makeNodeResolver());
    return promise.then(function(id) {
      return utils.assign(mod, {id: id});
    });
  },

  /**
   * Get resolved entries
   *
   * @private
   */
  _entries: function() {
    return q.all(this.entries.map(this._resolve.bind(this)));
  },

  /**
   * Mark composer as updated
   *
   * @private
   */
  _updated: function() {
    this._graphIndex.cache = {};
    this.emit('update');
  },

  /**
   * Create a set of entries into a dependency graph
   *
   * @private
   */
  _graph: function() {
    return this._entries().then(function(entries) {
      var graph = new DGraph(entries, {
          transform: [].concat(this.opts.transform, cssImportTr),
          extensions: this.opts.extensions,
          modules: builtins
        });

      if (this.opts.debug) {
        graph = watchGraph(graph);
        graph.on('update', this._updated.bind(this));
      }

      return graph;
    }.bind(this));
  },

  /**
   * @private
   */
  _graphIndex: function() {
    return this._graph()
      .then(function(graph) { return aggregate(graph.toStream()); })
      .then(common.buildIndex);
  },

  /**
   * Bundle
   */
  bundle: function() {
    return this._graphIndex().then(function(js) {
      var css = common.separateSubgraph(
            js,
            common.matcher(/\.(css|styl|scss|sass|less)/));

      css = common.stubMissingDeps(css);
      js = common.stubMissingDeps(js);
      js[common.dummyModule.id] = common.dummyModule;

      return {
        'bundle.css': cssBundler(css),
        'bundle.js': jsBundler(js, {
          debug: this.opts.debug,
          expose: exposeMap(this.entries)
        })
      }
    }.bind(this));
  }
});

function exposeMap(modules) {
  var expose = {};
  expose[common.dummyModule.id] = common.dummyModule.id;
  modules.forEach(function(mod) {
    if (mod.expose) expose[mod.id] = mod.expose;
  });
  return expose;
}

module.exports = Composer;
<commit_msg>Expose a factory function<commit_after>"use strict";

var EventEmitter  = require('events').EventEmitter,
    path          = require('path'),
    q             = require('kew'),
    utils         = require('lodash'),
    resolve       = require('browser-resolve'),
    builtins      = require('browser-builtins'),
    aggregate     = require('stream-aggregate-promise'),
    DGraph        = require('dgraph').Graph,
    watchGraph    = require('dgraph-live'),
    cssImportTr   = require('dgraph-css-import'),
    cssBundler    = require('./bundlers/css'),
    jsBundler     = require('./bundlers/js'),
    common        = require('./common');

/**
 * Compose bundle
 *
 * @param {Array.<String|Module>} entries
 * @param {Options} opts
 */
function Composer(entries, opts) {
  opts = opts || {};

  this.entries = [];

  this.opts = opts;
  this.basedir = opts.basedir || process.cwd();

  this._entries = utils.memoize(this._entries);
  this._graph = utils.memoize(this._graph);
  this._graphIndex = utils.memoize(this._graphIndex);

  [].concat(entries)
    .filter(Boolean)
    .forEach(this._addEntry.bind(this));
}

utils.assign(Composer.prototype, EventEmitter.prototype, {

  /**
   * Add entry
   *
   * @param {Module|String} entry
   * @private
   */
  _addEntry: function(entry) {
    if (utils.isString(entry))
      entry = {id: entry};

    if (utils.isBoolean(entry.expose))
      entry.expose = entry.id;

    this.entries.push(entry);
  },

  /**
   * Resolve single module
   *
   * @private
   */
  _resolve: function(mod) {
    var promise = q.defer(),
        parent = {filename: path.join(mod.basedir || this.basedir, '_fake.js')};
    resolve(mod.id, parent, promise.makeNodeResolver());
    return promise.then(function(id) {
      return utils.assign(mod, {id: id});
    });
  },

  /**
   * Get resolved entries
   *
   * @private
   */
  _entries: function() {
    return q.all(this.entries.map(this._resolve.bind(this)));
  },

  /**
   * Mark composer as updated
   *
   * @private
   */
  _updated: function() {
    this._graphIndex.cache = {};
    this.emit('update');
  },

  /**
   * Create a set of entries into a dependency graph
   *
   * @private
   */
  _graph: function() {
    return this._entries().then(function(entries) {
      var graph = new DGraph(entries, {
          transform: [].concat(this.opts.transform, cssImportTr),
          extensions: this.opts.extensions,
          modules: builtins
        });

      if (this.opts.debug) {
        graph = watchGraph(graph);
        graph.on('update', this._updated.bind(this));
      }

      return graph;
    }.bind(this));
  },

  /**
   * @private
   */
  _graphIndex: function() {
    return this._graph()
      .then(function(graph) { return aggregate(graph.toStream()); })
      .then(common.buildIndex);
  },

  /**
   * Bundle
   */
  bundle: function() {
    return this._graphIndex().then(function(js) {
      var css = common.separateSubgraph(
            js,
            common.matcher(/\.(css|styl|scss|sass|less)/));

      css = common.stubMissingDeps(css);
      js = common.stubMissingDeps(js);
      js[common.dummyModule.id] = common.dummyModule;

      return {
        'bundle.css': cssBundler(css),
        'bundle.js': jsBundler(js, {
          debug: this.opts.debug,
          expose: exposeMap(this.entries)
        })
      }
    }.bind(this));
  }
});

function exposeMap(modules) {
  var expose = {};
  expose[common.dummyModule.id] = common.dummyModule.id;
  modules.forEach(function(mod) {
    if (mod.expose) expose[mod.id] = mod.expose;
  });
  return expose;
}

module.exports = function(entries, opts) {
  return new Composer(entries, opts);
}
module.exports.Composer = Composer;
<|endoftext|>


<commit_before>var Util = {
	EMPTY_FN: function() {},

	inherits: function(Child, Parent) {
		var Tmp = function() {};
		Tmp.prototype = Parent.prototype;

		Child.prototype = new Tmp();
		Child.prototype.constructor = Child;
	},

	privateClass: function(name) {
		return $.fn.vanillabox.privateClasses_[name];
	}
};

var DEFAULT_CONFIG = Util.privateClass('DEFAULT_CONFIG');

/**
 * @constructor
 */
var Field = function(config) {
	var me = this;

	me.name_ = config.name;

	me.create_(config);
	me.setValue(DEFAULT_CONFIG[me.name_]);

	me.attach_();
};

Field.prototype.create_ = Util.EMPTY_FN;
Field.prototype.attach_ = Util.EMPTY_FN;

Field.prototype.getElement = function() {
	return this.elem_;
};

Field.prototype.getName = function() {
	return this.name_;
};

Field.prototype.getValue = Util.EMPTY_FN;
Field.prototype.setValue = Util.EMPTY_FN;

/**
 * @constructor
 * @extends Field
 */
var BooleanField = function(config) {
	Field.call(this, config);
};
Util.inherits(BooleanField, Field);

BooleanField.prototype.create_ = function(config) {
	var me = this;

	me.elem_ = $('<input type="checkbox">');
};

BooleanField.prototype.attach_ = function() {
	var me = this;
	me.elem_.on('change', $.proxy(me.onChange_, me));
};

BooleanField.prototype.getValue = function() {
	return !!this.elem_.prop('checked');
};

BooleanField.prototype.setValue = function(value) {
	this.elem_.prop('checked', value);
};

BooleanField.prototype.onChange_ = function() {
	$(this).trigger('change');
};

/**
 * @constructor
 * @extends Field
 */
var SelectField = function(config) {
	Field.call(this, config);
};
Util.inherits(SelectField, Field);

SelectField.prototype.create_ = function(config) {
	var me = this;
	var elem = $('<select>');
	var opts = config.options;
	var len = opts.length;
	var i;
	var optElem;

	for (i = 0; i < len; i++) {
		optElem = $('<option>');
		optElem.attr('value', opts[i]);
		optElem.text(opts[i]);
		elem.append(optElem);
	}

	me.elem_ = elem;
};

SelectField.prototype.attach_ = function() {
	var me = this;
	me.elem_.on('change', $.proxy(me.onChange_, me));
};

SelectField.prototype.getValue = function() {
	return this.elem_.val();
};

SelectField.prototype.setValue = function(value) {
	this.elem_.val(value);
};

SelectField.prototype.onChange_ = function() {
	$(this).trigger('change');
};

/**
 * @constructor
 * @extends Field
 */
var NumberField = function(config) {
	Field.call(this, config);
};
Util.inherits(NumberField, Field);

NumberField.prototype.create_ = function(config) {
	var me = this;

	me.elem_ = $('<input type="text">');
};

NumberField.prototype.attach_ = function() {
	var me = this;
	me.elem_.on('change', $.proxy(me.onChange_, me));
};

NumberField.prototype.getValue = function() {
	var me = this;
	var value = me.elem_.val();
	var intValue = parseInt(value, 10);

	return isNaN(intValue) ?
		DEFAULT_CONFIG[me.getName()] :
		intValue;
};

NumberField.prototype.setValue = function(value) {
	this.elem_.val(value);
};

NumberField.prototype.onChange_ = function() {
	$(this).trigger('change');
};

/**
 * @constructor
 */
var ConfigRow = function(config) {
	var me = this;

	me.config_ = config;

	me.create();

	me.updateEnabled_();
};

ConfigRow.FIELD_CLASSES = {
	'boolean': BooleanField,
	'select': SelectField,
	'number': NumberField
};

ConfigRow.prototype.create = function() {
	var me = this;

	if (me.elem_) {
		return;
	}

	var config = me.config_;
	var elem = $('<tr>');
	var tdElem;

	// name
	tdElem = $('<td>');
	tdElem.addClass('config-name-cell');
	tdElem.text(config.name);
	elem.append(tdElem);

	// description
	tdElem = $('<td>');
	tdElem.addClass('config-desc-cell');
	tdElem.text(config.description);
	elem.append(tdElem);

	// field
	var FieldClass = ConfigRow.FIELD_CLASSES[config.type];
	var field = new FieldClass(config);
	tdElem = $('<td>');
	tdElem.addClass('config-field-cell');
	tdElem.append(field.getElement());
	elem.append(tdElem);
	me.field_ = field;

	// enabled
	var checkboxElem;
	tdElem = $('<td>');
	tdElem.addClass('config-enabled-cell');
	checkboxElem = $('<input type="checkbox">');
	tdElem.append(checkboxElem);
	elem.append(tdElem);
	me.checkboxElem_ = checkboxElem;

	me.elem_ = elem;

	me.attach_();
};

ConfigRow.prototype.attach_ = function() {
	var me = this;

	var checkboxElem = me.checkboxElem_;
	$(checkboxElem).on('change', $.proxy(me.onCheckboxChange_, me));

	var field = me.field_;
	$(field).on('change', $.proxy(me.onFieldChange_, me));
};

ConfigRow.prototype.getElement = function() {
	return this.elem_;
};

ConfigRow.prototype.getField = function() {
	return this.field_;
};

ConfigRow.prototype.isEnabled = function() {
	var me = this;
	return me.checkboxElem_.prop('checked');
};

ConfigRow.prototype.setEnabled = function(enabled) {
	var me = this;

	me.checkboxElem_.prop('checked', enabled);
	me.updateEnabled_();
};

ConfigRow.prototype.updateEnabled_ = function() {
	var me = this;
	var enabled = me.isEnabled();

	me.elem_.toggleClass('config-row-disabled', !enabled);
};

ConfigRow.prototype.onCheckboxChange_ = function() {
	var me = this;

	me.updateEnabled_();
	$(me).trigger('change');
};

ConfigRow.prototype.onFieldChange_ = function() {
	var me = this;

	me.setEnabled(true);
	$(me).trigger('change');
};

/**
 * @constructor
 */
var ConfigForm = function(elem) {
	var me = this;

	me.elem_ = elem;

	me.create();
};

ConfigForm.HEADERS = [
	'Name',
	'Description',
	'Value',
	'Enabled'
];
ConfigForm.CONFIGS = [
	{
		name: 'animation',
		type: 'select',
		options: ['default', 'none'],
		description: 'Animation type. Set \'none\' to disable animation.'
	},
	{
		name: 'closeButton',
		type: 'boolean',
		description: 'Visibility of a close button. If true, a mask will be unclickable.'
	}, {
		name: 'keyboard',
		type: 'boolean',
		description: 'If false, keyboard operations will be disabled.'
	}, {
		name: 'loop',
		type: 'boolean',
		description: 'If true, grouped images will become a continuous loop.'
	}, {
		name: 'preferredWidth',
		type: 'number',
		description: 'Used when a content doesn\'t have fixed width (e.g. iframe)'
	}, {
		name: 'preferredHeight',
		type: 'number',
		description: 'Used when a content doesn\'t have fixed height (e.g. iframe)'
	}, {
		name: 'repositionOnScroll',
		type: 'boolean',
		description: 'If true, reposition on scroll will be enabled.'
	}, {
		name: 'type',
		type: 'select',
		options: ['image', 'iframe'],
		description: 'Type of contents. Set \'iframe\' to show an external webpage.'
	}
];

ConfigForm.prototype.create = function() {
	var me = this;
	var elem = me.getElement();
	var len;
	var i;

	if (me.tableElem_) {
		return;
	}

	var tableElem = $('<table>');
	me.tableElem_ = tableElem;

	var rowElem = $('<tr>');
	var thElem;
	len = ConfigForm.HEADERS.length;
	for (i = 0; i < len; i++) {
		thElem = $('<th>');
		thElem.text(ConfigForm.HEADERS[i]);
		rowElem.append(thElem);
	}
	tableElem.append(rowElem);

	var config;
	var row;
	len = ConfigForm.CONFIGS.length;
	me.rows_ = [];
	for (i = 0; i < len; i++) {
		config = ConfigForm.CONFIGS[i];

		row = new ConfigRow(config);
		tableElem.append(row.getElement());
		me.rows_.push(row);
	}

	elem.append(tableElem);

	me.attach_();
};

ConfigForm.prototype.attach_ = function() {
	var me = this;
	var len = me.rows_.length;
	var i;
	var row;

	for (i = 0; i < len; i++) {
		row = me.rows_[i];
		$(row).on('change', $.proxy(me.onRowChange_, me));
	}
};

ConfigForm.prototype.getElement = function() {
	return this.elem_;
};

ConfigForm.prototype.buildConfig = function() {
	var me = this;
	var rows = me.rows_;
	var len = rows.length;
	var config = {};
	var i;
	var row;
	var field;

	for (i = 0; i < len; i++) {
		row = rows[i];

		if (row.isEnabled()) {
			field = row.getField();
			config[field.getName()] = field.getValue();
		}
	}

	return config;
};

ConfigForm.prototype.onRowChange_ = function() {
	$(this).trigger('change');
};
<commit_msg>Change column order of options table<commit_after>var Util = {
	EMPTY_FN: function() {},

	inherits: function(Child, Parent) {
		var Tmp = function() {};
		Tmp.prototype = Parent.prototype;

		Child.prototype = new Tmp();
		Child.prototype.constructor = Child;
	},

	privateClass: function(name) {
		return $.fn.vanillabox.privateClasses_[name];
	}
};

var DEFAULT_CONFIG = Util.privateClass('DEFAULT_CONFIG');

/**
 * @constructor
 */
var Field = function(config) {
	var me = this;

	me.name_ = config.name;

	me.create_(config);
	me.setValue(DEFAULT_CONFIG[me.name_]);

	me.attach_();
};

Field.prototype.create_ = Util.EMPTY_FN;
Field.prototype.attach_ = Util.EMPTY_FN;

Field.prototype.getElement = function() {
	return this.elem_;
};

Field.prototype.getName = function() {
	return this.name_;
};

Field.prototype.getValue = Util.EMPTY_FN;
Field.prototype.setValue = Util.EMPTY_FN;

/**
 * @constructor
 * @extends Field
 */
var BooleanField = function(config) {
	Field.call(this, config);
};
Util.inherits(BooleanField, Field);

BooleanField.prototype.create_ = function(config) {
	var me = this;

	me.elem_ = $('<input type="checkbox">');
};

BooleanField.prototype.attach_ = function() {
	var me = this;
	me.elem_.on('change', $.proxy(me.onChange_, me));
};

BooleanField.prototype.getValue = function() {
	return !!this.elem_.prop('checked');
};

BooleanField.prototype.setValue = function(value) {
	this.elem_.prop('checked', value);
};

BooleanField.prototype.onChange_ = function() {
	$(this).trigger('change');
};

/**
 * @constructor
 * @extends Field
 */
var SelectField = function(config) {
	Field.call(this, config);
};
Util.inherits(SelectField, Field);

SelectField.prototype.create_ = function(config) {
	var me = this;
	var elem = $('<select>');
	var opts = config.options;
	var len = opts.length;
	var i;
	var optElem;

	for (i = 0; i < len; i++) {
		optElem = $('<option>');
		optElem.attr('value', opts[i]);
		optElem.text(opts[i]);
		elem.append(optElem);
	}

	me.elem_ = elem;
};

SelectField.prototype.attach_ = function() {
	var me = this;
	me.elem_.on('change', $.proxy(me.onChange_, me));
};

SelectField.prototype.getValue = function() {
	return this.elem_.val();
};

SelectField.prototype.setValue = function(value) {
	this.elem_.val(value);
};

SelectField.prototype.onChange_ = function() {
	$(this).trigger('change');
};

/**
 * @constructor
 * @extends Field
 */
var NumberField = function(config) {
	Field.call(this, config);
};
Util.inherits(NumberField, Field);

NumberField.prototype.create_ = function(config) {
	var me = this;

	me.elem_ = $('<input type="text">');
};

NumberField.prototype.attach_ = function() {
	var me = this;
	me.elem_.on('change', $.proxy(me.onChange_, me));
};

NumberField.prototype.getValue = function() {
	var me = this;
	var value = me.elem_.val();
	var intValue = parseInt(value, 10);

	return isNaN(intValue) ?
		DEFAULT_CONFIG[me.getName()] :
		intValue;
};

NumberField.prototype.setValue = function(value) {
	this.elem_.val(value);
};

NumberField.prototype.onChange_ = function() {
	$(this).trigger('change');
};

/**
 * @constructor
 */
var ConfigRow = function(config) {
	var me = this;

	me.config_ = config;

	me.create();

	me.updateEnabled_();
};

ConfigRow.FIELD_CLASSES = {
	'boolean': BooleanField,
	'select': SelectField,
	'number': NumberField
};

ConfigRow.prototype.create = function() {
	var me = this;

	if (me.elem_) {
		return;
	}

	var config = me.config_;
	var elem = $('<tr>');
	var tdElem;

	// enabled
	var checkboxElem;
	tdElem = $('<td>');
	tdElem.addClass('config-enabled-cell');
	checkboxElem = $('<input type="checkbox">');
	tdElem.append(checkboxElem);
	elem.append(tdElem);
	me.checkboxElem_ = checkboxElem;

	// name
	tdElem = $('<td>');
	tdElem.addClass('config-name-cell');
	tdElem.text(config.name);
	elem.append(tdElem);

	// description
	tdElem = $('<td>');
	tdElem.addClass('config-desc-cell');
	tdElem.text(config.description);
	elem.append(tdElem);

	// field
	var FieldClass = ConfigRow.FIELD_CLASSES[config.type];
	var field = new FieldClass(config);
	tdElem = $('<td>');
	tdElem.addClass('config-field-cell');
	tdElem.append(field.getElement());
	elem.append(tdElem);
	me.field_ = field;

	me.elem_ = elem;

	me.attach_();
};

ConfigRow.prototype.attach_ = function() {
	var me = this;

	var checkboxElem = me.checkboxElem_;
	$(checkboxElem).on('change', $.proxy(me.onCheckboxChange_, me));

	var field = me.field_;
	$(field).on('change', $.proxy(me.onFieldChange_, me));
};

ConfigRow.prototype.getElement = function() {
	return this.elem_;
};

ConfigRow.prototype.getField = function() {
	return this.field_;
};

ConfigRow.prototype.isEnabled = function() {
	var me = this;
	return me.checkboxElem_.prop('checked');
};

ConfigRow.prototype.setEnabled = function(enabled) {
	var me = this;

	me.checkboxElem_.prop('checked', enabled);
	me.updateEnabled_();
};

ConfigRow.prototype.updateEnabled_ = function() {
	var me = this;
	var enabled = me.isEnabled();

	me.elem_.toggleClass('config-row-disabled', !enabled);
};

ConfigRow.prototype.onCheckboxChange_ = function() {
	var me = this;

	me.updateEnabled_();
	$(me).trigger('change');
};

ConfigRow.prototype.onFieldChange_ = function() {
	var me = this;

	me.setEnabled(true);
	$(me).trigger('change');
};

/**
 * @constructor
 */
var ConfigForm = function(elem) {
	var me = this;

	me.elem_ = elem;

	me.create();
};

ConfigForm.HEADERS = [
	' ',
	'Name',
	'Description',
	'Value'
];
ConfigForm.CONFIGS = [
	{
		name: 'animation',
		type: 'select',
		options: ['default', 'none'],
		description: 'Animation type. Set \'none\' to disable animation.'
	},
	{
		name: 'closeButton',
		type: 'boolean',
		description: 'Visibility of a close button. If true, a mask will be unclickable.'
	}, {
		name: 'keyboard',
		type: 'boolean',
		description: 'If false, keyboard operations will be disabled.'
	}, {
		name: 'loop',
		type: 'boolean',
		description: 'If true, grouped images will become a continuous loop.'
	}, {
		name: 'preferredWidth',
		type: 'number',
		description: 'Used when a content doesn\'t have fixed width (e.g. iframe)'
	}, {
		name: 'preferredHeight',
		type: 'number',
		description: 'Used when a content doesn\'t have fixed height (e.g. iframe)'
	}, {
		name: 'repositionOnScroll',
		type: 'boolean',
		description: 'If true, reposition on scroll will be enabled.'
	}, {
		name: 'type',
		type: 'select',
		options: ['image', 'iframe'],
		description: 'Type of contents. Set \'iframe\' to show an external webpage.'
	}
];

ConfigForm.prototype.create = function() {
	var me = this;
	var elem = me.getElement();
	var len;
	var i;

	if (me.tableElem_) {
		return;
	}

	var tableElem = $('<table>');
	me.tableElem_ = tableElem;

	var rowElem = $('<tr>');
	var thElem;
	len = ConfigForm.HEADERS.length;
	for (i = 0; i < len; i++) {
		thElem = $('<th>');
		thElem.text(ConfigForm.HEADERS[i]);
		rowElem.append(thElem);
	}
	tableElem.append(rowElem);

	var config;
	var row;
	len = ConfigForm.CONFIGS.length;
	me.rows_ = [];
	for (i = 0; i < len; i++) {
		config = ConfigForm.CONFIGS[i];

		row = new ConfigRow(config);
		tableElem.append(row.getElement());
		me.rows_.push(row);
	}

	elem.append(tableElem);

	me.attach_();
};

ConfigForm.prototype.attach_ = function() {
	var me = this;
	var len = me.rows_.length;
	var i;
	var row;

	for (i = 0; i < len; i++) {
		row = me.rows_[i];
		$(row).on('change', $.proxy(me.onRowChange_, me));
	}
};

ConfigForm.prototype.getElement = function() {
	return this.elem_;
};

ConfigForm.prototype.buildConfig = function() {
	var me = this;
	var rows = me.rows_;
	var len = rows.length;
	var config = {};
	var i;
	var row;
	var field;

	for (i = 0; i < len; i++) {
		row = rows[i];

		if (row.isEnabled()) {
			field = row.getField();
			config[field.getName()] = field.getValue();
		}
	}

	return config;
};

ConfigForm.prototype.onRowChange_ = function() {
	$(this).trigger('change');
};
<|endoftext|>