<commit_before>'use strict';

var ensureString   = require('es5-ext/object/validate-stringifiable-value')
  , escape         = require('es5-ext/reg-exp/escape')
  , startsWith     = require('es5-ext/string/#/starts-with')
  , deferred       = require('deferred')
  , findRequires   = require('find-requires')
  , debug          = require('debug-ext')('rename-module:module')
  , readdir        = require('fs2/readdir')
  , stat           = require('fs2/stat')
  , readFile       = require('fs2/read-file')
  , writeFile      = require('fs2/write-file')
  , unlink         = require('fs2/unlink')
  , path           = require('path')
  , relative       = require('path2/posix/relative')
  , resolveModule  = require('cjs-module/resolve')
  , resolveRoot    = require('cjs-module/resolve-package-root')
  , isPathExternal = require('cjs-module/utils/is-path-external')
  , isModule       = require('./lib/is-module')
  , normalize      = require('./lib/normalize-local-path')

  , push = Array.prototype.push, stringify = JSON.stringify
  , basename = path.basename, extname = path.extname, sep = path.sep, dirname = path.dirname
  , resolve = path.resolve
  , findRequiresOpts = { raw: true };

var readdirOpts = { depth: Infinity, type: { file: true }, stream: true,
	dirFilter: function (path) { return (basename(path) !== 'node_modules'); },
	ignoreRules: 'git', pattern: new RegExp(escape(sep) + '(?:[^.]+|.+\\.js)$') };

module.exports = function (from, to) {
	from = resolve(ensureString(from));
	to = resolve(ensureString(to));

	// Validate arguments and resolve initial data
	return deferred(stat(from), resolveRoot(dirname(from)), stat(to).then(function () {
		throw new Error("Target path " + stringify(to) + " is not empty");
	}, function (err) {
		if (err.code === 'ENOENT') return null;
		throw err;
	}))(function (data) {
		var fileStats = data[0], root = data[1], dirReader, filePromises, modulesToUpdate
		  , fromExt = extname(from)
		  , rootPrefixLength = root.length + 1, trimmedPathStatus;

		if (!fileStats.isFile()) throw new Error("Input module " + stringify(from) + " is not a file");
		if (!root) {
			throw new Error("Unable to resolve package root (renamed module is expected to be placed " +
				"in scope of some package");
		}
		if (!startsWith.call(to, root + sep)) {
			throw new Error("Cannot reliably move module out of current package");
		}

		// Find all JS modules in a package
		debug('%s -> %s', from.slice(rootPrefixLength), to.slice(rootPrefixLength));
		debug('gather local modules at %s', root);
		dirReader = readdir(root, readdirOpts);
		filePromises = [];
		modulesToUpdate = [];
		dirReader.on('change', function (event) {
			push.apply(filePromises, event.added.map(function (path) {
				var filename = resolve(root, path);
				if (filename === from) return;
				return isModule(filename)(function (is) {
					if (!is) return;

					// Find if JS module contains a require to renamed module
					return readFile(filename)(function (code) {
						var dir = dirname(filename), expectedPathFull = relative(dir, from)
						  , expectedPathTrimmed;
						if (expectedPathFull[0] !== '.') expectedPathFull = './' + expectedPathFull;
						expectedPathTrimmed = expectedPathFull.slice(0, -extname(expectedPathFull).length);
						code = String(code);
						return deferred.map(findRequires(code, findRequiresOpts), function (data) {
							var modulePath;
							// Ignore requires to external packages
							if (isPathExternal(data.value)) return;

							modulePath = normalize(data.value, dir);

							// Check full path match, e.g. ./foo/bar.js (for ./foo/bar.js file)
							if (expectedPathFull === modulePath) return data;
							// Check trimmed path match, e.g. ./foo/bar (for ./foo/bar.js file)
							if (expectedPathTrimmed !== modulePath) return;
							// Validate whether trimmed path matches
							// If input module is .js file, then it surely will be matched (.js has priority)
							if (fromExt === '.js') return data;
							// Otherwise check whether some other module is not matched over moved one
							// e.g. if there's foo.json and foo.js, requiring './foo' will match foo.js
							// This check can be done once, therefore we keep once resolved value
							if (!trimmedPathStatus) trimmedPathStatus = resolveModule(dir, data.value);
							return trimmedPathStatus(function (requiredFilename) {
								if (from === requiredFilename) return data;
							});
						})(function (result) {
							result = result.filter(Boolean);
							if (!result.length) return;
							// Matching path(s) found, add module to rewrite queue
							modulesToUpdate.push({ filename: filename, dirname: dir,
								code: code, requires: result });
						});
					});
				});
			}));
		});
		return dirReader(function () {
			// Wait until all local modules are parsed
			return deferred.map(filePromises).aside(function () {
				debug('found %s dependents', modulesToUpdate.length);
			});
		})(function () {
			if (!modulesToUpdate.length) return;

			// Update affected requires in modules that require renamed module
			return deferred.map(modulesToUpdate, function (data) {
				var nuPath = relative(data.dirname, to)
				  , nuPathExt = extname(nuPath)
				  , diff = 0
				  , code = data.code;
				if (nuPath[0] !== '.') nuPath = './' + nuPath;
				data.requires.forEach(function (reqData) {
					var nuRaw = stringify((nuPathExt && !extname(reqData.value))
						? nuPath.slice(0, -nuPathExt.length) : nuPath).slice(1, -1);
					code = code.slice(0, reqData.point + diff) + nuRaw +
						code.slice(reqData.point + diff + reqData.raw.length - 2);
					diff += nuRaw.length - (reqData.raw.length - 2);
				});
				debug('rewrite %s', data.filename.slice(rootPrefixLength));
				return writeFile(data.filename, code);
			});
		})(function () {
			// Rename module, and update require paths within it
			return readFile(from)(function (code) {
				var dirFrom = dirname(from), ext = extname(from), dirTo = dirname(to);
				code = String(code);
				// If not JS module, no requires to parse
				if (ext && (ext !== '.js')) return code;
				// If module was renamed in same folder, then local paths will not change
				// (corner case would be requiring self module, but we assume nobody does that)
				if (dirFrom === dirTo) return code;
				return isModule(from)(function (is) {
					// Not JS modules no requires to parse
					if (!is) return code;
					return deferred.map(findRequires(code, findRequiresOpts).filter(function (data) {
						// Ignore external package requires
						return !isPathExternal(data.value);
					}), function (data) {
						return resolveModule(dirFrom, data.value)(function (path) {
							if (!path) return; // required module doesn't exist
							data.modulePath = path;
							return data;
						});
					})(function (requires) {
						var diff = 0, dir = dirname(to);
						requires.filter(Boolean).forEach(function (reqData) {
							var nuPath = relative(dir, reqData.modulePath)
							  , nuPathExt = extname(nuPath);
							if (nuPath[0] !== '.') nuPath = './' + nuPath;
							var nuRaw = stringify((nuPathExt && !extname(reqData.value))
								? nuPath.slice(0, -nuPathExt.length) : nuPath).slice(1, -1);
							code = code.slice(0, reqData.point + diff) + nuRaw +
								code.slice(reqData.point + diff + reqData.raw.length - 2);
							diff += nuRaw.length - (reqData.raw.length - 2);
						});
						return code;
					});
				});
			});
		})(function (nuCode) {
			debug('rewrite %s to %s', from.slice(rootPrefixLength), to.slice(rootPrefixLength));
			return deferred(writeFile(to, nuCode, { mode: fileStats.mode, intermediate: true }),
				unlink(from));
		});
	});
};
<commit_msg>Improve paths rewrite<commit_after>'use strict';

var ensureString   = require('es5-ext/object/validate-stringifiable-value')
  , escape         = require('es5-ext/reg-exp/escape')
  , startsWith     = require('es5-ext/string/#/starts-with')
  , deferred       = require('deferred')
  , findRequires   = require('find-requires')
  , debug          = require('debug-ext')('rename-module:module')
  , readdir        = require('fs2/readdir')
  , stat           = require('fs2/stat')
  , readFile       = require('fs2/read-file')
  , writeFile      = require('fs2/write-file')
  , unlink         = require('fs2/unlink')
  , path           = require('path')
  , relative       = require('path2/posix/relative')
  , resolveModule  = require('cjs-module/resolve')
  , resolveRoot    = require('cjs-module/resolve-package-root')
  , isPathExternal = require('cjs-module/utils/is-path-external')
  , isModule       = require('./lib/is-module')
  , normalize      = require('./lib/normalize-local-path')

  , push = Array.prototype.push, stringify = JSON.stringify
  , basename = path.basename, extname = path.extname, sep = path.sep, dirname = path.dirname
  , resolve = path.resolve
  , findRequiresOpts = { raw: true };

var readdirOpts = { depth: Infinity, type: { file: true }, stream: true,
	dirFilter: function (path) { return (basename(path) !== 'node_modules'); },
	ignoreRules: 'git', pattern: new RegExp(escape(sep) + '(?:[^.]+|.+\\.js)$') };

module.exports = function (from, to) {
	from = resolve(ensureString(from));
	to = resolve(ensureString(to));

	// Validate arguments and resolve initial data
	return deferred(stat(from), resolveRoot(dirname(from)), stat(to).then(function () {
		throw new Error("Target path " + stringify(to) + " is not empty");
	}, function (err) {
		if (err.code === 'ENOENT') return null;
		throw err;
	}))(function (data) {
		var fileStats = data[0], root = data[1], dirReader, filePromises, modulesToUpdate
		  , fromExt = extname(from)
		  , rootPrefixLength = root.length + 1, trimmedPathStatus;

		if (!fileStats.isFile()) throw new Error("Input module " + stringify(from) + " is not a file");
		if (!root) {
			throw new Error("Unable to resolve package root (renamed module is expected to be placed " +
				"in scope of some package");
		}
		if (!startsWith.call(to, root + sep)) {
			throw new Error("Cannot reliably move module out of current package");
		}

		// Find all JS modules in a package
		debug('%s -> %s', from.slice(rootPrefixLength), to.slice(rootPrefixLength));
		debug('gather local modules at %s', root);
		dirReader = readdir(root, readdirOpts);
		filePromises = [];
		modulesToUpdate = [];
		dirReader.on('change', function (event) {
			push.apply(filePromises, event.added.map(function (path) {
				var filename = resolve(root, path);
				if (filename === from) return;
				return isModule(filename)(function (is) {
					if (!is) return;

					// Find if JS module contains a require to renamed module
					return readFile(filename)(function (code) {
						var dir = dirname(filename), expectedPathFull = relative(dir, from)
						  , expectedPathTrimmed;
						if (expectedPathFull[0] !== '.') expectedPathFull = './' + expectedPathFull;
						expectedPathTrimmed = expectedPathFull.slice(0, -extname(expectedPathFull).length);
						code = String(code);
						return deferred.map(findRequires(code, findRequiresOpts), function (data) {
							var modulePath;
							// Ignore requires to external packages
							if (isPathExternal(data.value)) return;

							modulePath = normalize(data.value, dir);

							// Check full path match, e.g. ./foo/bar.js (for ./foo/bar.js file)
							if (expectedPathFull === modulePath) return data;
							// Check trimmed path match, e.g. ./foo/bar (for ./foo/bar.js file)
							if (expectedPathTrimmed !== modulePath) return;
							// Validate whether trimmed path matches
							// If input module is .js file, then it surely will be matched (.js has priority)
							if (fromExt === '.js') return data;
							// Otherwise check whether some other module is not matched over moved one
							// e.g. if there's foo.json and foo.js, requiring './foo' will match foo.js
							// This check can be done once, therefore we keep once resolved value
							if (!trimmedPathStatus) trimmedPathStatus = resolveModule(dir, data.value);
							return trimmedPathStatus(function (requiredFilename) {
								if (from === requiredFilename) return data;
							});
						})(function (result) {
							result = result.filter(Boolean);
							if (!result.length) return;
							// Matching path(s) found, add module to rewrite queue
							modulesToUpdate.push({ filename: filename, dirname: dir,
								code: code, requires: result });
						});
					});
				});
			}));
		});
		return dirReader(function () {
			// Wait until all local modules are parsed
			return deferred.map(filePromises).aside(function () {
				debug('found %s dependents', modulesToUpdate.length);
			});
		})(function () {
			if (!modulesToUpdate.length) return;

			// Update affected requires in modules that require renamed module
			return deferred.map(modulesToUpdate, function (data) {
				var nuPath = relative(data.dirname, to)
				  , nuPathExt = extname(nuPath)
				  , diff = 0
				  , code = data.code;
				if (nuPath[0] !== '.') nuPath = './' + nuPath;
				data.requires.forEach(function (reqData) {
					var nuRaw = stringify((nuPathExt && !extname(reqData.value))
						? nuPath.slice(0, -nuPathExt.length) : nuPath).slice(1, -1);
					code = code.slice(0, reqData.point + diff) + nuRaw +
						code.slice(reqData.point + diff + reqData.raw.length - 2);
					diff += nuRaw.length - (reqData.raw.length - 2);
				});
				debug('rewrite %s', data.filename.slice(rootPrefixLength));
				return writeFile(data.filename, code);
			});
		})(function () {
			// Rename module, and update require paths within it
			return readFile(from)(function (code) {
				var dirFrom = dirname(from), ext = extname(from), dirTo = dirname(to);
				code = String(code);
				// If not JS module, no requires to parse
				if (ext && (ext !== '.js')) return code;
				// If module was renamed in same folder, then local paths will not change
				// (corner case would be requiring self module, but we assume nobody does that)
				if (dirFrom === dirTo) return code;
				return isModule(from)(function (is) {
					var relPath;
					// Not JS module, so no requires to parse
					if (!is) return code;
					relPath = normalize(relative(dirTo, dirFrom)) + '/';
					return deferred.map(findRequires(code, findRequiresOpts).filter(function (data) {
						// Ignore external package requires
						return !isPathExternal(data.value);
					}), function (data) {
						var oldPath = normalize(data.value)
						  , nuPath = normalize(dirTo + '/' + relPath + oldPath, dirTo);
						if (nuPath === oldPath) return;
						data.nuPath = nuPath;
						return data;
					})(function (requires) {
						var diff = 0;
						requires.filter(Boolean).forEach(function (reqData) {
							var nuPath = reqData.nuPath
							  , nuPathExt = extname(nuPath);
							var nuRaw = stringify((nuPathExt && !extname(reqData.value))
								? nuPath.slice(0, -nuPathExt.length) : nuPath).slice(1, -1);
							code = code.slice(0, reqData.point + diff) + nuRaw +
								code.slice(reqData.point + diff + reqData.raw.length - 2);
							diff += nuRaw.length - (reqData.raw.length - 2);
						});
						return code;
					});
				});
			});
		})(function (nuCode) {
			debug('rewrite %s to %s', from.slice(rootPrefixLength), to.slice(rootPrefixLength));
			return deferred(writeFile(to, nuCode, { mode: fileStats.mode, intermediate: true }),
				unlink(from));
		});
	});
};
<|endoftext|>


<commit_before>import router from 'huawei-router-api/browser';
import moment from 'moment';

export class Notification {
  /**
   * @typedef NotificationData
   * @property {boolean} [read]
   * @property {string} title
   * @property {string} message
   * @property {('basic'|'sms')} [type='basic']
   * @property {number} [date]
   * @property {number} [progress]
   * @property {object} [metadata]
   */

  /**
   *
   * @param {NotificationData} data
   */
  constructor(data) {
    this.read = 'read' in data ? data.read : false;
    this.title = data.title;
    this.message = data.message;
    this.date = 'date' in data ? data.date : null;
    this.progress = data.progress;
    this.metadata = 'metadata' in data ? data.metadata : '';
    this.id = this.title + this.message + this.date + JSON.stringify(this.metadata);
  }

  /**
   * Converts the notification to a JSON object
   * @return {object}
   */
  toJSON() {
    return {
      read: this.read,
      title: this.title,
      message: this.message,
      date: this.date,
      metadata: this.metadata,
    };
  }

  static fromJSON(json) {
    return new Notification(json);
  }

  static fromSms(sms) {
    const parsed = router.sms.parse(sms.Content);

    let progress = null;
    if ('percent' in parsed
    && parsed.percent.length > 0
    && parsed.type === router.sms.types.DATA_PERCENT) {
      progress = parsed.percent[0] / 100;
    }

    let message = '';
    switch (parsed.type) {
    case router.sms.types.AD:
      message = '[[ ADVERTISEMENT  ]]';
      break;
    case router.sms.types.DATA:
      message = 'You have '
      + parsed.data[0].amount + parsed.data[0].unit
      + ' valid until ' + moment(parsed.expires[0]).format('Y-M-D H:mm:ss');
      break;
    default:
      message = sms.Content;
    }

    return new Notification({
      title: 'SMS from '+sms.Phone,
      message: message,
      date: Date.parse(sms.Date),
      read: parseInt(sms.Smstat) === 1,
      progress: progress,
      metadata: parsed,
    });
  }
}
<commit_msg>Use standard date format<commit_after>import router from 'huawei-router-api/browser';
import moment from 'moment';

export class Notification {
  /**
   * @typedef NotificationData
   * @property {boolean} [read]
   * @property {string} title
   * @property {string} message
   * @property {('basic'|'sms')} [type='basic']
   * @property {number} [date]
   * @property {number} [progress]
   * @property {object} [metadata]
   */

  /**
   *
   * @param {NotificationData} data
   */
  constructor(data) {
    this.read = 'read' in data ? data.read : false;
    this.title = data.title;
    this.message = data.message;
    this.date = 'date' in data ? data.date : null;
    this.progress = data.progress;
    this.metadata = 'metadata' in data ? data.metadata : '';
    this.id = this.title + this.message + this.date + JSON.stringify(this.metadata);
  }

  /**
   * Converts the notification to a JSON object
   * @return {object}
   */
  toJSON() {
    return {
      read: this.read,
      title: this.title,
      message: this.message,
      date: this.date,
      metadata: this.metadata,
    };
  }

  static fromJSON(json) {
    return new Notification(json);
  }

  static fromSms(sms) {
    const parsed = router.sms.parse(sms.Content);

    let progress = null;
    if ('percent' in parsed
    && parsed.percent.length > 0
    && parsed.type === router.sms.types.DATA_PERCENT) {
      progress = parsed.percent[0] / 100;
    }

    let message = '';
    switch (parsed.type) {
    case router.sms.types.AD:
      message = '[[ ADVERTISEMENT  ]]';
      break;
    case router.sms.types.DATA:
      message = 'You have '
      + parsed.data[0].amount + parsed.data[0].unit
      + ' valid until ' + moment(parsed.expires[0]).format('Y-M-D HH:mm:ss');
      break;
    default:
      message = sms.Content;
    }

    return new Notification({
      title: 'SMS from '+sms.Phone,
      message: message,
      date: Date.parse(sms.Date),
      read: parseInt(sms.Smstat) === 1,
      progress: progress,
      metadata: parsed,
    });
  }
}
<|endoftext|>


<commit_before>/* Exports an object that defines
 *  all of the configuration needed by the projects'
 *  depended-on grunt tasks.
 *
 * You can find the parent object in: node_modules/lineman/config/application.coffee
 */

module.exports = require(process.env['LINEMAN_MAIN']).config.extend('application', {

  // configure lineman to load additional angular related npm tasks
  loadNpmTasks: [
    "grunt-angular-templates",
    "grunt-ngmin"
  ],

  // configuration for grunt-angular-templates
  ngtemplates: {
    app: { // "app" matches the name of the angular module defined in app.js
      options: {
        base: "app/templates"
      },
      src: "app/templates/**/*.html",
      // puts angular templates in a different spot than lineman looks for other templates in order not to conflict with the watch process
      dest: "generated/angular/template-cache.js"
    }
  },

  // configuration for grunt-ngmin, this happens _after_ concat once, which is the ngmin ideal :)
  ngmin: {
    js: {
      src: "<%= files.js.concatenated %>",
      dest: "<%= files.js.concatenated %>"
    }
  },

  removeTasks: {
    common: ["handlebars", "coffee"]
  },

  // task override configuration
  prependTasks: {
    dist: ["ngmin"],         // ngmin should run in dist only
    common: ["ngtemplates"] // ngtemplates runs in dist and dev
  },

  // grunt-angular-templates expects that a module already be defined to inject into
  // this configuration orders the template inclusion _after_ the app level module
  concat: {
    js: {
      src: ["<banner:meta.banner>", "<%= files.js.vendor %>", "<%= files.coffee.generated %>", "<%= files.js.app %>", "<%= files.ngtemplates.dest %>"],
      separator: ";"
    }
  },

  // configures grunt-watch-nospawn to listen for changes to, and recompile angular templates
  watch: {
    ngtemplates: {
      files: "app/templates/**/*.html",
      tasks: ["ngtemplates", "concat"]
    }
  }

});
<commit_msg>readability++<commit_after>/* Exports an object that defines
 *  all of the configuration needed by the projects'
 *  depended-on grunt tasks.
 *
 * You can find the parent object in: node_modules/lineman/config/application.coffee
 */

module.exports = require(process.env['LINEMAN_MAIN']).config.extend('application', {

  // configure lineman to load additional angular related npm tasks
  loadNpmTasks: [
    "grunt-angular-templates",
    "grunt-ngmin"
  ],

  // we don't have handlebars templates or coffeescript by default
  removeTasks: {
    common: ["handlebars", "coffee"]
  },

  // task override configuration
  prependTasks: {
    dist: ["ngmin"],         // ngmin should run in dist only
    common: ["ngtemplates"] // ngtemplates runs in dist and dev
  },

  // configuration for grunt-angular-templates
  ngtemplates: {
    app: { // "app" matches the name of the angular module defined in app.js
      options: {
        base: "app/templates"
      },
      src: "app/templates/**/*.html",
      // puts angular templates in a different spot than lineman looks for other templates in order not to conflict with the watch process
      dest: "generated/angular/template-cache.js"
    }
  },

  // configuration for grunt-ngmin, this happens _after_ concat once, which is the ngmin ideal :)
  ngmin: {
    js: {
      src: "<%= files.js.concatenated %>",
      dest: "<%= files.js.concatenated %>"
    }
  },

  // grunt-angular-templates expects that a module already be defined to inject into
  // this configuration orders the template inclusion _after_ the app level module
  concat: {
    js: {
      src: ["<banner:meta.banner>", "<%= files.js.vendor %>", "<%= files.coffee.generated %>", "<%= files.js.app %>", "<%= files.ngtemplates.dest %>"],
      separator: ";"
    }
  },

  // configures grunt-watch-nospawn to listen for changes to, and recompile angular templates
  watch: {
    ngtemplates: {
      files: "app/templates/**/*.html",
      tasks: ["ngtemplates", "concat"]
    }
  }

});
<|endoftext|>


<commit_before>angular.module("yds").directive("ydsAggregate", ["Data", "DashboardService", "$sce",
    function (Data, DashboardService, $sce) {
        return {
            restrict: "E",
            scope: {
                projectId: "@",     // Project ID of chart
                viewType: "@",      // View type of chart
                lang: "@",          // Language
                baseUrl: "@",       // Base URL to send to API (optional)
                extraParams: "=",   // Extra parameters to send

                dashboardId: "@",   // ID used for getting selected year range from DashboardService
                setOnInit: "@",     // If true, will set this aggregate's view type in DashboardService on init
                valueObj: "=",      // If set, the Dashboard aggregates will try to save their value in this object

                iconSize: "@",      // Icon size for FontAwesome icon (2-5)
                showViewBtn: "@",   // If true, will show the "view details" button in the layouts where it is available

                elementH: "@",      // Minimum height of Aggregate
                maxHeight: "@"      // Max height (if exceeded will scroll). Currently works on "title" layout
            },
            templateUrl: Data.templatePath + "templates/general-purpose/aggregate.html",
            link: function (scope) {
                var projectId = scope.projectId;
                var viewType = scope.viewType;
                var dashboardId = scope.dashboardId;
                var lang = scope.lang;
                var setOnInit = scope.setOnInit;
                var elementH = parseInt(scope.elementH);
                var maxHeight = parseInt(scope.maxHeight);
                var iconSize = scope.iconSize;
                var baseUrl = scope.baseUrl;

                var initialized = false;

                scope.detailsButton = false;

                // If project attribute is undefined, set default value
                if (_.isUndefined(projectId) || projectId.trim() === "")
                    projectId = "none";

                // If view type is undefined, show error
                if (_.isUndefined(viewType) || viewType.trim() === "") {
                    console.error("View type not defined!");
                    return;
                }

                // If dashboardId is undefined, show error
                if (_.isUndefined(dashboardId) || dashboardId.trim() === "") {
                    dashboardId = "default";
                }

                // If language is undefined, set default value
                if (_.isUndefined(lang) || lang.trim() === "")
                    lang = "en";

                // If iconSize is undefined, set default value
                if (_.isUndefined(iconSize) || iconSize.trim() === "")
                    iconSize = "4";

                // If elementH is undefined, set default value
                if (_.isUndefined(elementH) || _.isNaN(elementH))
                    elementH = 140;

                // If maxHeight is not undefined, set the CSS style needed to scroll when content exceeds it
                if (!_.isUndefined(maxHeight) && !_.isNaN(maxHeight)) {
                    scope.scrollStyle = {
                        "max-height": maxHeight + "px",
                        "overflow-y": "auto"
                    };
                }

                var getAggregateData = function () {
                    var params = scope.extraParams;

                    // If base URL attribute is defined, add it to the parameters that will be sent
                    if (!_.isUndefined(baseUrl) && baseUrl.length > 0) {
                        params = _.extend({
                            baseurl: baseUrl
                        }, params);
                    }

                    // Get data for aggregate from API to set variables
                    Data.getAggregate(projectId, viewType, lang, params).then(function (response) {
                        // Get view
                        var view = _.first(response.view);

                        // Get value and label
                        scope.label = $sce.trustAsHtml(response.data.label);
                        scope.value = $sce.trustAsHtml(String(response.data.value));

                        if (!_.isEmpty(response.view)) {
                            // If view has icon, set the icon class
                            if (_.has(view, "icon")) {
                                scope.iconClass = view.icon + " fa-" + iconSize + "x";
                            }

                            // If view has a color, set the aggregate's color to that
                            if (_.has(view, "color")) {
                                // Get color and create panel and panel heading styles
                                var color = view.color;

                                scope.panelStyle = {
                                    "border-color": color
                                };

                                scope.panelHeadingStyle = {
                                    "background-color": color,
                                    "border-color": color,
                                    "color": "#FFFFFF"
                                };
                            }

                            // Check if view has layout and set appropriate options
                            if (_.has(view, "layout") && view.layout !== "default") {
                                scope.layout = view.layout;

                                switch (scope.layout) {
                                    case "title_aspect":
                                        // Get aspect to display on page
                                        scope.aspect = response.data.aspect;
                                        break;
                                    case "dashboard":
                                        // Create class for aggregate
                                        scope.dashboardClass = "aggregate-" + viewType.replace(/\./g, "-");

                                        // If possible, save the aggregate's value in the value object
                                        if (!_.isUndefined(viewType) && !_.isUndefined(scope.valueObj)) {
                                            scope.valueObj[viewType] = scope.value;
                                        }

                                        break;
                                    case "plain":
                                        scope.viewTypeClass = "aggregate-" + viewType.replace(/\./g, "-");
                                }
                            } else {
                                // Set default layout options
                                scope.layout = "default";

                                if (!_.isUndefined(scope.showViewBtn) && (scope.showViewBtn === "true" || scope.showViewBtn === "false")) {
                                    scope.detailsButton = (scope.showViewBtn === "true");
                                } else {
                                    scope.detailsButton = true;
                                }
                            }

                            // If detailsButton is shown, subtract the button's height from the elementH
                            if (scope.detailsButton) {
                                elementH -= 40;
                            }

                            // If view didn't have a color so style is undefined, initialize it as empty object
                            if (_.isUndefined(scope.panelHeadingStyle)) {
                                scope.panelHeadingStyle = {};
                            }

                            // Add height to the panel heading style
                            scope.panelHeadingStyle = _.extend(scope.panelHeadingStyle, {
                                "min-height": elementH + "px"
                            });

                            if (setOnInit === "true" && !initialized && _.isEmpty(DashboardService.getViewType(dashboardId))) {
                                scope.setViewType();
                            }
                        }

                        initialized = true;
                    });
                };

                /**
                 * Sets the view type to this aggregate component's view type in DashboardService
                 */
                scope.setViewType = function () {
                    DashboardService.setViewType(dashboardId, {
                        type: viewType,
                        panelStyle: scope.panelStyle,
                        panelHeadingStyle: scope.panelHeadingStyle
                    });
                };

                // Watch for changes in extra parameters of aggregate and update it
                scope.$watch("extraParams", function (newValue, oldValue) {
                    if (!_.isEqual(newValue, oldValue)) {
                        getAggregateData();
                    }
                });

                // Create aggregate for the first time
                if (!initialized) {
                    getAggregateData();
                }
            }
        };
    }
]);
<commit_msg>Make Aggregate print errors to console<commit_after>angular.module("yds").directive("ydsAggregate", ["Data", "DashboardService", "$sce",
    function (Data, DashboardService, $sce) {
        return {
            restrict: "E",
            scope: {
                projectId: "@",     // Project ID of chart
                viewType: "@",      // View type of chart
                lang: "@",          // Language
                baseUrl: "@",       // Base URL to send to API (optional)
                extraParams: "=",   // Extra parameters to send

                dashboardId: "@",   // ID used for getting selected year range from DashboardService
                setOnInit: "@",     // If true, will set this aggregate's view type in DashboardService on init
                valueObj: "=",      // If set, the Dashboard aggregates will try to save their value in this object

                iconSize: "@",      // Icon size for FontAwesome icon (2-5)
                showViewBtn: "@",   // If true, will show the "view details" button in the layouts where it is available

                elementH: "@",      // Minimum height of Aggregate
                maxHeight: "@"      // Max height (if exceeded will scroll). Currently works on "title" layout
            },
            templateUrl: Data.templatePath + "templates/general-purpose/aggregate.html",
            link: function (scope) {
                var projectId = scope.projectId;
                var viewType = scope.viewType;
                var dashboardId = scope.dashboardId;
                var lang = scope.lang;
                var setOnInit = scope.setOnInit;
                var elementH = parseInt(scope.elementH);
                var maxHeight = parseInt(scope.maxHeight);
                var iconSize = scope.iconSize;
                var baseUrl = scope.baseUrl;

                var initialized = false;

                scope.detailsButton = false;

                // If project attribute is undefined, set default value
                if (_.isUndefined(projectId) || projectId.trim() === "")
                    projectId = "none";

                // If view type is undefined, show error
                if (_.isUndefined(viewType) || viewType.trim() === "") {
                    console.error("View type not defined!");
                    return;
                }

                // If dashboardId is undefined, show error
                if (_.isUndefined(dashboardId) || dashboardId.trim() === "") {
                    dashboardId = "default";
                }

                // If language is undefined, set default value
                if (_.isUndefined(lang) || lang.trim() === "")
                    lang = "en";

                // If iconSize is undefined, set default value
                if (_.isUndefined(iconSize) || iconSize.trim() === "")
                    iconSize = "4";

                // If elementH is undefined, set default value
                if (_.isUndefined(elementH) || _.isNaN(elementH))
                    elementH = 140;

                // If maxHeight is not undefined, set the CSS style needed to scroll when content exceeds it
                if (!_.isUndefined(maxHeight) && !_.isNaN(maxHeight)) {
                    scope.scrollStyle = {
                        "max-height": maxHeight + "px",
                        "overflow-y": "auto"
                    };
                }

                var getAggregateData = function () {
                    var params = scope.extraParams;

                    // If base URL attribute is defined, add it to the parameters that will be sent
                    if (!_.isUndefined(baseUrl) && baseUrl.length > 0) {
                        params = _.extend({
                            baseurl: baseUrl
                        }, params);
                    }

                    // Get data for aggregate from API to set variables
                    Data.getAggregate(projectId, viewType, lang, params).then(function (response) {
                        // Get view
                        var view = _.first(response.view);

                        // Get value and label
                        scope.label = $sce.trustAsHtml(response.data.label);
                        scope.value = $sce.trustAsHtml(String(response.data.value));

                        if (!_.isEmpty(response.view)) {
                            // If view has icon, set the icon class
                            if (_.has(view, "icon")) {
                                scope.iconClass = view.icon + " fa-" + iconSize + "x";
                            }

                            // If view has a color, set the aggregate's color to that
                            if (_.has(view, "color")) {
                                // Get color and create panel and panel heading styles
                                var color = view.color;

                                scope.panelStyle = {
                                    "border-color": color
                                };

                                scope.panelHeadingStyle = {
                                    "background-color": color,
                                    "border-color": color,
                                    "color": "#FFFFFF"
                                };
                            }

                            // Check if view has layout and set appropriate options
                            if (_.has(view, "layout") && view.layout !== "default") {
                                scope.layout = view.layout;

                                switch (scope.layout) {
                                    case "title_aspect":
                                        // Get aspect to display on page
                                        scope.aspect = response.data.aspect;
                                        break;
                                    case "dashboard":
                                        // Create class for aggregate
                                        scope.dashboardClass = "aggregate-" + viewType.replace(/\./g, "-");

                                        // If possible, save the aggregate's value in the value object
                                        if (!_.isUndefined(viewType) && !_.isUndefined(scope.valueObj)) {
                                            scope.valueObj[viewType] = scope.value;
                                        }

                                        break;
                                    case "plain":
                                        scope.viewTypeClass = "aggregate-" + viewType.replace(/\./g, "-");
                                }
                            } else {
                                // Set default layout options
                                scope.layout = "default";

                                if (!_.isUndefined(scope.showViewBtn) && (scope.showViewBtn === "true" || scope.showViewBtn === "false")) {
                                    scope.detailsButton = (scope.showViewBtn === "true");
                                } else {
                                    scope.detailsButton = true;
                                }
                            }

                            // If detailsButton is shown, subtract the button's height from the elementH
                            if (scope.detailsButton) {
                                elementH -= 40;
                            }

                            // If view didn't have a color so style is undefined, initialize it as empty object
                            if (_.isUndefined(scope.panelHeadingStyle)) {
                                scope.panelHeadingStyle = {};
                            }

                            // Add height to the panel heading style
                            scope.panelHeadingStyle = _.extend(scope.panelHeadingStyle, {
                                "min-height": elementH + "px"
                            });

                            if (setOnInit === "true" && !initialized && _.isEmpty(DashboardService.getViewType(dashboardId))) {
                                scope.setViewType();
                            }
                        }

                        initialized = true;
                    }, function (error) {
                        console.error("Error when getting data for Aggregate: ", viewType, error.message);
                    });
                };

                /**
                 * Sets the view type to this aggregate component's view type in DashboardService
                 */
                scope.setViewType = function () {
                    DashboardService.setViewType(dashboardId, {
                        type: viewType,
                        panelStyle: scope.panelStyle,
                        panelHeadingStyle: scope.panelHeadingStyle
                    });
                };

                // Watch for changes in extra parameters of aggregate and update it
                scope.$watch("extraParams", function (newValue, oldValue) {
                    if (!_.isEqual(newValue, oldValue)) {
                        getAggregateData();
                    }
                });

                // Create aggregate for the first time
                if (!initialized) {
                    getAggregateData();
                }
            }
        };
    }
]);
<|endoftext|>


<commit_before>import React from 'react';
import {Button} from 'react-bootstrap';
import ModalImage from 'react-modal-image';
import {useParams} from 'react-router-dom';
import {connect} from 'react-redux';
import PropTypes from 'prop-types';
import {Link} from 'react-router-dom';
import {addOneToCart} from '../../store/StoreHelpers.js';
import './ProductScreen.css';

/**
 * @param {!Object<string,
 *      {name:string, item:!Object, quantity:number, description:string,
 *      inCart:boolean, cost:number}>} items The items stored in the site state
 * @param {function(string, number)} addToCart A function to modify
 *      the status of an item in the global cart
 * @return {!JSX} Page component for where a user can view
 *     details about a single product.
 */
const ProductScreenBase = function({items, addToCart}) {
  const {id} = useParams();
  const currProduct = items[id];
  const buttonText = currProduct.inCart ? 'In Cart' : 'Add to Cart';

  const addOnClick = () => {
    addToCart(id);
  };
  const buyOnClick = () => {
    if (!currProduct.inCart) {
      addToCart(id);
    }
  };

  return (

{currProduct.name}

        <ModalImage
          className="product-image"
          small={currProduct.thumbnail}
          large={currProduct.image}
        />

Click image to view full print.

{'Price: '}
            ${currProduct.cost}

            {currProduct.description}

            <Button
              variant="secondary"
              onClick={addOnClick}
              disabled={currProduct.inCart}
            >
              {buttonText}
            </Button>
            <Button variant="secondary" onClick={buyOnClick}
              as={Link} to='/cart'>Buy Now</Button>

  );
};

ProductScreenBase.propTypes = {
  items: PropTypes.object,
  addToCart: PropTypes.func,
};

/**
  * @param {{items:Itemstore}} state
  * @return {{items:!Object<string,
  *      {name:string, item:!Object, quantity:number, description:string,
  *      inCart:boolean, cost:number}>}} The items stored in the site state.
  */
const mapStateToProps = (state) => ({
  items: state.items,
});

/**
  * @param {Dispatch} dispatch
  * @return {function(id:{number})} The function that is to be used
  *  to update the redux store.
  */
const mapDispatchToProps = (dispatch) => {
  return {
    addToCart: (id) => {
      dispatch(addOneToCart(id));
    },
  };
};

/*
 * Decorate the ProductScreenBase function, implicity passing in
 * information about the global site state. Also pass mapDispatchToProps
 * function to allow modification of global cart.
 */
export const ProductScreen =
  connect(mapStateToProps, mapDispatchToProps)(ProductScreenBase);
<commit_msg>added gtag and modals<commit_after>import React, {useEffect} from 'react';
import {Button} from 'react-bootstrap';
import ModalImage from 'react-modal-image';
import {useParams} from 'react-router-dom';
import {connect} from 'react-redux';
import PropTypes from 'prop-types';
import {Link} from 'react-router-dom';
import {addOneToCart} from '../../store/StoreHelpers.js';
import {CodeModal} from '../../components/CodeModal/CodeModal.js';
import {sendAddToCartEvent, sendViewItemEvent} from '../../lib/gtagEvents';
import {getAddToCartCodeSnippet, getViewItemCodeSnippet} from '../../lib/gtagSnippets.js';
import {getMeasureCodeSnippet} from '../../utils';
import './ProductScreen.css';

/**
 * @param {!Object<string,
 *      {name:string, item:!Object, quantity:number, description:string,
 *      inCart:boolean, cost:number}>} items The items stored in the site state
 * @param {function(string, number)} addToCart A function to modify
 *      the status of an item in the global cart
 * @return {!JSX} Page component for where a user can view
 *     details about a single product.
 */
const ProductScreenBase = function({items, addToCart}) {
  const {id} = useParams();
  const currProduct = items[id];
  const buttonText = currProduct.inCart ? 'In Cart' : 'Add to Cart';

  // begin checkout on first page load only.
  const sendViewItem = () => {
    sendViewItemEvent(id);
  };
  useEffect(sendViewItem, []);

  // displays code modal only if add to cart is an option
  const displayModal = () => {
    if (!currProduct.inCart) {
      return (<CodeModal popupId={'addToCart'}
        gtagCode={getAddToCartCodeSnippet(id)}
        measureCode={getMeasureCodeSnippet(id)}/>);
    }
    return;
  };

  const addOnClick = () => {
    addToCart(id);
    sendAddToCartEvent(id);
  };
  const buyOnClick = () => {
    if (!currProduct.inCart) {
      addToCart(id);
      sendAddToCartEvent(id);
    }
  };

  return (

          {currProduct.name}
          <CodeModal popupId={'ViewItem'}
            gtagCode={getViewItemCodeSnippet(id)}
            measureCode={getMeasureCodeSnippet(id)}/>

        <ModalImage
          className="product-image"
          small={currProduct.thumbnail}
          large={currProduct.image}
        />

Click image to view full print.

{'Price: '}
            ${currProduct.cost}

            {currProduct.description}

            <Button
              variant="secondary"
              onClick={addOnClick}
              disabled={currProduct.inCart}
            >
              {buttonText}
            </Button>
            {displayModal()}
            <Button variant="secondary" onClick={buyOnClick}
              as={Link} to='/cart'>Buy Now</Button>
            <CodeModal popupId={'addToCart'}
              gtagCode={getAddToCartCodeSnippet(id)}
              measureCode={getMeasureCodeSnippet(id)}/>

  );
};

ProductScreenBase.propTypes = {
  items: PropTypes.object,
  addToCart: PropTypes.func,
};

/**
  * @param {{items:Itemstore}} state
  * @return {{items:!Object<string,
  *      {name:string, item:!Object, quantity:number, description:string,
  *      inCart:boolean, cost:number}>}} The items stored in the site state.
  */
const mapStateToProps = (state) => ({
  items: state.items,
});

/**
  * @param {Dispatch} dispatch
  * @return {function(id:{number})} The function that is to be used
  *  to update the redux store.
  */
const mapDispatchToProps = (dispatch) => {
  return {
    addToCart: (id) => {
      dispatch(addOneToCart(id));
    },
  };
};

/*
 * Decorate the ProductScreenBase function, implicity passing in
 * information about the global site state. Also pass mapDispatchToProps
 * function to allow modification of global cart.
 */
export const ProductScreen =
  connect(mapStateToProps, mapDispatchToProps)(ProductScreenBase);
<|endoftext|>


<commit_before>import path from 'path';
import async from 'async';
import fs from 'fs';
import * as babylon from 'babylon';
import crypto from 'crypto';
import browserResolve from 'browser-resolve';
import murmur from 'imurmurhash';
import {startsWith} from 'lodash/string';
import {assert} from '../utils/assert';
import {nodeLibs} from '../dependencies/browser_resolve';
import {analyzeBabelAstDependencies} from '../dependencies/babel_ast_dependency_analyzer';
import {createWorkerFarm} from '../workers/worker_farm';
import {createFileCache, createMockCache} from '../kv-file-cache';

const sourceRoot = process.cwd();
const rootPackageJson = path.join(sourceRoot, 'package.json');
const rootNodeModules = path.join(sourceRoot, 'node_modules');

function trace(caches, cb) {
  const tree = Object.create(null);

  function getAst(file, stat, cb) {
    const cache = caches.ast;
    const cacheKey = file + stat.mtime.getTime();

    cache.get(cacheKey, (err, data) => {
      if (err || data) return cb(err, data);

      fs.readFile(file, 'utf8', (err, text) => {
        if (err) return cb(err);

        let ast;
        try {
          ast = babylon.parse(text, {sourceType: 'module'})
        } catch(err) {
          return cb(err);
        }

        cache.set(cacheKey, ast);

        cb(null, ast);
      });
    });
  }

  function getDependencies(file, stat, cb) {
    const cache = caches.dependencies;
    const cacheKey = file + stat.mtime.getTime();

    cache.get(cacheKey, (err, data) => {
      if (err || data) return cb(err, data);

      getAst(file, stat, (err, ast) => {
        if (err) return cb(err);

        let dependencies;
        try {
          dependencies = analyzeBabelAstDependencies(ast);
        } catch(err) {
          return cb(err);
        }

        cache.set(cacheKey, dependencies);

        cb(null, dependencies);
      });
    });
  }

  function getResolvedDependencies(file, stat, cb) {
    const packageResolverCache = caches.packageResolver;
    const moduleResolverCache = caches.moduleResolver;

    getDependencies(file, stat, (err, deps) => {
      if (err) return cb(err);

      // If the file is within the root node_modules, we can aggressively
      // cache its resolved dependencies
      if (startsWith(file, rootNodeModules)) {
        return moduleResolverCache.get(file, (err, data) => {
          if (err || data) return cb(err, data);
          // TODO: handle missing cached deps?

          async.map(
            deps,
            (dep, cb) => browserResolveDependency(dep, file, cb),
            (err, data) => {
              if (err) return cb(err);

              moduleResolverCache.set(file, data);

              cb(null, data);
            }
          );
        });
      }

      const pathDeps = deps.filter(dep => dep[0] === '.' || dep[0] === '/');
      const packageDeps = deps.filter(dep => dep[0] !== '.' && dep[0] !== '/');

      // if a dependency is path based (relative or absolute), we always run the resolver
      // if a dependency is a package, check cache and fallback to resolve
      async.parallel([
        (cb) => {
          async.map(
            pathDeps,
            (dep, cb) => browserResolveDependency(dep, file, cb),
            cb
          )
        },
        (cb) => {
          const cacheKey = 'packages';
          packageResolverCache.get(cacheKey, (err, data) => {
            if (err) return cb(err);
            if (!data) data = {};

            const resolved = packageDeps.filter(dep => data.hasOwnProperty(dep));
            const unresolved = packageDeps.filter(dep => !data.hasOwnProperty(dep));

            if (unresolved.length === 0) {
              return cb(null, resolved);
            }

            async.map(
              unresolved,
              (dep, cb) => browserResolveDependency(dep, file, cb),
              (err, resolvedPaths) => {
                if (err) return cb(err);

                resolvedPaths.map(resolved, i => {
                  data[unresolved[i]] = resolved;
                });

                packageResolverCache.set(cacheKey, data);

                cb(null, resolved.concat(resolvedPaths));
              }
            )
          });
        }
      ], cb);
    });
  }

  function traceFile(file, cb) {
    tree[file] = [];

    fs.stat(file, (err, stat) => {
      if (err) return cb(err);

      getResolvedDependencies(file, stat, (err, resolved) => {
        if (err) {
          err.message = `File: ${file}\n\n${err.message}`;
          return cb(err);
        }

        tree[file] = resolved;

        const untracedFiles = resolved.filter(file => !tree[file]);

        if (untracedFiles.length) {
          untracedFiles.forEach(file => {
            tree[file] = Object.create(null)
          });

          async.map(
            untracedFiles,
            (file, cb) => traceFile(file, cb),
            cb
          );
        } else {
          cb(null);
        }
      });
    });
  }

  async.parallel([
    (cb) => traceFile(require.resolve('redux'), cb),
    (cb) => traceFile(require.resolve('react'), cb),
    (cb) => traceFile(require.resolve('babylon'), cb)
  ], (err) => {
    cb(err, tree);
  });
}

function createFileCaches() {
  const packageJson = fs.readFileSync(rootPackageJson);
  const moduleDirs = fs.readdirSync(rootNodeModules);

  const hash = murmur(packageJson);
  moduleDirs.forEach(dir => hash.hash(dir));
  const packageHash = hash.result();

  return {
    // Used for ASTs parsed from text files
    ast: createFileCache(path.join(__dirname, 'ast_cache')),
    // Used for dependency identifiers extracted form ASTs
    dependencies: createFileCache(path.join(__dirname, 'dependency_cache')),
    // Used for resolving package dependencies
    packageResolver: createFileCache(path.join(__dirname, packageHash + '_package_resolver_cache')),
    // Used for resolving path-based dependencies for files within `rootNodeModules`.
    // Path-based dependencies are denoted by relative (./ or ../) or absolute paths (/)
    moduleResolver: createFileCache(path.join(__dirname, packageHash + '_module_resolver_cache'))
  }
}

function createMockCaches() {
  const mockCache = createMockCache();
  return {
    ast: mockCache,
    dependencies: mockCache,
    packageResolver: mockCache,
    moduleResolver: mockCache
  }
}

function browserResolveDependency(dependency, origin, cb) {
  browserResolve(
    dependency,
    {
      basedir: path.dirname(origin),
      modules: nodeLibs
    },
    cb
  );
}

module.exports = function tracerPerf(useFileCache, cb) {
  const start = (new Date).getTime();

  if (useFileCache) {
    trace(createFileCaches(), (err, tree) => {
      assert.isNull(err);
      assert.isObject(tree);

      const end = (new Date).getTime() - start;
      console.log(`\n\nTraced ${Object.keys(tree).length} records in ${end}ms with file caches`);

      cb();
    });
  } else {
    trace(createMockCaches(), (err, tree) => {
      assert.isNull(err);
      assert.isObject(tree);

      const end = (new Date).getTime() - start;
      console.log(`\n\nTraced ${Object.keys(tree).length} records in ${end}ms with mock caches`);

      cb();
    });
  }
};<commit_msg>Tracer perf test improvements<commit_after>import path from 'path';
import async from 'async';
import fs from 'fs';
import * as babylon from 'babylon';
import crypto from 'crypto';
import browserResolve from 'browser-resolve';
import murmur from 'imurmurhash';
import {startsWith} from 'lodash/string';
import {assert} from '../utils/assert';
import {nodeLibs} from '../dependencies/browser_resolve';
import {analyzeBabelAstDependencies} from '../dependencies/babel_ast_dependency_analyzer';
import {createWorkerFarm} from '../workers/worker_farm';
import {createFileCache, createMockCache} from '../kv-file-cache';

const sourceRoot = process.cwd();
const rootPackageJson = path.join(sourceRoot, 'package.json');
const rootNodeModules = path.join(sourceRoot, 'node_modules');

function trace(caches, cb) {
  const tree = Object.create(null);

  function getAst(file, stat, cb) {
    const cache = caches.ast;
    const cacheKey = file + stat.mtime.getTime();

    cache.get(cacheKey, (err, data) => {
      if (err || data) return cb(err, data);

      fs.readFile(file, 'utf8', (err, text) => {
        if (err) return cb(err);

        let ast;
        try {
          ast = babylon.parse(text, {sourceType: 'module'})
        } catch(err) {
          return cb(err);
        }

        cache.set(cacheKey, ast);

        cb(null, ast);
      });
    });
  }

  function getDependencies(file, stat, cb) {
    const cache = caches.dependencies;
    const cacheKey = file + stat.mtime.getTime();

    cache.get(cacheKey, (err, data) => {
      if (err || data) return cb(err, data);

      getAst(file, stat, (err, ast) => {
        if (err) return cb(err);

        let dependencies;
        try {
          dependencies = analyzeBabelAstDependencies(ast);
        } catch(err) {
          return cb(err);
        }

        cache.set(cacheKey, dependencies);

        cb(null, dependencies);
      });
    });
  }

  function getResolvedDependencies(file, stat, cb) {
    const packageResolverCache = caches.packageResolver;
    const moduleResolverCache = caches.moduleResolver;

    // If the file is within the root node_modules, we can aggressively
    // cache its resolved dependencies
    if (startsWith(file, rootNodeModules)) {
      return moduleResolverCache.get(file, (err, data) => {
        if (err || data) return cb(err, data);

        getDependencies(file, stat, (err, deps) => {
          if (err) return cb(err);

          async.map(
            deps,
            (dep, cb) => browserResolveDependency(dep, file, cb),
            (err, data) => {
              if (err) return cb(err);

              moduleResolverCache.set(file, data);

              cb(null, data);
            }
          );
        });
      });
    }

    // If the file does not live in the root node_modules, we need to get the
    // dependency identifiers first, so that we can split based on path-based
    // and package dependencies
    getDependencies(file, stat, (err, deps) => {
      if (err) return cb(err);

      const pathDeps = deps.filter(dep => dep[0] === '.' || dep[0] === '/');
      const packageDeps = deps.filter(dep => dep[0] !== '.' && dep[0] !== '/');

      // If a dependency identifier is relative (./ ../) or absolute (/), there are
      // edge-cases where caching the resolved path may produce the wrong result.
      // The simplest example is an identifier that may resolve to either a directory
      // or a file. Detecting these cases is problematic, so we always run the resolver
      // for path-based dependency identifiers.
      //
      // If a dependency identifier is a package (does not start with a period or slash),
      // we can aggressively cache the resolved path.
      async.parallel([
        (cb) => {
          async.map(
            pathDeps,
            (dep, cb) => browserResolveDependency(dep, file, cb),
            cb
          )
        },
        (cb) => {
          const cacheKey = 'packages';
          packageResolverCache.get(cacheKey, (err, data) => {
            if (err) return cb(err);
            if (!data) data = {};

            const resolved = packageDeps.filter(dep => data.hasOwnProperty(dep));
            const unresolved = packageDeps.filter(dep => !data.hasOwnProperty(dep));

            if (unresolved.length === 0) {
              return cb(null, resolved);
            }

            async.map(
              unresolved,
              (dep, cb) => browserResolveDependency(dep, file, cb),
              (err, resolvedPaths) => {
                if (err) return cb(err);

                resolvedPaths.map(resolved, i => {
                  data[unresolved[i]] = resolved;
                });

                packageResolverCache.set(cacheKey, data);

                cb(null, resolved.concat(resolvedPaths));
              }
            )
          });
        }
      ], cb);
    });
  }

  function traceFile(file, cb) {
    tree[file] = [];

    fs.stat(file, (err, stat) => {
      if (err) return cb(err);

      getResolvedDependencies(file, stat, (err, resolved) => {
        if (err) {
          err.message = `File: ${file}\n\n${err.message}`;
          return cb(err);
        }

        tree[file] = resolved;

        const untracedFiles = resolved.filter(file => !tree[file]);

        if (untracedFiles.length) {
          untracedFiles.forEach(file => {
            tree[file] = Object.create(null)
          });

          async.map(
            untracedFiles,
            (file, cb) => traceFile(file, cb),
            cb
          );
        } else {
          cb(null);
        }
      });
    });
  }

  async.parallel([
    (cb) => traceFile(require.resolve('redux'), cb),
    (cb) => traceFile(require.resolve('react'), cb),
    (cb) => traceFile(require.resolve('imurmurhash'), cb),
    (cb) => traceFile(require.resolve('whatwg-fetch'), cb),
    (cb) => traceFile(require.resolve('glob'), cb)
  ], (err) => {
    cb(err, tree);
  });
}

function createFileCaches() {
  const packageJson = fs.readFileSync(rootPackageJson);
  const moduleDirs = fs.readdirSync(rootNodeModules);

  const hash = murmur(packageJson);
  moduleDirs.forEach(dir => hash.hash(dir));
  const packageHash = hash.result();

  return {
    // Used for ASTs parsed from text files
    ast: createFileCache(path.join(__dirname, 'ast_cache')),
    // Used for dependency identifiers extracted form ASTs
    dependencies: createFileCache(path.join(__dirname, 'dependency_cache')),
    // Used for resolving package dependencies
    packageResolver: createFileCache(path.join(__dirname, packageHash + '_package_resolver_cache')),
    // Used for resolving path-based dependencies for files within `rootNodeModules`.
    // Path-based dependencies are denoted by relative (./ or ../) or absolute paths (/)
    moduleResolver: createFileCache(path.join(__dirname, packageHash + '_module_resolver_cache'))
  }
}

function createMockCaches() {
  const mockCache = createMockCache();
  return {
    ast: mockCache,
    dependencies: mockCache,
    packageResolver: mockCache,
    moduleResolver: mockCache
  }
}

function browserResolveDependency(dependency, origin, cb) {
  browserResolve(
    dependency,
    {
      basedir: path.dirname(origin),
      modules: nodeLibs
    },
    cb
  );
}

module.exports = function tracerPerf(useFileCache, cb) {
  const start = (new Date).getTime();

  if (useFileCache) {
    trace(createFileCaches(), (err, tree) => {
      assert.isNull(err);
      assert.isObject(tree);

      const end = (new Date).getTime() - start;
      console.log(`\n\nTraced ${Object.keys(tree).length} records in ${end}ms with file caches`);

      cb();
    });
  } else {
    trace(createMockCaches(), (err, tree) => {
      assert.isNull(err);
      assert.isObject(tree);

      const end = (new Date).getTime() - start;
      console.log(`\n\nTraced ${Object.keys(tree).length} records in ${end}ms with mock caches`);

      cb();
    });
  }
};<|endoftext|>


<commit_before>var config = require('../config')
var webpack = require('webpack')
var merge = require('webpack-merge')
var utils = require('./utils')
var baseWebpackConfig = require('./webpack.base.conf')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var InertToHTMLPlugin = require('./webpack.plugin.insertToHtml')
var glob = require('glob');
var path = require('path');

var args = process.argv;
var EnvName = args[2].replace('-env=', '');// 环境名称，如: prd | stg | dev ...
console.log('EnvName:' + EnvName);

function getEntry(globPath) {
  var entries = {},
    basename, tmp, pathname;

  glob.sync(globPath).forEach(function (entry) {
    basename = path.basename(entry, path.extname(entry));
    tmp = entry.split('/').splice(-3);
    pathname = tmp.splice(0, 1) + '/' + basename; // 正确输出js和html的路径
    entries[pathname] = entry;
  });

  return entries;
}

// add hot-reload related code to entry chunks
Object.keys(baseWebpackConfig.entry).forEach(function (name) {
  baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
})

module.exports = merge(baseWebpackConfig, {
  module: {
    loaders: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
  },
  // eval-source-map is faster for development
  devtool: '#eval-source-map',
  resolve: {
    alias: {
      'env': path.resolve(__dirname, '../config/dev.env.js')
    }
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': config.dev.env
    }),
    new InertToHTMLPlugin({
      paths: [path.posix.join(config.dev.assetsPublicPath, 'config/' + EnvName +'.js')]
    }),
    // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin(),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks: function (module, count) {
        // any required modules inside node_modules are extracted to vendor
        return (
          module.resource &&
          /\.js$/.test(module.resource) &&
          module.resource.indexOf(
            path.join(__dirname, '../node_modules')
          ) === 0
        )
      }
    })
    // https://github.com/ampedandwired/html-webpack-plugin
    // new HtmlWebpackPlugin({
    //   filename: 'index.html',
    //   template: 'index.html',
    //   inject: true
    // })
  ]
});

// var pages = getEntry('./src/module/**/*.html');
var pages = module.exports.entry;

for (var pathname in pages) {
    // 配置生成的html文件，定义路径等
    var conf = {
      filename: pathname + '.html',
      // template: pages[pathname],   // 模板路径
      template: './index.html',   // 模板路径
      inject: true,              // js插入位置
      minify: {
        //removeComments: true,
        //collapseWhitespace: true,
        //removeAttributeQuotes: true
      },
      // necessary to consistently work with multiple chunks via CommonsChunkPlugin
      // chunksSortMode: 'dependency'
    };

    if (/^module\//.test(pathname)) {
      conf.chunks = ['vendor','app', pathname];
      // conf.hash = true;
      module.exports.plugins.push(new HtmlWebpackPlugin(conf));
    }

  }
<commit_msg>修改打包依赖模式<commit_after>var config = require('../config')
var webpack = require('webpack')
var merge = require('webpack-merge')
var utils = require('./utils')
var baseWebpackConfig = require('./webpack.base.conf')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var InertToHTMLPlugin = require('./webpack.plugin.insertToHtml')
var glob = require('glob');
var path = require('path');

var args = process.argv;
var EnvName = args[2].replace('-env=', '');// 环境名称，如: prd | stg | dev ...
console.log('EnvName:' + EnvName);

function getEntry(globPath) {
  var entries = {},
    basename, tmp, pathname;

  glob.sync(globPath).forEach(function (entry) {
    basename = path.basename(entry, path.extname(entry));
    tmp = entry.split('/').splice(-3);
    pathname = tmp.splice(0, 1) + '/' + basename; // 正确输出js和html的路径
    entries[pathname] = entry;
  });

  return entries;
}

// add hot-reload related code to entry chunks
Object.keys(baseWebpackConfig.entry).forEach(function (name) {
  baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name])
})

module.exports = merge(baseWebpackConfig, {
  module: {
    loaders: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
  },
  // eval-source-map is faster for development
  devtool: '#eval-source-map',
  resolve: {
    alias: {
      'env': path.resolve(__dirname, '../config/dev.env.js')
    }
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': config.dev.env
    }),
    new InertToHTMLPlugin({
      paths: [path.posix.join(config.dev.assetsPublicPath, 'config/' + EnvName +'.js')]
    }),
    // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin(),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks: function (module, count) {
        // any required modules inside node_modules are extracted to vendor
        return (
          module.resource &&
          /\.js$/.test(module.resource) &&
          module.resource.indexOf(
            path.join(__dirname, '../node_modules')
          ) === 0
        )
      }
    })
    // https://github.com/ampedandwired/html-webpack-plugin
    // new HtmlWebpackPlugin({
    //   filename: 'index.html',
    //   template: 'index.html',
    //   inject: true
    // })
  ]
});

// var pages = getEntry('./src/module/**/*.html');
var pages = module.exports.entry;

for (var pathname in pages) {
    // 配置生成的html文件，定义路径等
    var conf = {
      filename: pathname + '.html',
      // template: pages[pathname],   // 模板路径
      template: './index.html',   // 模板路径
      inject: true,              // js插入位置
      minify: {
        //removeComments: true,
        //collapseWhitespace: true,
        //removeAttributeQuotes: true
      },
      // necessary to consistently work with multiple chunks via CommonsChunkPlugin
      chunksSortMode: 'dependency'
    };

    if (/^module\//.test(pathname)) {
      conf.chunks = ['vendor','app', pathname];
      // conf.hash = true;
      module.exports.plugins.push(new HtmlWebpackPlugin(conf));
    }

  }
<|endoftext|>


<commit_before>"use strict";

var NodeSurface = require("../node/node_surface");
var SurfaceComponent = require("../node/surface_component");

var TextSurface = function(node, surfaceProvider, options) {
  NodeSurface.call(this, node, surfaceProvider);
  options = options || {};
  var self = this;

  this.property = options.property || "content";

  if (self.node[self.property] === undefined) {
    throw new Error("Illegal property", self.node, self.property);
  }

  // default implementation for component.length
  options.length = options.length || function() {
    return self.node[self.property].length + 1;
  };

  var component = new SurfaceComponent(this, options.root || node, [node.id, self.property], options);

  if (options.property) {
    // HACK: this does not work for arbitrarily nested views
    component.__getElement__ = function() {
      return self.view.childViews[self.property].el;
    };
  } else {
    component.__getElement__ = function() {
      return self.view.el;
    };
  }

  this.components.push(component);
};

// This surface has not been refactored. We simply override the default implementation
// and use the existing implementation.
TextSurface.Prototype = function() {

  this.getCharPosition = function(el, offset) {
    if (!this.view) {
      throw new Error("No view attached.");
    }

    // Bootstrapping: cases that happened with empty text node.
    // In these cases we return charPos = 0
    if (this.view._fragments.length === 0 || el === this.view._fragments[0].el.parentElement) {
      return 0;
    }

    // Otherwise find the correct TEXT element
    var frag;
    for (var i = 0; i < this.view._fragments.length; i++) {
      var f = this.view._fragments[i];
      if (f.el === el) {
        frag = f;
        break;
      }
    }

    if (!frag) {
      console.error("AAAAArg", el);
      throw new Error("Could not lookup text element.");
    }

    var charPos = frag.charPos + offset;
    return charPos;
  };

  // Returns the corresponding DOM element position for the given character
  // --------
  //
  // A DOM position is specified by a tuple of element and offset.
  // In the case of text nodes it is a TEXT element.

  this.getDOMPosition = function(charPos) {
    if (!this.view) {
      throw new Error("No view attached.");
    }
    var result = this.view._lookupPostion(charPos);
    var frag = result[0];
    var offset = result[1];

    var range = window.document.createRange();
    range.setStart(frag.el, offset);
    return range;
  };

  this.getComponent = function() {
    return this.components[0];
  };
};
TextSurface.Prototype.prototype = NodeSurface.prototype;
TextSurface.prototype = new TextSurface.Prototype();

// A helper which turned out to be useful for editable textish properties
// --------
// The node view must provide a corresponding view under `childViews[property]`

TextSurface.textProperty = function(nodeSurface, property, options) {
  options = options || {};

  // propagate the root node
  options.root = options.root || nodeSurface.node;
  options.name = property;

  var node = nodeSurface.node;

  if (options.path) {
    node = nodeSurface.node.document.get(options.path[0]);
    options.alias = [nodeSurface.node.id, property];
  } else {
    options.property = property;
  }

  var propertySurface = new TextSurface(node, nodeSurface.surfaceProvider, options);
  var propertyComponent = propertySurface.components[0];
  return propertyComponent;
};

module.exports = TextSurface;
<commit_msg>No need for the text length hack in general.<commit_after>"use strict";

var NodeSurface = require("../node/node_surface");
var SurfaceComponent = require("../node/surface_component");

var TextSurface = function(node, surfaceProvider, options) {
  NodeSurface.call(this, node, surfaceProvider);
  options = options || {};
  var self = this;

  this.property = options.property || "content";

  if (self.node[self.property] === undefined) {
    throw new Error("Illegal property", self.node, self.property);
  }

  // default implementation for component.length
  options.length = options.length || function() {
    return self.node[self.property].length;
  };

  var component = new SurfaceComponent(this, options.root || node, [node.id, self.property], options);

  if (options.property) {
    // HACK: this does not work for arbitrarily nested views
    component.__getElement__ = function() {
      return self.view.childViews[self.property].el;
    };
  } else {
    component.__getElement__ = function() {
      return self.view.el;
    };
  }

  this.components.push(component);
};

// This surface has not been refactored. We simply override the default implementation
// and use the existing implementation.
TextSurface.Prototype = function() {

  this.getCharPosition = function(el, offset) {
    if (!this.view) {
      throw new Error("No view attached.");
    }

    // Bootstrapping: cases that happened with empty text node.
    // In these cases we return charPos = 0
    if (this.view._fragments.length === 0 || el === this.view._fragments[0].el.parentElement) {
      return 0;
    }

    // Otherwise find the correct TEXT element
    var frag;
    for (var i = 0; i < this.view._fragments.length; i++) {
      var f = this.view._fragments[i];
      if (f.el === el) {
        frag = f;
        break;
      }
    }

    if (!frag) {
      console.error("AAAAArg", el);
      throw new Error("Could not lookup text element.");
    }

    var charPos = frag.charPos + offset;
    return charPos;
  };

  // Returns the corresponding DOM element position for the given character
  // --------
  //
  // A DOM position is specified by a tuple of element and offset.
  // In the case of text nodes it is a TEXT element.

  this.getDOMPosition = function(charPos) {
    if (!this.view) {
      throw new Error("No view attached.");
    }
    var result = this.view._lookupPostion(charPos);
    var frag = result[0];
    var offset = result[1];

    var range = window.document.createRange();
    range.setStart(frag.el, offset);
    return range;
  };

  this.getComponent = function() {
    return this.components[0];
  };
};
TextSurface.Prototype.prototype = NodeSurface.prototype;
TextSurface.prototype = new TextSurface.Prototype();

// A helper which turned out to be useful for editable textish properties
// --------
// The node view must provide a corresponding view under `childViews[property]`

TextSurface.textProperty = function(nodeSurface, property, options) {
  options = options || {};

  // propagate the root node
  options.root = options.root || nodeSurface.node;
  options.name = property;

  var node = nodeSurface.node;

  if (options.path) {
    node = nodeSurface.node.document.get(options.path[0]);
    options.alias = [nodeSurface.node.id, property];
  } else {
    options.property = property;
  }

  var propertySurface = new TextSurface(node, nodeSurface.surfaceProvider, options);
  var propertyComponent = propertySurface.components[0];
  return propertyComponent;
};

module.exports = TextSurface;
<|endoftext|>


<commit_before>import test from 'tape';

import candela from '..';

const componentList = [
  'BarChart',
  'BoxPlot',
  'BulletChart',
  'GanttChart',
  'Heatmap',
  'Histogram',
  'LineChart',
  'LineUp',
  'ParallelCoordinates',
  'ScatterPlot',
  'ScatterPlotMatrix',
  'UpSet'
];

function componentExists (t, cd, name) {
  const component = cd.components[name];

  t.ok(component, `candela.components.${name} exists`);
  t.equal(typeof component, 'function', `candela.components.${name} is a function`);
}

function structureTests (t, cd) {
  t.ok(cd, 'candela exists');

  t.ok(cd.VisComponent, 'candela.VisComponent exists');

  t.ok(cd.VisComponent.VisComponent, 'candela.VisComponent.VisComponent exists');
  t.equal(typeof cd.VisComponent.VisComponent, 'function', 'candela.VisComponent.VisComponent is a function');

  t.ok(cd.components, 'candela.components exists');

  t.equal(Object.keys(cd.components).length, componentList.length, `candela.components contains ${componentList.length} components`);

  componentList.forEach(name => {
    componentExists(t, cd, name);
  });
}

test('Structure and content of exported Candela library object', t => {
  structureTests(t, candela);
  t.end();
});

test('Structure and content of unminified Candela library file', t => {
  try {
    let candelaBuilt = require('../../../build/candela/candela.js');
    t.ok(candelaBuilt, 'The built candela.js file exists');

    if (candelaBuilt) {
      structureTests(t, candelaBuilt);
    }
  } catch (e) {
    t.skip('Built candela.js file does not exist');
  }

  t.end();
});
<commit_msg>Name Geo in list of components to test existence<commit_after>import test from 'tape';

import candela from '..';

const componentList = [
  'BarChart',
  'BoxPlot',
  'BulletChart',
  'GanttChart',
  'Geo',
  'Heatmap',
  'Histogram',
  'LineChart',
  'LineUp',
  'ParallelCoordinates',
  'ScatterPlot',
  'ScatterPlotMatrix',
  'UpSet'
];

function componentExists (t, cd, name) {
  const component = cd.components[name];

  t.ok(component, `candela.components.${name} exists`);
  t.equal(typeof component, 'function', `candela.components.${name} is a function`);
}

function structureTests (t, cd) {
  t.ok(cd, 'candela exists');

  t.ok(cd.VisComponent, 'candela.VisComponent exists');

  t.ok(cd.VisComponent.VisComponent, 'candela.VisComponent.VisComponent exists');
  t.equal(typeof cd.VisComponent.VisComponent, 'function', 'candela.VisComponent.VisComponent is a function');

  t.ok(cd.components, 'candela.components exists');

  t.equal(Object.keys(cd.components).length, componentList.length, `candela.components contains ${componentList.length} components`);

  componentList.forEach(name => {
    componentExists(t, cd, name);
  });
}

test('Structure and content of exported Candela library object', t => {
  structureTests(t, candela);
  t.end();
});

test('Structure and content of unminified Candela library file', t => {
  try {
    let candelaBuilt = require('../../../build/candela/candela.js');
    t.ok(candelaBuilt, 'The built candela.js file exists');

    if (candelaBuilt) {
      structureTests(t, candelaBuilt);
    }
  } catch (e) {
    t.skip('Built candela.js file does not exist');
  }

  t.end();
});
<|endoftext|>


<commit_before>var fs = require('fs'),
  path = require('path'),
  mkdirp = require('mkdirp'),
  webpack = require('webpack'),
  ExtractTextPlugin = require('extract-text-webpack-plugin')

module.exports = function buildWebpackConfig (options) {
  options = options || {}

  var ENV = options.ENV || process.env.NODE_ENV || 'development',
    BUILD = options.BUILD || process.env.BUILD

  // shared values
  var publicPath = BUILD ? '/assets/' : 'http://localhost:8080/assets/'
  var outputPath = __dirname + '/public/assets'

  // base
  var config = {
    entry: {
      bshed: './client'
    },

    output: {
      path: outputPath,
      pathinfo: !BUILD,
      publicPath: publicPath,
      filename: '[name].[hash].js',
      chunkFilename: '[id].[hash].js'
    },

    target: 'web',

    devtool: BUILD ? 'source-map' : 'eval',

    externals: [],
    module: {
      loaders: [{
        test: /\.(png|jpg|jpeg|gif|svg)$/,
        loader: BUILD ? 'url?limit=10000' : 'url'
      }, {
        test: /\.(woff)$/,
        loader: BUILD ? 'url?limit=100000' : 'url'
      }, {
        test: /\.(ttf|eot)$/,
        loader: 'file'
      }]
    },
    resolve: {
      extensions: ['', '.js', '.jsx', '.less']
    },
    plugins: [
      StatsPlugin(),
      new webpack.DefinePlugin({
        'process.env.NODE_ENV': JSON.stringify(ENV)
      })
    ],
    devServer: {
      contentBase: './public',
      stats: {
        modules: false,
        cached: false,
        chunk: false
      }
    }
  }

  // loaders
  var babelLoader = 'babel?experimental&optional=runtime'
  config.module.loaders.push({
    test: /\.js$/,
    loader: babelLoader,
    exclude: /.*node_modules.*/
  })

  var hotLoader = BUILD ? '' : 'react-hot!'
  config.module.loaders.push({
    test: /\.jsx$/,
    loader: hotLoader + babelLoader,
    exclude: /.*node_modules.*((?!\.jsx).{4}$)/
  })

  var lessLoader = 'css?sourceMap!autoprefixer!less?sourceMap'
  config.module.loaders.push({
    test: /\.less$/,
    loader: BUILD ? ExtractTextPlugin.extract(lessLoader) : 'style!' + lessLoader
  })

  if (BUILD) {
    // Minifify, dedupe, extract css
    config.plugins.push(
      new ExtractTextPlugin('[name].[hash].css'),
      new webpack.NoErrorsPlugin(),
      new webpack.optimize.DedupePlugin(),
      new webpack.optimize.UglifyJsPlugin()
    )
  }

  return config

  function StatsPlugin () {
    return function () {
      this.plugin('done', saveStats)
    }

    function saveStats (stats) {
      var jsonStats = stats.toJson({
        chunks: false,
        modules: false
      })
      jsonStats.publicPath = publicPath
      mkdirp.sync(outputPath)
      fs.writeFileSync(path.join(outputPath, 'stats.json'), JSON.stringify(jsonStats))
    }
  }
}
<commit_msg>readability<commit_after>var fs = require('fs'),
  path = require('path'),
  mkdirp = require('mkdirp'),
  webpack = require('webpack'),
  ExtractTextPlugin = require('extract-text-webpack-plugin')

module.exports = function buildWebpackConfig (options) {
  options = options || {}

  var ENV = options.ENV || process.env.NODE_ENV || 'development',
    BUILD = options.BUILD || process.env.BUILD

  // shared values
  var publicPath = BUILD ? '/assets/' : 'http://localhost:8080/assets/'
  var outputPath = __dirname + '/public/assets'

  // base
  var config = {
    entry: {
      bshed: './client'
    },

    output: {
      path: outputPath,
      pathinfo: !BUILD,
      publicPath: publicPath,
      filename: '[name].[hash].js',
      chunkFilename: '[id].[hash].js'
    },

    target: 'web',

    devtool: BUILD ? 'source-map' : 'eval',

    externals: [],
    module: {
      loaders: [{
        test: /\.(png|jpg|jpeg|gif|svg)$/,
        loader: BUILD ? 'url?limit=10000' : 'url'
      }, {
        test: /\.(woff)$/,
        loader: BUILD ? 'url?limit=100000' : 'url'
      }, {
        test: /\.(ttf|eot)$/,
        loader: 'file'
      }]
    },
    resolve: {
      extensions: ['', '.js', '.jsx', '.less']
    },
    plugins: [
      StatsPlugin(),
      new webpack.DefinePlugin({
        'process.env.NODE_ENV': JSON.stringify(ENV)
      })
    ],
    devServer: {
      contentBase: './public',
      stats: {
        modules: false,
        cached: false,
        chunk: false
      }
    }
  }

  // loaders
  var babelLoader = 'babel?experimental&optional=runtime'
  config.module.loaders.push({
    test: /\.js$/,
    loader: babelLoader,
    exclude: /.*node_modules.*/
  })

  config.module.loaders.push({
    test: /\.jsx$/,
    loader: (BUILD ? '' : 'react-hot!') + babelLoader,
    exclude: /.*node_modules.*((?!\.jsx).{4}$)/
  })

  var lessLoader = 'css?sourceMap!autoprefixer!less?sourceMap'
  config.module.loaders.push({
    test: /\.less$/,
    loader: BUILD ? ExtractTextPlugin.extract(lessLoader) : 'style!' + lessLoader
  })

  if (BUILD) {
    // Minifify, dedupe, extract css
    config.plugins.push(
      new ExtractTextPlugin('[name].[hash].css'),
      new webpack.NoErrorsPlugin(),
      new webpack.optimize.DedupePlugin(),
      new webpack.optimize.UglifyJsPlugin()
    )
  }

  return config

  function StatsPlugin () {
    return function () {
      this.plugin('done', saveStats)
    }

    function saveStats (stats) {
      var jsonStats = stats.toJson({
        chunks: false,
        modules: false
      })
      jsonStats.publicPath = publicPath
      mkdirp.sync(outputPath)
      fs.writeFileSync(path.join(outputPath, 'stats.json'), JSON.stringify(jsonStats))
    }
  }
}
<|endoftext|>


<commit_before>import webpack from 'webpack';
import path from 'path';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import HtmlWebpackPlugin from 'html-webpack-plugin';

const config = {
    entry: [
        path.join(__dirname, '../', 'src', 'app'),
    ],

    output: {
        path: path.join(__dirname, '../', 'dist'),
        filename: 'js/[name]_[hash].js',
        publicPath: '/',
    },

    resolve: {
        extensions: ['.js', '.jsx', '.styl', '.css'],
    },

    module: {
        loaders: [
            {
                test: /\.styl$/,
                loader: ExtractTextPlugin.extract({
                    fallback: 'style-loader',
                    use: [
                        { loader: 'css-loader', options: { sourceMap: true } },
                        { loader: 'postcss-loader', options: { sourceMap: true, importLoaders: 1 } },
                        { loader: 'stylus-loader', options: { sourceMap: true } }
                    ],
                }),
            },
            {
                test: /\.(eot|woff2?|ttf)$/,
                loader: 'file-loader?limit=1024&name=/fonts/[name].[ext]',
            },

            {
                test: /\.(jpg|svg)$/,
                loader: 'file-loader?name=/images/[name].[ext]',
            },

            {
                test: /\.jsx?$/,
                loader: 'babel-loader',
                exclude: [/node_modules/, /src\/styles\/vendor/],
                query: {
                    presets: ['env', 'react', 'stage-0'],
                },
            },
        ],
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './index.html',
        }),
        new ExtractTextPlugin('css/[name]_[contenthash].css'),
    ],
};

export default { ...config };
<commit_msg>fix css loader<commit_after>import webpack from 'webpack';
import path from 'path';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import HtmlWebpackPlugin from 'html-webpack-plugin';

const config = {
    entry: [
        path.join(__dirname, '../', 'src', 'app'),
    ],

    output: {
        path: path.join(__dirname, '../', 'dist'),
        filename: 'js/[name]_[hash].js',
        publicPath: '/',
    },

    resolve: {
        extensions: ['.js', '.jsx', '.styl', '.css'],
    },

    module: {
        loaders: [
            {
                test: /\.styl$/,
                loader: ExtractTextPlugin.extract({
                    fallback: 'style-loader',
                    use: [
                        { loader: 'css-loader', options: { sourceMap: true, importLoaders: 1 } },
                        { loader: 'postcss-loader', options: { sourceMap: true } },
                        { loader: 'stylus-loader', options: { sourceMap: true } },
                    ],
                }),
            },
            {
                test: /\.(eot|woff2?|ttf)$/,
                loader: 'file-loader?limit=1024&name=/fonts/[name].[ext]',
            },

            {
                test: /\.(jpg|svg)$/,
                loader: 'file-loader?name=/images/[name].[ext]',
            },

            {
                test: /\.jsx?$/,
                loader: 'babel-loader',
                exclude: [/node_modules/, /src\/styles\/vendor/],
                query: {
                    presets: ['env', 'react', 'stage-0'],
                },
            },
        ],
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './index.html',
        }),
        new ExtractTextPlugin('css/[name]_[contenthash].css'),
    ],
};

export default { ...config };
<|endoftext|>