<commit_before>'use strict';

const checker = require('license-checker');
const versionHandler = require('../lib/version-handler.js');
const warnings = require('../lib/warnings.js');
const reader = require('../lib/file-reader.js');
const writer = require('../lib/file-writer.js');
const fs = require('fs');
const path = require('path');
const unifiedList = require('../lib/unified-list.js');

// Gets the project name, version and license from package.json.
const projectName = (options) => require(`${options.directory}/package.json`).name;
const projectVersion = (options) => require(`${options.directory}/package.json`).version;
const projectLicense = (options) => require(`${options.directory}/package.json`).license;

// Gets the project dependencies from package.json.
const projectDependencies = (options) => require(`${options.directory}/package.json`).dependencies;

let canonicalNameMapper;

// The generated XMl element will be like this example:
//  <license>
//    <name>roi</name>
//    <version>0.15.0</version>
//    <license>Apache-2.0</license>
//    <file> file content here. </file>
//  </license>
const entry = (info, dependency, options) => {
  const canonicalName = canonicalNameMapper.map(info.licenses);
  unifiedList.init(options);
  const url = unifiedList.urlForName(options, canonicalName);
  return {
    packageName: dependency.name,
    version: dependency.version,
    licenses: {
      license: [{
        name: canonicalName,
        url: options.verbose ? reader.readLicenseFile(info.licenseFile) : url
      }]
    }
  };
};

// This function will populate the licenses array with
// data based on the project's declared dependencies found
// inside json data of all dependencies.
// Also returns the json object xmlElement with the data found.
// The parameter 'identifier' can be a dependency
// nameVersion or a name. example: roi@1.2.3 or roi
function addLicenseEntry (xmlElement, identifier, json, options) {
  if (json.hasOwnProperty(identifier)) {
    // name and version object e.g. { name: 'roi', version: '1.2.3' }
    const nameVersion = versionHandler.fromNpmVersion(identifier);
    xmlElement.dependencies.dependency.push(entry(json[identifier], nameVersion, options));
  }
  return xmlElement;
}

// Same as addLicenseEntry but ignores the difference between the
// version declared on package.json and the version installed by npm.
function addLicenseEntryIgnoreVersionRange (xmlElement, identifier, json, options) {
  const name = identifier.split('@')[0];
  for (const key in json) {
    if (key.indexOf(name) > -1) {
      const nameVersion = versionHandler.fromNpmVersionIgnoreRange(identifier);
      xmlElement.dependencies.dependency.push(entry(json[key], nameVersion, options));
    }
  }
  return xmlElement;
}

// Returns an object that will represent the XML element.
const createXmlObject = (options) => {
  const xmlObject = {
    project: projectName(options),
    version: projectVersion(options)
  };
  if (options.metadata) {
    xmlObject.license = projectLicense(options);
  }
  xmlObject.dependencies = {dependency: []};
  return xmlObject;
};

// Gathers the licenses of the json for each
// dependency declared on the project.
// It is possible to choose between top level dependencies
// or all (including sub-modules -> options.alldeps) and
// populates the xml elements with the data found.
function xmlObjectData (options, declaredDependencies, json) {
  const xmlObject = createXmlObject(options);
  if (options.alldeps) {
    // the name and version e.g. roi@1.2.3
    for (const nameVersion in json) {
      addLicenseEntry(xmlObject, nameVersion, json, options);
    }
  } else {
    if (options.ignoreVersionRange) {
      for (const name in declaredDependencies) {
        const nameVersion = versionHandler.nameVersion(name, declaredDependencies[name]);
        addLicenseEntryIgnoreVersionRange(xmlObject, nameVersion, json, options);
      }
    } else {
      // name - is only the name e.g. roi and not roi@1.2.3
      for (const name in declaredDependencies) {
        const npmVersion = versionHandler.asNpmVersion(name, declaredDependencies[name]);
        addLicenseEntry(xmlObject, npmVersion, json, options);
      }
    }
  }
  return xmlObject;
}

// Shows warning messages if needed.
function showWarnings (options, declaredDependencies, xmlObject) {
  const unknown = require('../lib/unknown.js').check(xmlObject);
  const xmlObjectDependencies = xmlObject.dependencies.dependency.map(e => e.packageName);
  const missingDependencies = Object.keys(declaredDependencies)
                                    .filter(e1 => xmlObjectDependencies
                                    .filter(e2 => e2 === e1)
                                    .length === 0);
  if (missingDependencies.length > 0) {
    console.log(`Dependencies found in package.json but not in xml: ${missingDependencies.join(',')}`);
    console.log(`Please run 'license-reporter --ignore-version-range' to show all declared dependencies on generated xml.`);
  }
  warnings.print(unknown, 'UNKNOWN');
  unifiedList.init(options);
  unifiedList.check(options, xmlObject);
}

// This function will scan the license data.
function checkLicense (options, declaredDependencies) {
  // NOTE: The json argument will have all the license information
  // for each module and it's dependencies of the project.
  return new Promise((resolve, reject) => {
    checker.init({start: options.directory}, (error, json) => {
      if (error) {
        reject(error);
      } else {
        resolve(xmlObjectData(options, declaredDependencies, json));
      }
    });
  });
}

// Checks if node_modules exists and returns
// true if it is not empty not considering '.bin'
// directory.
const nodeModulesFound = (dir) => {
  const modulesDir = path.join(dir, 'node_modules');
  if (fs.existsSync(modulesDir)) {
    const content = fs.readdirSync(modulesDir).filter(e => e !== '.bin');
    if (content.length > 0) {
      return true;
    } else {
      return false;
    }
  } else {
    return false;
  }
};

// This function is the license's entry point
// to gather licenses. Also create the xml,
// print warnings and create html in case needed.
function run (options) {
  if (nodeModulesFound(options.directory)) {
    let mappings = [];
    if (options.nameMap) {
      mappings = reader.readAsJson(options.nameMap);
      if (mappings === null) {
        console.error('Could not find name map file: ', options.nameMap);
        process.exit(3);
      }
    }
    canonicalNameMapper = require('../lib/canonical-name.js')(mappings);
    if (options.merge) {
      writer.mergeXmls(options);
      return;
    }
    const declaredDependencies = projectDependencies(options);
    checkLicense(options, declaredDependencies)
    .then(xmlObject => {
      writer.createXml(options, xmlObject);
      if (!options.silent) {
        showWarnings(options, declaredDependencies, xmlObject);
      }
      if (options.html) {
        writer.createHtml(options, xmlObject);
      }
    }).catch(e => {
      console.error(e);
    });
  } else {
    const xmlObject = createXmlObject(options);
    xmlObject.license = projectLicense(options);
    writer.createXml(options, xmlObject);
  }
}

module.exports = {
  run
};
<commit_msg>fix: data duplication to the output. <commit_after>'use strict';

const checker = require('license-checker');
const versionHandler = require('../lib/version-handler.js');
const warnings = require('../lib/warnings.js');
const reader = require('../lib/file-reader.js');
const writer = require('../lib/file-writer.js');
const fs = require('fs');
const path = require('path');
const unifiedList = require('../lib/unified-list.js');

// Gets the project name, version and license from package.json.
const projectName = (options) => require(`${options.directory}/package.json`).name;
const projectVersion = (options) => require(`${options.directory}/package.json`).version;
const projectLicense = (options) => require(`${options.directory}/package.json`).license;

// Gets the project dependencies from package.json.
const projectDependencies = (options) => require(`${options.directory}/package.json`).dependencies;

let canonicalNameMapper;

// The generated XMl element will be like this example:
//  <license>
//    <name>roi</name>
//    <version>0.15.0</version>
//    <license>Apache-2.0</license>
//    <file> file content here. </file>
//  </license>
const entry = (info, dependency, options) => {
  const canonicalName = canonicalNameMapper.map(info.licenses);
  unifiedList.init(options);
  const url = unifiedList.urlForName(options, canonicalName);
  return {
    packageName: dependency.name,
    version: dependency.version,
    licenses: {
      license: [{
        name: canonicalName,
        url: options.verbose ? reader.readLicenseFile(info.licenseFile) : url
      }]
    }
  };
};

// This function will populate the licenses array with
// data based on the project's declared dependencies found
// inside json data of all dependencies.
// Also returns the json object xmlElement with the data found.
// The parameter 'identifier' can be a dependency
// nameVersion or a name. example: roi@1.2.3 or roi
function addLicenseEntry (xmlElement, identifier, json, options) {
  if (json.hasOwnProperty(identifier)) {
    // name and version object e.g. { name: 'roi', version: '1.2.3' }
    const nameVersion = versionHandler.fromNpmVersion(identifier);
    xmlElement.dependencies.dependency.push(entry(json[identifier], nameVersion, options));
  }
  return xmlElement;
}

// Same as addLicenseEntry but ignores the difference between the
// version declared on package.json and the version installed by npm.
function addLicenseEntryIgnoreVersionRange (xmlElement, identifier, json, options) {
  const name = identifier.split('@')[0];
  for (const key in json) {
    if (key.indexOf(name) > -1) {
      const nameVersion = versionHandler.fromNpmVersionIgnoreRange(identifier);
      xmlElement.dependencies.dependency.push(entry(json[key], nameVersion, options));
    }
  }
  xmlElement.dependencies.dependency = xmlElement.dependencies.dependency
  .filter((d, index, self) => self.findIndex((t) => {
    return t.version === d.version && t.licenses.license[0].name === d.licenses.license[0].name;
  }) === index);
  return xmlElement;
}

// Returns an object that will represent the XML element.
const createXmlObject = (options) => {
  const xmlObject = {
    project: projectName(options),
    version: projectVersion(options)
  };
  if (options.metadata) {
    xmlObject.license = projectLicense(options);
  }
  xmlObject.dependencies = {dependency: []};
  return xmlObject;
};

// Gathers the licenses of the json for each
// dependency declared on the project.
// It is possible to choose between top level dependencies
// or all (including sub-modules -> options.alldeps) and
// populates the xml elements with the data found.
function xmlObjectData (options, declaredDependencies, json) {
  const xmlObject = createXmlObject(options);
  if (options.alldeps) {
    // the name and version e.g. roi@1.2.3
    for (const nameVersion in json) {
      addLicenseEntry(xmlObject, nameVersion, json, options);
    }
  } else {
    if (options.ignoreVersionRange) {
      for (const name in declaredDependencies) {
        const nameVersion = versionHandler.nameVersion(name, declaredDependencies[name]);
        addLicenseEntryIgnoreVersionRange(xmlObject, nameVersion, json, options);
      }
    } else {
      // name - is only the name e.g. roi and not roi@1.2.3
      for (const name in declaredDependencies) {
        const npmVersion = versionHandler.asNpmVersion(name, declaredDependencies[name]);
        addLicenseEntry(xmlObject, npmVersion, json, options);
      }
    }
  }
  return xmlObject;
}

// Shows warning messages if needed.
function showWarnings (options, declaredDependencies, xmlObject) {
  const unknown = require('../lib/unknown.js').check(xmlObject);
  const xmlObjectDependencies = xmlObject.dependencies.dependency.map(e => e.packageName);
  const missingDependencies = Object.keys(declaredDependencies)
                                    .filter(e1 => xmlObjectDependencies
                                    .filter(e2 => e2 === e1)
                                    .length === 0);
  if (missingDependencies.length > 0 && !options.ignoreVersionRange) {
    console.log(`Dependencies found in package.json but not in xml: ${missingDependencies.join(',')}`);
    console.log(`Please run 'license-reporter --ignore-version-range' to show all declared dependencies on generated xml.`);
  }
  warnings.print(unknown, 'UNKNOWN');
  unifiedList.init(options);
  unifiedList.check(options, xmlObject);
}

// This function will scan the license data.
function checkLicense (options, declaredDependencies) {
  // NOTE: The json argument will have all the license information
  // for each module and it's dependencies of the project.
  return new Promise((resolve, reject) => {
    checker.init({start: options.directory}, (error, json) => {
      if (error) {
        reject(error);
      } else {
        resolve(xmlObjectData(options, declaredDependencies, json));
      }
    });
  });
}

// Checks if node_modules exists and returns
// true if it is not empty not considering '.bin'
// directory.
const nodeModulesFound = (dir) => {
  const modulesDir = path.join(dir, 'node_modules');
  if (fs.existsSync(modulesDir)) {
    const content = fs.readdirSync(modulesDir).filter(e => e !== '.bin');
    if (content.length > 0) {
      return true;
    } else {
      return false;
    }
  } else {
    return false;
  }
};

// This function is the license's entry point
// to gather licenses. Also create the xml,
// print warnings and create html in case needed.
function run (options) {
  if (nodeModulesFound(options.directory)) {
    let mappings = [];
    if (options.nameMap) {
      mappings = reader.readAsJson(options.nameMap);
      if (mappings === null) {
        console.error('Could not find name map file: ', options.nameMap);
        process.exit(3);
      }
    }
    canonicalNameMapper = require('../lib/canonical-name.js')(mappings);
    if (options.merge) {
      writer.mergeXmls(options);
      return;
    }
    const declaredDependencies = projectDependencies(options);
    checkLicense(options, declaredDependencies)
    .then(xmlObject => {
      writer.createXml(options, xmlObject);
      if (!options.silent) {
        showWarnings(options, declaredDependencies, xmlObject);
      }
      if (options.html) {
        writer.createHtml(options, xmlObject);
      }
    }).catch(e => {
      console.error(e);
    });
  } else {
    const xmlObject = createXmlObject(options);
    xmlObject.license = projectLicense(options);
    writer.createXml(options, xmlObject);
  }
}

module.exports = {
  run
};
<|endoftext|>


<commit_before>#!/usr/bin/env node

/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

const { NON_COMPILATION_ARGS } = require("./utils/constants");

(function() {
	// wrap in IIFE to be able to use return

	const importLocal = require("import-local");
	// Prefer the local installation of webpack-cli
	if (importLocal(__filename)) {
		return;
	}

	require("v8-compile-cache");

	const ErrorHelpers = require("./utils/errorHelpers");

	const NON_COMPILATION_CMD = process.argv.find(arg => {
		if (arg === "serve") {
			global.process.argv = global.process.argv.filter(a => a !== "serve");
			process.argv = global.process.argv;
		}
		return NON_COMPILATION_ARGS.find(a => a === arg);
	});

	if (NON_COMPILATION_CMD) {
		return require("./utils/prompt-command")(NON_COMPILATION_CMD, ...process.argv);
	}

	const yargs = require("yargs").usage(`webpack-cli ${require("../package.json").version}

Usage: webpack-cli [options]
       webpack-cli [options] --entry <entry> --output <output>
       webpack-cli [options] <entries...> --output <output>
       webpack-cli <command> [options]

For more information, see https://webpack.js.org/api/cli/.`);

	require("./config/config-yargs")(yargs);

	// yargs will terminate the process early when the user uses help or version.
	// This causes large help outputs to be cut short (https://github.com/nodejs/node/wiki/API-changes-between-v0.10-and-v4#process).
	// To prevent this we use the yargs.parse API and exit the process normally
	yargs.parse(process.argv.slice(2), (err, argv, output) => {
		Error.stackTraceLimit = 30;

		// arguments validation failed
		if (err && output) {
			console.error(output);
			process.exitCode = 1;
			return;
		}

		// help or version info
		if (output) {
			console.log(output);
			return;
		}

		if (argv.verbose) {
			argv["display"] = "verbose";
		}

		let options;
		try {
			options = require("./utils/convert-argv")(argv);
		} catch (err) {
			if (err.name !== "ValidationError") {
				throw err;
			}

			const stack = ErrorHelpers.cleanUpWebpackOptions(err.stack, err.message);
			const message = err.message + "\n" + stack;

			if (argv.color) {
				console.error(`\u001b[1m\u001b[31m${message}\u001b[39m\u001b[22m`);
			} else {
				console.error(message);
			}

			process.exitCode = 1;
			return;
		}

		/**
		 * When --silent flag is present, an object with a no-op write method is
		 * used in place of process.stout
		 */
		const stdout = argv.silent
			? {
				write: () => {}
			  } // eslint-disable-line
			: process.stdout;

		function ifArg(name, fn, init) {
			if (Array.isArray(argv[name])) {
				if (init) init();
				argv[name].forEach(fn);
			} else if (typeof argv[name] !== "undefined") {
				if (init) init();
				fn(argv[name], -1);
			}
		}

		function processOptions(options) {
			// process Promise
			if (typeof options.then === "function") {
				options.then(processOptions).catch(function(err) {
					console.error(err.stack || err);
					process.exit(1); // eslint-disable-line
				});
				return;
			}

			const firstOptions = [].concat(options)[0];
			const statsPresetToOptions = require("webpack").Stats.presetToOptions;

			let outputOptions = options.stats;
			if (typeof outputOptions === "boolean" || typeof outputOptions === "string") {
				outputOptions = statsPresetToOptions(outputOptions);
			} else if (!outputOptions) {
				outputOptions = {};
			}

			ifArg("display", function(preset) {
				outputOptions = statsPresetToOptions(preset);
			});

			outputOptions = Object.create(outputOptions);
			if (Array.isArray(options) && !outputOptions.children) {
				outputOptions.children = options.map(o => o.stats);
			}
			if (typeof outputOptions.context === "undefined") outputOptions.context = firstOptions.context;

			ifArg("env", function(value) {
				if (outputOptions.env) {
					outputOptions._env = value;
				}
			});

			ifArg("json", function(bool) {
				if (bool) {
					outputOptions.json = bool;
					outputOptions.modules = bool;
				}
			});

			if (typeof outputOptions.colors === "undefined") outputOptions.colors = require("supports-color").stdout;

			ifArg("sort-modules-by", function(value) {
				outputOptions.modulesSort = value;
			});

			ifArg("sort-chunks-by", function(value) {
				outputOptions.chunksSort = value;
			});

			ifArg("sort-assets-by", function(value) {
				outputOptions.assetsSort = value;
			});

			ifArg("display-exclude", function(value) {
				outputOptions.exclude = value;
			});

			if (!outputOptions.json) {
				if (typeof outputOptions.cached === "undefined") outputOptions.cached = false;
				if (typeof outputOptions.cachedAssets === "undefined") outputOptions.cachedAssets = false;

				ifArg("display-chunks", function(bool) {
					if (bool) {
						outputOptions.modules = false;
						outputOptions.chunks = true;
						outputOptions.chunkModules = true;
					}
				});

				ifArg("display-entrypoints", function(bool) {
					outputOptions.entrypoints = bool;
				});

				ifArg("display-reasons", function(bool) {
					if (bool) outputOptions.reasons = true;
				});

				ifArg("display-depth", function(bool) {
					if (bool) outputOptions.depth = true;
				});

				ifArg("display-used-exports", function(bool) {
					if (bool) outputOptions.usedExports = true;
				});

				ifArg("display-provided-exports", function(bool) {
					if (bool) outputOptions.providedExports = true;
				});

				ifArg("display-optimization-bailout", function(bool) {
					if (bool) outputOptions.optimizationBailout = bool;
				});

				ifArg("display-error-details", function(bool) {
					if (bool) outputOptions.errorDetails = true;
				});

				ifArg("display-origins", function(bool) {
					if (bool) outputOptions.chunkOrigins = true;
				});

				ifArg("display-max-modules", function(value) {
					outputOptions.maxModules = +value;
				});

				ifArg("display-cached", function(bool) {
					if (bool) outputOptions.cached = true;
				});

				ifArg("display-cached-assets", function(bool) {
					if (bool) outputOptions.cachedAssets = true;
				});

				if (!outputOptions.exclude) outputOptions.exclude = ["node_modules", "bower_components", "components"];

				if (argv["display-modules"]) {
					outputOptions.maxModules = Infinity;
					outputOptions.exclude = undefined;
					outputOptions.modules = true;
				}
			}

			ifArg("hide-modules", function(bool) {
				if (bool) {
					outputOptions.modules = false;
					outputOptions.chunkModules = false;
				}
			});

			ifArg("info-verbosity", function(value) {
				outputOptions.infoVerbosity = value;
			});

			ifArg("build-delimiter", function(value) {
				outputOptions.buildDelimiter = value;
			});

			const webpack = require("webpack");

			let lastHash = null;
			let compiler;
			try {
				compiler = webpack(options);
			} catch (err) {
				if (err.name === "WebpackOptionsValidationError") {
					if (argv.color) console.error(`\u001b[1m\u001b[31m${err.message}\u001b[39m\u001b[22m`);
					else console.error(err.message);
					// eslint-disable-next-line no-process-exit
					process.exit(1);
				}

				throw err;
			}

			if (argv.progress) {
				const ProgressPlugin = require("webpack").ProgressPlugin;
				new ProgressPlugin({
					profile: argv.profile
				}).apply(compiler);
			}
			if (outputOptions.infoVerbosity === "verbose") {
				if (argv.w) {
					compiler.hooks.watchRun.tap("WebpackInfo", compilation => {
						const compilationName = compilation.name ? compilation.name : "";
						console.error("\nCompilation " + compilationName + " starting…\n");
					});
				} else {
					compiler.hooks.beforeRun.tap("WebpackInfo", compilation => {
						const compilationName = compilation.name ? compilation.name : "";
						console.error("\nCompilation " + compilationName + " starting…\n");
					});
				}
				compiler.hooks.done.tap("WebpackInfo", compilation => {
					const compilationName = compilation.name ? compilation.name : "";
					console.error("\nCompilation " + compilationName + " finished\n");
				});
			}

			function compilerCallback(err, stats) {
				if (!options.watch || err) {
					// Do not keep cache anymore
					compiler.purgeInputFileSystem();
				}
				if (err) {
					lastHash = null;
					console.error(err.stack || err);
					if (err.details) console.error(err.details);
					process.exit(1); // eslint-disable-line
				}
				if (outputOptions.json) {
					stdout.write(JSON.stringify(stats.toJson(outputOptions), null, 2) + "\n");
				} else if (stats.hash !== lastHash) {
					lastHash = stats.hash;
					if (stats.compilation && stats.compilation.errors.length !== 0) {
						const errors = stats.compilation.errors;
						if (errors[0].name === "EntryModuleNotFoundError") {
							console.error("\n\u001b[1m\u001b[31mInsufficient number of arguments or no entry found.");
							console.error(
								"\u001b[1m\u001b[31mAlternatively, run 'webpack(-cli) --help' for usage info.\u001b[39m\u001b[22m\n"
							);
						}
					}
					const statsString = stats.toString(outputOptions);
					const delimiter = outputOptions.buildDelimiter ? `${outputOptions.buildDelimiter}\n` : "";
					if (statsString) stdout.write(`${statsString}\n${delimiter}`);

					/**
					 * Show a hint to donate to our Opencollective
					 * once a week, only on Monday
					 */
					const openCollectivePath = __dirname + "/opencollective.js";
					const MONDAY = 1;
					const SIX_DAYS = 518400000;
					const now = new Date();
					if (now.getDay() === MONDAY) {
						const { statSync, utimesSync } = require("fs");
						const lastPrint = statSync(openCollectivePath).atime;
						const lastPrintTS = new Date(lastPrint).getTime();
						const timeSinceLastPrint = now.getTime() - lastPrintTS;
						if (timeSinceLastPrint > SIX_DAYS) {
							require(openCollectivePath);
							// On windows we need to manually update the atime
							utimesSync(openCollectivePath, now, now);
						}
					}
				}
				if (!options.watch && stats.hasErrors()) {
					process.exitCode = 2;
				}
			}
			if (firstOptions.watch || options.watch) {
				const watchOptions = firstOptions.watchOptions || firstOptions.watch || options.watch || {};
				if (watchOptions.stdin) {
					process.stdin.on("end", function(_) {
						process.exit(); // eslint-disable-line
					});
					process.stdin.resume();
				}
				compiler.watch(watchOptions, compilerCallback);
				if (outputOptions.infoVerbosity !== "none") console.error("\nwebpack is watching the files…\n");
			} else {
				compiler.run((err, stats) => {
					if (compiler.close) {
						compiler.close(err2 => {
							compilerCallback(err || err2, stats);
						});
					} else {
						compilerCallback(err, stats);
					}
				});
			}
		}
		processOptions(options);
	});
})();
<commit_msg>fix(cli): error when no webpack and args found<commit_after>#!/usr/bin/env node

/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

const { NON_COMPILATION_ARGS } = require("./utils/constants");

(function() {
	// wrap in IIFE to be able to use return

	const importLocal = require("import-local");
	// Prefer the local installation of webpack-cli
	if (importLocal(__filename)) {
		return;
	}

	require("v8-compile-cache");

	const ErrorHelpers = require("./utils/errorHelpers");

	const NON_COMPILATION_CMD = process.argv.find(arg => {
		if (arg === "serve") {
			global.process.argv = global.process.argv.filter(a => a !== "serve");
			process.argv = global.process.argv;
		}
		return NON_COMPILATION_ARGS.find(a => a === arg);
	});

	if (NON_COMPILATION_CMD) {
		return require("./utils/prompt-command")(NON_COMPILATION_CMD, ...process.argv);
	}

	const yargs = require("yargs").usage(`webpack-cli ${require("../package.json").version}

Usage: webpack-cli [options]
       webpack-cli [options] --entry <entry> --output <output>
       webpack-cli [options] <entries...> --output <output>
       webpack-cli <command> [options]

For more information, see https://webpack.js.org/api/cli/.`);

	require("./config/config-yargs")(yargs);

	// yargs will terminate the process early when the user uses help or version.
	// This causes large help outputs to be cut short (https://github.com/nodejs/node/wiki/API-changes-between-v0.10-and-v4#process).
	// To prevent this we use the yargs.parse API and exit the process normally
	yargs.parse(process.argv.slice(2), (err, argv, output) => {
		Error.stackTraceLimit = 30;

		// arguments validation failed
		if (err && output) {
			console.error(output);
			process.exitCode = 1;
			return;
		}

		// help or version info
		if (output) {
			console.log(output);
			return;
		}

		if (argv.verbose) {
			argv["display"] = "verbose";
		}

		let options;
		try {
			options = require("./utils/convert-argv")(argv);
		} catch (err) {
			if (err.name !== "ValidationError") {
				console.error("\n\u001b[1m\u001b[31mWebpack not found, please install webpack");
				console.error(
					"\u001b[1m\u001b[31mAlternatively, run 'webpack(-cli) --help' for usage info.\u001b[39m\u001b[22m\n"
				);
				process.exitCode = 1;
				return;
			}

			const stack = ErrorHelpers.cleanUpWebpackOptions(err.stack, err.message);
			const message = err.message + "\n" + stack;

			if (argv.color) {
				console.error(`\u001b[1m\u001b[31m${message}\u001b[39m\u001b[22m`);
			} else {
				console.error(message);
			}

			process.exitCode = 1;
			return;
		}

		/**
		 * When --silent flag is present, an object with a no-op write method is
		 * used in place of process.stout
		 */
		const stdout = argv.silent
			? {
					write: () => {}
			  } // eslint-disable-line
			: process.stdout;

		function ifArg(name, fn, init) {
			if (Array.isArray(argv[name])) {
				if (init) init();
				argv[name].forEach(fn);
			} else if (typeof argv[name] !== "undefined") {
				if (init) init();
				fn(argv[name], -1);
			}
		}

		function processOptions(options) {
			// process Promise
			if (typeof options.then === "function") {
				options.then(processOptions).catch(function(err) {
					console.error(err.stack || err);
					process.exit(1); // eslint-disable-line
				});
				return;
			}

			const firstOptions = [].concat(options)[0];
			const statsPresetToOptions = require("webpack").Stats.presetToOptions;

			let outputOptions = options.stats;
			if (typeof outputOptions === "boolean" || typeof outputOptions === "string") {
				outputOptions = statsPresetToOptions(outputOptions);
			} else if (!outputOptions) {
				outputOptions = {};
			}

			ifArg("display", function(preset) {
				outputOptions = statsPresetToOptions(preset);
			});

			outputOptions = Object.create(outputOptions);
			if (Array.isArray(options) && !outputOptions.children) {
				outputOptions.children = options.map(o => o.stats);
			}
			if (typeof outputOptions.context === "undefined") outputOptions.context = firstOptions.context;

			ifArg("env", function(value) {
				if (outputOptions.env) {
					outputOptions._env = value;
				}
			});

			ifArg("json", function(bool) {
				if (bool) {
					outputOptions.json = bool;
					outputOptions.modules = bool;
				}
			});

			if (typeof outputOptions.colors === "undefined") outputOptions.colors = require("supports-color").stdout;

			ifArg("sort-modules-by", function(value) {
				outputOptions.modulesSort = value;
			});

			ifArg("sort-chunks-by", function(value) {
				outputOptions.chunksSort = value;
			});

			ifArg("sort-assets-by", function(value) {
				outputOptions.assetsSort = value;
			});

			ifArg("display-exclude", function(value) {
				outputOptions.exclude = value;
			});

			if (!outputOptions.json) {
				if (typeof outputOptions.cached === "undefined") outputOptions.cached = false;
				if (typeof outputOptions.cachedAssets === "undefined") outputOptions.cachedAssets = false;

				ifArg("display-chunks", function(bool) {
					if (bool) {
						outputOptions.modules = false;
						outputOptions.chunks = true;
						outputOptions.chunkModules = true;
					}
				});

				ifArg("display-entrypoints", function(bool) {
					outputOptions.entrypoints = bool;
				});

				ifArg("display-reasons", function(bool) {
					if (bool) outputOptions.reasons = true;
				});

				ifArg("display-depth", function(bool) {
					if (bool) outputOptions.depth = true;
				});

				ifArg("display-used-exports", function(bool) {
					if (bool) outputOptions.usedExports = true;
				});

				ifArg("display-provided-exports", function(bool) {
					if (bool) outputOptions.providedExports = true;
				});

				ifArg("display-optimization-bailout", function(bool) {
					if (bool) outputOptions.optimizationBailout = bool;
				});

				ifArg("display-error-details", function(bool) {
					if (bool) outputOptions.errorDetails = true;
				});

				ifArg("display-origins", function(bool) {
					if (bool) outputOptions.chunkOrigins = true;
				});

				ifArg("display-max-modules", function(value) {
					outputOptions.maxModules = +value;
				});

				ifArg("display-cached", function(bool) {
					if (bool) outputOptions.cached = true;
				});

				ifArg("display-cached-assets", function(bool) {
					if (bool) outputOptions.cachedAssets = true;
				});

				if (!outputOptions.exclude) outputOptions.exclude = ["node_modules", "bower_components", "components"];

				if (argv["display-modules"]) {
					outputOptions.maxModules = Infinity;
					outputOptions.exclude = undefined;
					outputOptions.modules = true;
				}
			}

			ifArg("hide-modules", function(bool) {
				if (bool) {
					outputOptions.modules = false;
					outputOptions.chunkModules = false;
				}
			});

			ifArg("info-verbosity", function(value) {
				outputOptions.infoVerbosity = value;
			});

			ifArg("build-delimiter", function(value) {
				outputOptions.buildDelimiter = value;
			});

			const webpack = require("webpack");

			let lastHash = null;
			let compiler;
			try {
				compiler = webpack(options);
			} catch (err) {
				if (err.name === "WebpackOptionsValidationError") {
					if (argv.color) console.error(`\u001b[1m\u001b[31m${err.message}\u001b[39m\u001b[22m`);
					else console.error(err.message);
					// eslint-disable-next-line no-process-exit
					process.exit(1);
				}

				throw err;
			}

			if (argv.progress) {
				const ProgressPlugin = require("webpack").ProgressPlugin;
				new ProgressPlugin({
					profile: argv.profile
				}).apply(compiler);
			}
			if (outputOptions.infoVerbosity === "verbose") {
				if (argv.w) {
					compiler.hooks.watchRun.tap("WebpackInfo", compilation => {
						const compilationName = compilation.name ? compilation.name : "";
						console.error("\nCompilation " + compilationName + " starting…\n");
					});
				} else {
					compiler.hooks.beforeRun.tap("WebpackInfo", compilation => {
						const compilationName = compilation.name ? compilation.name : "";
						console.error("\nCompilation " + compilationName + " starting…\n");
					});
				}
				compiler.hooks.done.tap("WebpackInfo", compilation => {
					const compilationName = compilation.name ? compilation.name : "";
					console.error("\nCompilation " + compilationName + " finished\n");
				});
			}

			function compilerCallback(err, stats) {
				if (!options.watch || err) {
					// Do not keep cache anymore
					compiler.purgeInputFileSystem();
				}
				if (err) {
					lastHash = null;
					console.error(err.stack || err);
					if (err.details) console.error(err.details);
					process.exit(1); // eslint-disable-line
				}
				if (outputOptions.json) {
					stdout.write(JSON.stringify(stats.toJson(outputOptions), null, 2) + "\n");
				} else if (stats.hash !== lastHash) {
					lastHash = stats.hash;
					if (stats.compilation && stats.compilation.errors.length !== 0) {
						const errors = stats.compilation.errors;
						if (errors[0].name === "EntryModuleNotFoundError") {
							console.error("\n\u001b[1m\u001b[31mInsufficient number of arguments or no entry found.");
							console.error(
								"\u001b[1m\u001b[31mAlternatively, run 'webpack(-cli) --help' for usage info.\u001b[39m\u001b[22m\n"
							);
						}
					}
					const statsString = stats.toString(outputOptions);
					const delimiter = outputOptions.buildDelimiter ? `${outputOptions.buildDelimiter}\n` : "";
					if (statsString) stdout.write(`${statsString}\n${delimiter}`);

					/**
					 * Show a hint to donate to our Opencollective
					 * once a week, only on Monday
					 */
					const openCollectivePath = __dirname + "/opencollective.js";
					const MONDAY = 1;
					const SIX_DAYS = 518400000;
					const now = new Date();
					if (now.getDay() === MONDAY) {
						const { statSync, utimesSync } = require("fs");
						const lastPrint = statSync(openCollectivePath).atime;
						const lastPrintTS = new Date(lastPrint).getTime();
						const timeSinceLastPrint = now.getTime() - lastPrintTS;
						if (timeSinceLastPrint > SIX_DAYS) {
							require(openCollectivePath);
							// On windows we need to manually update the atime
							utimesSync(openCollectivePath, now, now);
						}
					}
				}
				if (!options.watch && stats.hasErrors()) {
					process.exitCode = 2;
				}
			}
			if (firstOptions.watch || options.watch) {
				const watchOptions = firstOptions.watchOptions || firstOptions.watch || options.watch || {};
				if (watchOptions.stdin) {
					process.stdin.on("end", function(_) {
						process.exit(); // eslint-disable-line
					});
					process.stdin.resume();
				}
				compiler.watch(watchOptions, compilerCallback);
				if (outputOptions.infoVerbosity !== "none") console.error("\nwebpack is watching the files…\n");
			} else {
				compiler.run((err, stats) => {
					if (compiler.close) {
						compiler.close(err2 => {
							compilerCallback(err || err2, stats);
						});
					} else {
						compilerCallback(err, stats);
					}
				});
			}
		}
		processOptions(options);
	});
})();
<|endoftext|>


<commit_before>#!/usr/bin/env node
/*
 * Copyright (c) Maximilian Antoni <max@javascript.studio>
 */
'use strict';

const fs = require('fs');
const path = require('path');
const url = require('url');
const zlib = require('zlib');
const { PassThrough } = require('stream');
const minimist = require('minimist');
const ora = require('ora');
const convert_source_map = require('convert-source-map');
const logger = require('@studio/log');
const log_format = require('@studio/log/format/fancy');
const studio_config = require('../lib/config');
const upload = require('../lib/upload');
const load_report = require('../lib/load-report');
const render_report = require('../lib/render-report');

function enableLogger() {
  logger.transform(log_format({ ts: false, ns: false })).out(process.stdout);
}

const argv = minimist(process.argv.slice(2), {
  alias: {
    file: 'f',
    global: 'g',
    help: 'h',
    version: 'v',
    exceptions: 'e'
  }
});

if (argv.help) {
  const help_file = path.join(__dirname, 'help.txt');
  fs.createReadStream(help_file, 'utf8').pipe(process.stdout);
  return;
}
if (argv.version) {
  const pkg = require('../package.json');
  console.log(`${pkg.name} version ${pkg.version}`);
  return;
}
if (argv.debug) {
  enableLogger();
}

let stream_end = false;
let config = null;
let url_json = null;
let gzip_buffer = null;
let source_map;

console.log('');
const spinner = ora('').start();

function fail(message, error) {
  spinner.stop();
  if (!argv.debug) {
    enableLogger();
  }
  logger('cli').error(message, {}, error);
  process.exitCode = 1;
}

function upload_gzip() {
  if (argv.debug) {
    spinner.stop();
  } else {
    spinner.text = 'Uploading';
  }
  const stream = new PassThrough();
  upload.upload(url_json.url, stream, gzip_buffer.length, (err) => {
    if (err) {
      fail('Failed to upload file', err.message);
      return;
    }
    load_report(config, url_json.number, argv, spinner, (err, report_json) => {
      if (err) {
        fail('Failed to load report', err.message);
        return;
      }
      render_report(report_json, source_map);
    });
  });
  stream.write(gzip_buffer);
  stream.end();
}

function read_stream(stream) {
  let source = '';
  stream.on('data', (chunk) => {
    source += chunk;
  });
  stream.on('end', () => {
    if (!source) {
      fail('No sources received on stdin');
      return;
    }
    source_map = convert_source_map.fromSource(source);
    if (source_map) {
      source_map = source_map.toObject();
      source = convert_source_map.removeComments(source);
    }
    const gzip = zlib.createGzip();
    const chunks = [];
    gzip.on('data', (chunk) => {
      chunks.push(chunk);
    });
    gzip.on('end', () => {
      gzip_buffer = Buffer.concat(chunks);
      stream_end = true;
      if (url_json) {
        upload_gzip();
      } else {
        spinner.text = 'Pending upload';
      }
    });
    gzip.write(source);
    gzip.end();
  });
}

spinner.text = 'Reading input';
if (argv.file) {
  const stream = fs.createReadStream(argv.file, 'utf8');
  stream.on('error', (err) => {
    if (err) {
      fail(`Failed to read file ${argv.file}`, err.message);
      return;
    }
  });
  read_stream(stream);
} else {
  process.stdin.setEncoding('utf8');
  read_stream(process.stdin);
}

const config_file = path.join(studio_config.home(), '.studio', 'config');

studio_config.read(config_file, (err, values) => {
  if (err) {
    fail('Failed to read config', err.message);
    return;
  }
  const api = values.api || 'https://api.javascript.studio/beta';
  const api_url = url.parse(api);

  config = {
    protocol: api_url.protocol,
    hostname: api_url.hostname,
    basepath: api_url.path === '/' ? '' : api_url.path,
    port: api_url.port,
    account: values.account,
    token: values.token
  };

  if (argv.debug) {
    spinner.stop();
  }

  let data = null;
  if (argv.global) {
    data = {
      global: argv.global
    };
  }
  upload.url(config, data, (err, json) => {
    if (err) {
      fail('Failed to get upload URL', err.message);
      return;
    }
    url_json = json;
    if (stream_end) {
      upload_gzip();
    } else if (argv.debug) {
      spinner.start().text = 'Reading input';
    }
  });
});
<commit_msg>Consistent function naming convention<commit_after>#!/usr/bin/env node
/*
 * Copyright (c) Maximilian Antoni <max@javascript.studio>
 */
'use strict';

const fs = require('fs');
const path = require('path');
const url = require('url');
const zlib = require('zlib');
const { PassThrough } = require('stream');
const minimist = require('minimist');
const ora = require('ora');
const convert_source_map = require('convert-source-map');
const logger = require('@studio/log');
const log_format = require('@studio/log/format/fancy');
const studio_config = require('../lib/config');
const upload = require('../lib/upload');
const load_report = require('../lib/load-report');
const render_report = require('../lib/render-report');

function enableLogger() {
  logger.transform(log_format({ ts: false, ns: false })).out(process.stdout);
}

const argv = minimist(process.argv.slice(2), {
  alias: {
    file: 'f',
    global: 'g',
    help: 'h',
    version: 'v',
    exceptions: 'e'
  }
});

if (argv.help) {
  const help_file = path.join(__dirname, 'help.txt');
  fs.createReadStream(help_file, 'utf8').pipe(process.stdout);
  return;
}
if (argv.version) {
  const pkg = require('../package.json');
  console.log(`${pkg.name} version ${pkg.version}`);
  return;
}
if (argv.debug) {
  enableLogger();
}

let stream_end = false;
let config = null;
let url_json = null;
let gzip_buffer = null;
let source_map;

console.log('');
const spinner = ora('').start();

function fail(message, error) {
  spinner.stop();
  if (!argv.debug) {
    enableLogger();
  }
  logger('cli').error(message, {}, error);
  process.exitCode = 1;
}

function uploadGzip() {
  if (argv.debug) {
    spinner.stop();
  } else {
    spinner.text = 'Uploading';
  }
  const stream = new PassThrough();
  upload.upload(url_json.url, stream, gzip_buffer.length, (err) => {
    if (err) {
      fail('Failed to upload file', err.message);
      return;
    }
    load_report(config, url_json.number, argv, spinner, (err, report_json) => {
      if (err) {
        fail('Failed to load report', err.message);
        return;
      }
      render_report(report_json, source_map);
    });
  });
  stream.write(gzip_buffer);
  stream.end();
}

function readStream(stream) {
  let source = '';
  stream.on('data', (chunk) => {
    source += chunk;
  });
  stream.on('end', () => {
    if (!source) {
      fail('No sources received on stdin');
      return;
    }
    source_map = convert_source_map.fromSource(source);
    if (source_map) {
      source_map = source_map.toObject();
      source = convert_source_map.removeComments(source);
    }
    const gzip = zlib.createGzip();
    const chunks = [];
    gzip.on('data', (chunk) => {
      chunks.push(chunk);
    });
    gzip.on('end', () => {
      gzip_buffer = Buffer.concat(chunks);
      stream_end = true;
      if (url_json) {
        uploadGzip();
      } else {
        spinner.text = 'Pending upload';
      }
    });
    gzip.write(source);
    gzip.end();
  });
}

spinner.text = 'Reading input';
if (argv.file) {
  const stream = fs.createReadStream(argv.file, 'utf8');
  stream.on('error', (err) => {
    if (err) {
      fail(`Failed to read file ${argv.file}`, err.message);
      return;
    }
  });
  readStream(stream);
} else {
  process.stdin.setEncoding('utf8');
  readStream(process.stdin);
}

const config_file = path.join(studio_config.home(), '.studio', 'config');

studio_config.read(config_file, (err, values) => {
  if (err) {
    fail('Failed to read config', err.message);
    return;
  }
  const api = values.api || 'https://api.javascript.studio/beta';
  const api_url = url.parse(api);

  config = {
    protocol: api_url.protocol,
    hostname: api_url.hostname,
    basepath: api_url.path === '/' ? '' : api_url.path,
    port: api_url.port,
    account: values.account,
    token: values.token
  };

  if (argv.debug) {
    spinner.stop();
  }

  let data = null;
  if (argv.global) {
    data = {
      global: argv.global
    };
  }
  upload.url(config, data, (err, json) => {
    if (err) {
      fail('Failed to get upload URL', err.message);
      return;
    }
    url_json = json;
    if (stream_end) {
      uploadGzip();
    } else if (argv.debug) {
      spinner.start().text = 'Reading input';
    }
  });
});
<|endoftext|>


<commit_before>#!/usr/bin/env node

var program = require('commander'),
    main = require('../main.js');

program
    .version('1.0.1')
    .option('-a, --all', 'Show hidden files')
    .option('-d, --depth <n>', 'Depth <int>. Defaults to 0', parseInt, 0)
    .option('--full', 'List files and directories recursively, with no limit on depth')
    .option('--list-deepest-paths', 'Lists the deepest paths in the directory tree')
    .parse(process.argv);

var lsp = function(baseDir, depth, showHidden, fullRecurse) {
    var data = main.walkDir(baseDir, depth, showHidden),
        output = main.prettyPrint(data, 0, 'name', true);
    console.log(output);
};

var listDeepestPaths = function(baseDir) {
    var data = main.getDeepestPaths(baseDir),
        output = main.prettyPrint(data.deepestPaths, 0, 'path', false);

    output = data.deepestPaths.length + ' path(s) at a depth of ' + data.maxDepth + '\n' + output;
    console.log(output);
}

var cli = function() {
    if (program.listDeepestPaths) {
        listDeepestPaths(process.cwd());
    } else {
        lsp(process.cwd(), program.depth, program.all, program.full);
    }
}

// Run main
cli();
<commit_msg>Deleted bin/cli.js<commit_after><|endoftext|>


<commit_before>$(document).ready(function() {
	if(typeof FileActions!=='undefined'){
		FileActions.register('image','View','',function(filename){
			viewImage($('#dir').val(),filename);
		});
		FileActions.setDefault('image','View');
	}
	OC.search.customResults.Images=function(row,item){
		var image=item.link.substr(item.link.indexOf('?file=')+6);
		var a=row.find('a');
		a.attr('href','#');
		a.click(function(){
			var pos=image.lastIndexOf('/')
			var file=image.substr(pos + 1);
			var dir=image.substr(0,pos);
			viewImage(dir,file);
		});
	}
});

function viewImage(dir, file) {
	if(file.indexOf('.psd')>0){//can't view those
		return;
	}
	var location=OC.filePath('files','ajax','download.php')+'?files='+file+'&dir='+dir;
	$.fancybox({
		"href": location,
		"title": file.replace(/</, "<").replace(/>/, ">"),
		"titlePosition": "inside"
	});
}
<commit_msg>show pictures in folder with special characters, e.g. '+'<commit_after>$(document).ready(function() {
	if(typeof FileActions!=='undefined'){
		FileActions.register('image','View','',function(filename){
			viewImage($('#dir').val(),filename);
		});
		FileActions.setDefault('image','View');
	}
	OC.search.customResults.Images=function(row,item){
		var image=item.link.substr(item.link.indexOf('?file=')+6);
		var a=row.find('a');
		a.attr('href','#');
		a.click(function(){
			var pos=image.lastIndexOf('/')
			var file=image.substr(pos + 1);
			var dir=image.substr(0,pos);
			viewImage(dir,file);
		});
	}
});

function viewImage(dir, file) {
	if(file.indexOf('.psd')>0){//can't view those
		return;
	}
	var location=OC.filePath('files','ajax','download.php')+'?files='+encodeURIComponent(file)+'&dir='+encodeURIComponent(dir);
	$.fancybox({
		"href": location,
		"title": file.replace(/</, "<").replace(/>/, ">"),
		"titlePosition": "inside"
	});
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

// Copyright (C) 2014, Microsoft Corporation. All rights reserved.
// This code is governed by the BSD License found in the LICENSE file.

var parser = require('test262-parser');
var tapify = require('../lib/tapify');
var simpleReporter = require('../lib/simpleReporter.js');
var glob = require('glob');
var through = require('through');
var fs = require('fs');
var jss = require('JSONStream').stringify();
var scenarios = require('../lib/scenarios');

var args = require('minimist')(process.argv.slice(2), {
    default: {
        runner: 'node',
        reporter: 'simple',
        threads: 1,
    },
    alias: {
        consoleCommand: 'e',
        consolePrintCommand: 'p',
        runner: 'r',
        reporter: 'R',
        threads: 't',
    }
});

// default to console runner if passing console command
if(args.consoleCommand && args.runner === 'node') {
    args.runner = 'console';
}

// Try to create our runner
var Runner;
try {
    Runner = require('../lib/runners/' + args.runner);
} catch(e) {
    if(e.code === 'MODULE_NOT_FOUND') throw new Error('Runner ' + args.runner + ' not found.');
    throw e;
}

var runner = new Runner(args);
var results = parser
    .pipe(through(flatMap(scenarios(args))))
    .pipe(throughThreaded(function(test, done) {
        runner.run(test, done);
    }, args.threads));

if(args.reporter === 'json') {
    results.pipe(jss).pipe(process.stdout);
} else if(args.reporter === 'tap') {
    results.pipe(tapify).pipe(process.stdout);
} else if(args.reporter === 'simple') {
    results.pipe(simpleReporter);
}

// Make sure unnamed args are processed as glob patterns, even though unix-based
// system will auto-expand glob pattern args.
var files = args._.reduce(function (files, pattern) {
    return files.concat(glob.sync(pattern));
}, []);

processFiles(files);

function processFiles(files) {
    var index = -1;

    function nextFile() {
        index++;
        if(index < files.length) {
            processFile(files[index], nextFile);
        } else {
            parser.end();
        }
    }

    nextFile();

    function processFile(file, cb) {
        fs.readFile(file, 'utf8', function(err, contents) {
            parser.write({file: file, contents: contents});
            cb();
        });
    }
}

function flatMap(iterFn) {
    return function (test) {
        var iter = iterFn(test);
        var val = iter.next();

        while(!val.done) {
            this.queue(val.value);
            val = iter.next();
        }
    }
}

function throughThreaded(cb, threads) {
    var pending = 0;
    var done = false;

    return through(function(data) {
        var that = this;
        pending++;

        if(pending >= threads) that.pause();

        cb(data, function() {
            that.queue(data);
            pending--;
            if(done && pending === 0) that.queue(null);
            if(pending < threads && that.paused) that.resume();
        });
    }, function() {
        done = true;
        if(pending === 0) {
            this.queue(null);
        }
    })
}
<commit_msg>Default to 4 threads<commit_after>#!/usr/bin/env node

// Copyright (C) 2014, Microsoft Corporation. All rights reserved.
// This code is governed by the BSD License found in the LICENSE file.

var parser = require('test262-parser');
var tapify = require('../lib/tapify');
var simpleReporter = require('../lib/simpleReporter.js');
var glob = require('glob');
var through = require('through');
var fs = require('fs');
var jss = require('JSONStream').stringify();
var scenarios = require('../lib/scenarios');

var args = require('minimist')(process.argv.slice(2), {
    default: {
        runner: 'node',
        reporter: 'simple',
        threads: 4,
    },
    alias: {
        consoleCommand: 'e',
        consolePrintCommand: 'p',
        runner: 'r',
        reporter: 'R',
        threads: 't',
    }
});

// default to console runner if passing console command
if(args.consoleCommand && args.runner === 'node') {
    args.runner = 'console';
}

// Try to create our runner
var Runner;
try {
    Runner = require('../lib/runners/' + args.runner);
} catch(e) {
    if(e.code === 'MODULE_NOT_FOUND') throw new Error('Runner ' + args.runner + ' not found.');
    throw e;
}

var runner = new Runner(args);
var results = parser
    .pipe(through(flatMap(scenarios(args))))
    .pipe(throughThreaded(function(test, done) {
        runner.run(test, done);
    }, args.threads));

if(args.reporter === 'json') {
    results.pipe(jss).pipe(process.stdout);
} else if(args.reporter === 'tap') {
    results.pipe(tapify).pipe(process.stdout);
} else if(args.reporter === 'simple') {
    results.pipe(simpleReporter);
}

// Make sure unnamed args are processed as glob patterns, even though unix-based
// system will auto-expand glob pattern args.
var files = args._.reduce(function (files, pattern) {
    return files.concat(glob.sync(pattern));
}, []);

processFiles(files);

function processFiles(files) {
    var index = -1;

    function nextFile() {
        index++;
        if(index < files.length) {
            processFile(files[index], nextFile);
        } else {
            parser.end();
        }
    }

    nextFile();

    function processFile(file, cb) {
        fs.readFile(file, 'utf8', function(err, contents) {
            parser.write({file: file, contents: contents});
            cb();
        });
    }
}

function flatMap(iterFn) {
    return function (test) {
        var iter = iterFn(test);
        var val = iter.next();

        while(!val.done) {
            this.queue(val.value);
            val = iter.next();
        }
    }
}

function throughThreaded(cb, threads) {
    var pending = 0;
    var done = false;

    return through(function(data) {
        var that = this;
        pending++;

        if(pending >= threads) that.pause();

        cb(data, function() {
            that.queue(data);
            pending--;
            if(done && pending === 0) that.queue(null);
            if(pending < threads && that.paused) that.resume();
        });
    }, function() {
        done = true;
        if(pending === 0) {
            this.queue(null);
        }
    })
}
<|endoftext|>


<commit_before>define(["dojo/_base/declare", "ppwcode/contracts/_Mixin", "ppwcode/oddsAndEnds/typeOf"],
    function(declare, _ContractMixin, typeOf) {

      var UrlBuilder = declare([_ContractMixin], {
        // summary:
        //   An interface for which you have to provide an implementation.
        //   Instances, when operational, return url's for CRUD functions,
        //   for specific objects.
        //   How they do it, is up to the implementation.

        _c_invar: [
        ],

        get: function(/*String*/ method) {
          this._c_pre(function() {return typeOf(method) === "string";});

          switch (method) {
            case "GET":
              return this.retrieve;
            case "POST":
              return this.create;
            case "PUT":
              return this.update;
            case "DELETE":
              return this.delete;
            default:
              throw new Error("Unknown method: " + method);
          }
        },

        search: function(/*String?*/ serverType, /*Object?*/ query) {
          // summary:
          //   Returns a URL to search for objects.
          // description:
          //   A search for a specific `serverType` with or without a `query` should
          //   return objects of that type.
          //   A search for a specific `serverType` without a `query` should return all
          //   objects of that type.
          //   The semantics of a search without a specific `serverType`, with
          //   or without a `query`, is open.
          //   The semantics of the `query`, is open.
          this._c_pre(function() {return !serverType || typeOf(serverType) === "string";});
          this._c_pre(function() {return !query || typeOf(query) === "object";});

          this._c_ABSTRACT();
        },

        toMany: function(serverType, id, serverPropertyName) {
          // summary:
          //   Returns a URL to retrieve all objects of a to-many property of an object.
          this._c_pre(function() {return typeOf(serverType) === "string";});
          this._c_pre(function() {return typeOf(id) === "number";});
          this._c_pre(function() {return typeOf(serverPropertyName) === "string";});

          this._c_ABSTRACT();
        },

        retrieve: function(serverType, id) {
          // summary:
          //   Returns a URL to retrieve an object of the given `serverType` with the given id.
          this._c_pre(function() {return typeOf(serverType) === "string";});
          this._c_pre(function() {return typeOf(id) === "number";});

          this._c_ABSTRACT();
        },

        create: function(serverType) {
          // summary:
          //   Returns a URL to create an object of the given `serverType`.
          this._c_pre(function() {return typeOf(serverType) === "string";});

          this._c_ABSTRACT();
        },

        update: function(serverType, id) {
          // summary:
          //   Returns a URL to update an object of the given `serverType`.
          this._c_pre(function() {return typeOf(serverType) === "string";});
          this._c_pre(function() {return typeOf(id) === "number";});

          this._c_ABSTRACT();
        },

        delete: function(serverType, id) {
          // summary:
          //   Returns a URL to delete an object of the given `serverType`.
          this._c_pre(function() {return typeOf(serverType) === "string";});
          this._c_pre(function() {return typeOf(id) === "number";});

          this._c_ABSTRACT();
        }

      });

      return UrlBuilder;
    }
);
<commit_msg>this needs a hitch<commit_after>define(["dojo/_base/declare", "ppwcode/contracts/_Mixin", "ppwcode/oddsAndEnds/typeOf", "dojo/_base/lang"],
    function(declare, _ContractMixin, typeOf, lang) {

      var UrlBuilder = declare([_ContractMixin], {
        // summary:
        //   An interface for which you have to provide an implementation.
        //   Instances, when operational, return url's for CRUD functions,
        //   for specific objects.
        //   How they do it, is up to the implementation.

        _c_invar: [
        ],

        get: function(/*String*/ method) {
          this._c_pre(function() {return typeOf(method) === "string";});

          switch (method) {
            case "GET":
              return lang.hitch(this, this.retrieve);
            case "POST":
              return lang.hitch(this, this.create);
            case "PUT":
              return lang.hitch(this, this.update);
            case "DELETE":
              return lang.hitch(this, this.delete);
            default:
              throw new Error("Unknown method: " + method);
          }
        },

        search: function(/*String?*/ serverType, /*Object?*/ query) {
          // summary:
          //   Returns a URL to search for objects.
          // description:
          //   A search for a specific `serverType` with or without a `query` should
          //   return objects of that type.
          //   A search for a specific `serverType` without a `query` should return all
          //   objects of that type.
          //   The semantics of a search without a specific `serverType`, with
          //   or without a `query`, is open.
          //   The semantics of the `query`, is open.
          this._c_pre(function() {return !serverType || typeOf(serverType) === "string";});
          this._c_pre(function() {return !query || typeOf(query) === "object";});

          this._c_ABSTRACT();
        },

        toMany: function(serverType, id, serverPropertyName) {
          // summary:
          //   Returns a URL to retrieve all objects of a to-many property of an object.
          this._c_pre(function() {return typeOf(serverType) === "string";});
          this._c_pre(function() {return typeOf(id) === "number";});
          this._c_pre(function() {return typeOf(serverPropertyName) === "string";});

          this._c_ABSTRACT();
        },

        retrieve: function(serverType, id) {
          // summary:
          //   Returns a URL to retrieve an object of the given `serverType` with the given id.
          this._c_pre(function() {return typeOf(serverType) === "string";});
          this._c_pre(function() {return typeOf(id) === "number";});

          this._c_ABSTRACT();
        },

        create: function(serverType) {
          // summary:
          //   Returns a URL to create an object of the given `serverType`.
          this._c_pre(function() {return typeOf(serverType) === "string";});

          this._c_ABSTRACT();
        },

        update: function(serverType, id) {
          // summary:
          //   Returns a URL to update an object of the given `serverType`.
          this._c_pre(function() {return typeOf(serverType) === "string";});
          this._c_pre(function() {return typeOf(id) === "number";});

          this._c_ABSTRACT();
        },

        delete: function(serverType, id) {
          // summary:
          //   Returns a URL to delete an object of the given `serverType`.
          this._c_pre(function() {return typeOf(serverType) === "string";});
          this._c_pre(function() {return typeOf(id) === "number";});

          this._c_ABSTRACT();
        }

      });

      return UrlBuilder;
    }
);
<|endoftext|>


<commit_before>define(["dojo/_base/declare", "./PpwCodeObject", "dojo/Stateful", "ppwcode/contracts/_Mixin", "dojo/when", "ppwcode/oddsAndEnds/js"],
    function(declare, PpwCodeObject, Stateful, _ContractMixin, when, js) {

      /*
         NOTE:

         This class combines some of our own ppwcode stuff with dojo/Stateful stuff.
         Stateful has a number of annoying features, which we started working around.
         In a later version, we probably should consolidate the code in here, and
         thus no longer inherit from Stateful.
         For now, we keep inheritance, to track the evolution of Stateful. Changes
         might happen in later versions, and we would want to see those.
         Below, we HACK to solve these issues.

         The adaptations we make here are:

         1) In postscript, which is executed as the last step in construction, all
            properties of the kwargs of the constructor which are not yet set, are copied
            to the prototype. We don't want this. We only want properties that we define
            in the class, no strange stuff. Secondly, this is too early, in the constructor
            chain.
         2) Both set and _changeAttrValue should not do anything, and certainly not send events,
            if the new value is the same as the old value. The remaining problem is what
            "the same" means. We now use "!=", but we might need to change that further
            later.
         3) Setters and getters might change a value that is submitted or retrieved.
            If this is not allowed, it does not make much sense to have setters and getters
            in the first place (the same applies to validation, BTW).
            But if a setter or a getter does not exactly copy the given value, the events
            that are sent out must sent the actual new value, not the submitted new value.
            This means that set and _changeAttrValue must use the setter and getter in any
            case (even if value == oldValue), and 2) is incomplete. For 2), we fall back
            to the minimum requirement, certainly not to send events.
       */

      // HACK Stateful adapation: Do not blindly copy all properties of the kwargs
//      var statefulPrototype = Stateful.prototype;
//      delete statefulPrototype.postscript;
      // now hack is replaced by overriding postscript in our class; no side effects that way

      function areDifferentValues(newValue, oldValue) {
        var result;
        switch (js.typeOf(newValue)) {
          case "array":
            result = (js.typeOf(oldValue) !== "array") ||
              newValue.some(function(element, index) {
                return areDifferentValues(element, oldValue[index]);
              });
            break;
          default:
            result = newValue != oldValue;
        }
        return result;
      }

      return declare([PpwCodeObject, Stateful], {

        _c_invar: [
          // TODO nothing here yet
        ],

        "-chains-": {
          reload: "after"
        },

        // lastReloaded: Date?
        //   The time of last reload.
        lastReloaded: null,

        constructor: function(/*Object*/ props) {
          // TODO replace warning with a precondition when all other code is changed
          // The only good usage is to ALWAYS create semantic objects with an no-ops constructor, and potentionally reload after that.
          // Not true, see Property Instance
          if (props) {
            console.warn("Code should be rewritten to not use arguments in the constructor.")
          }
        },

        postscript: function() {
          // summary:
          //   Does nothing. This method is here to override the
          //   stupid implementation of Stateful.

          this._c_NOP();
        },

        set: function(/*String*/name, /*Object*/value) {
          // Code copied from dojo/Stateful
          if(typeof name === "object"){
            for(var x in name){
              if(name.hasOwnProperty(x) && x !="_watchCallbacks"){
                this.set(x, name[x]);
              }
            }
            return this;
          }

          var names = this._getAttrNames(name),
            oldValue = this._get(name, names),
            setter = this[names.s],
            result;
          if (typeof setter === "function") {
            // use the explicit setter
            result = setter.apply(this, Array.prototype.slice.call(arguments, 1));
          } else {
            // no setter so set attribute directly
            this[name] = value;
          }
          if(this._watchCallbacks) {
            // HACK send the actual new value in the event, not the supplied value
            var newValue = this.get(name);
            // HACK only send if something changed; changed takes into account array-values
            if (areDifferentValues(newValue, oldValue)) {
              var self = this;
              // If setter returned a promise, wait for it to complete, otherwise call watches immediately
              when(result, function() {
                // HACK send the actual new value in the event, not the supplied value
                self._watchCallbacks(name, oldValue, newValue);
              });
            }
          }
          return this; // return be.ppwcode.vernacular.semantics.SemanticObject
        },

        _changeAttrValue: function(name, value) {
          var oldValue = this.get(name);
          this[name] = value;
          if(this._watchCallbacks) {
            // HACK send the actual new value in the event, not the supplied value
            var newValue = this.get(name);
            // HACK only send if something changed; changed takes into account array-values
            if (areDifferentValues(newValue, oldValue)) {
              // HACK send the actual new value in the event, not the supplied value
              this._watchCallbacks(name, oldValue, newValue);
            }
          }
          return this; // return SemanticObject
        },

        isEditable: function() { return true; },
        isDeletable: function() { return true },

        reload: function(/*Object*/ json) {
          // summary:
          //   Chained method that loads data from `json`.
          // description:
          //   Subclasses should overwrite this method
          //   to load the properties from `json` that are defined
          //   in that subclass.
          //   See also _extendJsonObject.
          //   The time of reload is remembered in lastReloaded.

          this._changeAttrValue("lastReloaded", new Date());
        },

        _extendJsonObject: function(/*Object*/ json) {
          this._c_NOP(json);
        },

        _stateToString: function(/*Array of String*/ toStrings) {
          this._c_NOP(toStrings);
        }

      });
    }
);
<commit_msg>Fixed a major bug in SemanticObject: the default compare used was incorrect. Now we have A LOT less events.<commit_after>define(["dojo/_base/declare", "./PpwCodeObject", "dojo/Stateful", "dojo/when", "ppwcode/oddsAndEnds/js"],
    function(declare, PpwCodeObject, Stateful, when, js) {

      /*
         NOTE:

         This class combines some of our own ppwcode stuff with dojo/Stateful stuff.
         Stateful has a number of annoying features, which we started working around.
         In a later version, we probably should consolidate the code in here, and
         thus no longer inherit from Stateful.
         For now, we keep inheritance, to track the evolution of Stateful. Changes
         might happen in later versions, and we would want to see those.
         Below, we HACK to solve these issues.

         The adaptations we make here are:

         1) In postscript, which is executed as the last step in construction, all
            properties of the kwargs of the constructor which are not yet set, are copied
            to the prototype. We don't want this. We only want properties that we define
            in the class, no strange stuff. Secondly, this is too early, in the constructor
            chain.
         2) Both set and _changeAttrValue should not do anything, and certainly not send events,
            if the new value is the same as the old value. The remaining problem is what
            "the same" means. We now use "!=", but we might need to change that further
            later.
         3) Setters and getters might change a value that is submitted or retrieved.
            If this is not allowed, it does not make much sense to have setters and getters
            in the first place (the same applies to validation, BTW).
            But if a setter or a getter does not exactly copy the given value, the events
            that are sent out must sent the actual new value, not the submitted new value.
            This means that set and _changeAttrValue must use the setter and getter in any
            case (even if value == oldValue), and 2) is incomplete. For 2), we fall back
            to the minimum requirement, certainly not to send events.
       */

      // HACK Stateful adapation: Do not blindly copy all properties of the kwargs
//      var statefulPrototype = Stateful.prototype;
//      delete statefulPrototype.postscript;
      // now hack is replaced by overriding postscript in our class; no side effects that way

      function areDifferentValues(newValue, oldValue) {
        var result;
        switch (js.typeOf(newValue)) {
          case "array":
            result = (js.typeOf(oldValue) !== "array") ||
              newValue.some(function(element, index) {
                return areDifferentValues(element, oldValue[index]);
              });
            break;
          default:
            result = (newValue != oldValue);
        }
        return result;
      }

      return declare([PpwCodeObject, Stateful], {

        _c_invar: [
          // TODO nothing here yet
        ],

        "-chains-": {
          reload: "after"
        },

        // lastReloaded: Date?
        //   The time of last reload.
        lastReloaded: null,

        constructor: function(/*Object*/ props) {
          // TODO replace warning with a precondition when all other code is changed
          // The only good usage is to ALWAYS create semantic objects with an no-ops constructor, and potentionally reload after that.
          // Not true, see Property Instance
          if (props) {
            console.warn("Code should be rewritten to not use arguments in the constructor.")
          }
        },

        postscript: function() {
          // summary:
          //   Does nothing. This method is here to override the
          //   stupid implementation of Stateful.

          this._c_NOP();
        },

        set: function(/*String*/name, /*Object*/value) {
          // Code copied from dojo/Stateful
          if(typeof name === "object"){
            for(var x in name){
              if(name.hasOwnProperty(x) && x !="_watchCallbacks"){
                this.set(x, name[x]);
              }
            }
            return this;
          }

          var names = this._getAttrNames(name),
            oldValue = this._get(name, names),
            setter = this[names.s],
            result;
          if (typeof setter === "function") {
            // use the explicit setter
            result = setter.apply(this, Array.prototype.slice.call(arguments, 1));
          } else {
            // no setter so set attribute directly
            this[name] = value;
          }
          if(this._watchCallbacks) {
            // HACK send the actual new value in the event, not the supplied value
            var newValue = this.get(name);
            // HACK only send if something changed; changed takes into account array-values
            if (areDifferentValues(newValue, oldValue)) {
              var self = this;
              // If setter returned a promise, wait for it to complete, otherwise call watches immediately
              when(result, function() {
                // HACK send the actual new value in the event, not the supplied value
                self._watchCallbacks(name, oldValue, newValue);
              });
            }
          }
          return this; // return be.ppwcode.vernacular.semantics.SemanticObject
        },

        _changeAttrValue: function(name, value) {
          var oldValue = this.get(name);
          this[name] = value;
          if(this._watchCallbacks) {
            // HACK send the actual new value in the event, not the supplied value
            var newValue = this.get(name);
            // HACK only send if something changed; changed takes into account array-values
            if (areDifferentValues(newValue, oldValue)) {
              // HACK send the actual new value in the event, not the supplied value
              this._watchCallbacks(name, oldValue, newValue);
            }
          }
          return this; // return SemanticObject
        },

        isEditable: function() { return true; },
        isDeletable: function() { return true },

        reload: function(/*Object*/ json) {
          // summary:
          //   Chained method that loads data from `json`.
          // description:
          //   Subclasses should overwrite this method
          //   to load the properties from `json` that are defined
          //   in that subclass.
          //   See also _extendJsonObject.
          //   The time of reload is remembered in lastReloaded.

          this._changeAttrValue("lastReloaded", new Date());
        },

        _extendJsonObject: function(/*Object*/ json) {
          this._c_NOP(json);
        },

        _stateToString: function(/*Array of String*/ toStrings) {
          this._c_NOP(toStrings);
        }

      });
    }
);
<|endoftext|>


<commit_before>// Copyright 2018, University of Colorado Boulder

/**
 * Alternate vertex form equation with coefficients that can be changed via sliders.
 * Form is y = (1/(4p))(x - h)^2 + k, where p, h, and k can be changed with number pickers
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( require => {
  'use strict';

  // modules
  const CoefficientSlider = require( 'GRAPHING_QUADRATICS/common/view/CoefficientSlider' );
  const GQColors = require( 'GRAPHING_QUADRATICS/common/GQColors' );
  const GQConstants = require( 'GRAPHING_QUADRATICS/common/GQConstants' );
  const GQSymbols = require( 'GRAPHING_QUADRATICS/common/GQSymbols' );
  const graphingQuadratics = require( 'GRAPHING_QUADRATICS/graphingQuadratics' );
  const HBox = require( 'SCENERY/nodes/HBox' );
  const Line = require( 'SCENERY/nodes/Line' );
  const MathSymbols = require( 'SCENERY_PHET/MathSymbols' );
  const Node = require( 'SCENERY/nodes/Node' );
  const NumberDisplay = require( 'SCENERY_PHET/NumberDisplay' );
  const PhetFont = require( 'SCENERY_PHET/PhetFont' );
  const RichText = require( 'SCENERY/nodes/RichText' );
  const Tandem = require( 'TANDEM/Tandem' );
  const VBox = require( 'SCENERY/nodes/VBox' );

  class FocusAndDirectrixInteractiveEquationNode extends Node {

    /**
     * @param {NumberProperty} pProperty - p coefficient of alternate vertex form
     * @param {NumberProperty} hProperty - h coefficient of alternate vertex form
     * @param {NumberProperty} kProperty - k coefficient of alternate vertex form
     * @param {Object} [options]
     */
    constructor( pProperty, hProperty, kProperty, options ) {

      options = _.extend( {
        tandem: Tandem.required
      }, options );

      // equation
      const equationNode = new EquationNode( pProperty, hProperty, kProperty, {
        tandem: options.tandem.createTandem( 'equationNode' ),
        phetioDocumentation: 'the equation that changes as you adjust the sliders'
      } );

      // coefficient controls (labeled sliders)
      const pSlider = new CoefficientSlider( GQSymbols.p, pProperty, {

        // p=0 is not supported by this sim, see https://github.com/phetsims/graphing-quadratics/issues/31
        skipZero: true,
        interval: GQConstants.FOCUS_AND_DIRECTRIX_INTERVAL_P,
        labelColor: GQColors.FOCUS_AND_DIRECTRIX_P,
        tandem: options.tandem.createTandem( 'pSlider' ),
        phetioDocumentation: 'slider for coefficient p'
      } );
      const hSlider = new CoefficientSlider( GQSymbols.h, hProperty, {
        interval: GQConstants.FOCUS_AND_DIRECTRIX_INTERVAL_H,
        labelColor: GQColors.FOCUS_AND_DIRECTRIX_H,
        tandem: options.tandem.createTandem( 'hSlider' ),
        phetioDocumentation: 'slider for coefficient h'
      } );
      const kSlider = new CoefficientSlider( GQSymbols.k, kProperty, {
        interval: GQConstants.FOCUS_AND_DIRECTRIX_INTERVAL_K,
        labelColor: GQColors.FOCUS_AND_DIRECTRIX_K,
        tandem: options.tandem.createTandem( 'kSlider' ),
        phetioDocumentation: 'slider for coefficient k'
      } );

      assert && assert( !options.children, 'FocusAndDirectrixInteractiveEquationNode sets children' );
      options.children = [ equationNode, pSlider, hSlider, kSlider ];

      super( options );

      // horizontally align sliders under their associated values in the equation
      const ySpacing = 3;
      pSlider.x = this.globalToLocalBounds( equationNode.pGlobalBounds ).centerX;
      pSlider.top = equationNode.bottom + ySpacing;
      hSlider.x = this.globalToLocalBounds( equationNode.hGlobalBounds ).centerX;
      hSlider.top = equationNode.bottom + ySpacing;
      kSlider.x = this.globalToLocalBounds( equationNode.kGlobalBounds ).centerX;
      kSlider.top = equationNode.bottom + ySpacing;
    }
  }

  graphingQuadratics.register( 'FocusAndDirectrixInteractiveEquationNode', FocusAndDirectrixInteractiveEquationNode );

  /**
   * The equation that appears above the sliders.
   */
  class EquationNode extends Node {

    /**
     * @param {NumberProperty} pProperty
     * @param {NumberProperty} hProperty
     * @param {NumberProperty} kProperty
     * @param {Object} [options]
     */
    constructor( pProperty, hProperty, kProperty, options ) {

      options = _.extend( {
        maxWidth: 325, // determined empirically
        tandem: Tandem.required
      }, options );

      assert && assert( pProperty.range, 'missing pProperty.range' );
      assert && assert( hProperty.range, 'missing hProperty.range' );
      assert && assert( kProperty.range, 'missing kProperty.range' );

      // common options for NumberDisplay instances
      const numberDisplayOptions = {
        font: new PhetFont( { size: GQConstants.INTERACTIVE_EQUATION_FONT_SIZE, weight: 'bold' } ),
        backgroundFill: null,
        backgroundStroke: null,
        backgroundLineWidth: 0,
        xMargin: 0,
        yMargin: 0
      };

      // options for other parts of the equation
      const equationOptions = {
        font: new PhetFont( GQConstants.INTERACTIVE_EQUATION_FONT_SIZE ),
        fill: 'black'
      };
      const xyOptions = _.extend( {}, equationOptions, {
        maxWidth: 20 // determined empirically
      } );

      // y
      const yNode = new RichText( GQSymbols.y, xyOptions );

      // =
      const equalsNode = new RichText( MathSymbols.EQUAL_TO, equationOptions );

      // 1
      const numeratorNode = new RichText( '1', equationOptions );

      // 4(
      const fourParenNode = new RichText( '4(', equationOptions );

      // p value
      const pNode = new NumberDisplay( pProperty, pProperty.range, _.extend( {}, numberDisplayOptions, {
        numberFill: GQColors.FOCUS_AND_DIRECTRIX_P,
        decimalPlaces: GQConstants.FOCUS_AND_DIRECTRIX_DECIMALS_P
      } ) );

      // )
      const parenNode = new RichText( ')', equationOptions );

      // 1/4(p)
      const denominatorNode = new HBox( {
        children: [ fourParenNode, pNode, parenNode ]
      } );

      // horizontal line between numerator and denominator
      const fractionLineLength = 1.25 * Math.max( numeratorNode.width, denominatorNode.width );
      const fractionLine = new Line( 0, 0, fractionLineLength, 0, {
        stroke: 'black',
        lineWidth: 1
      } );

      // 1/4p
      const fractionNode = new VBox( {
        spacing: 2,
        children: [ numeratorNode, fractionLine, denominatorNode ],
        scale: 0.85
      } );

      // (
      const anotherParenNode = new RichText( '(', equationOptions );

      // x
      const xNode = new RichText( GQSymbols.x, xyOptions );

      // -
      const minusNode = new RichText( MathSymbols.MINUS, equationOptions );

      // h value
      const hNode = new NumberDisplay( hProperty, hProperty.range, _.extend( {}, numberDisplayOptions, {
        numberFill: GQColors.FOCUS_AND_DIRECTRIX_H,
        decimalPlaces: GQConstants.FOCUS_AND_DIRECTRIX_DECIMALS_H
      } ) );

      // )^2
      const parenSquaredNode = new RichText( ')2', equationOptions );

      // +
      const plusNode = new RichText( MathSymbols.PLUS, equationOptions );

      // k value
      const kNode = new NumberDisplay( kProperty, kProperty.range, _.extend( {}, numberDisplayOptions, {
        numberFill: GQColors.FOCUS_AND_DIRECTRIX_K,
        decimalPlaces: GQConstants.FOCUS_AND_DIRECTRIX_DECIMALS_K
      } ) );

      // layout
      const operatorSpacing = 8; // space around operators
      const termSpacing = 4; // space inside a term
      equalsNode.left = yNode.right + operatorSpacing;
      fractionNode.left = equalsNode.right + operatorSpacing;
      fractionNode.centerY = equalsNode.centerY;
      anotherParenNode.left = fractionNode.right + termSpacing;
      xNode.left = anotherParenNode.right + termSpacing;
      minusNode.left = xNode.right + operatorSpacing;
      hNode.left = minusNode.right + operatorSpacing;
      parenSquaredNode.left = hNode.right + termSpacing;
      plusNode.left = parenSquaredNode.right + operatorSpacing;
      kNode.left = plusNode.right + operatorSpacing;
      hNode.bottom = equalsNode.bottom;
      kNode.bottom = equalsNode.bottom;

      // y = (1/(4p))(x - h)^2 + k
      assert && assert( !options.children, 'EquationNode sets children' );
      options.children = [ yNode, equalsNode, fractionNode,
        anotherParenNode, xNode, minusNode, hNode, parenSquaredNode, plusNode, kNode ];

      super( options );

      // @private needed by methods
      this.pNode = pNode;
      this.hNode = hNode;
      this.kNode = kNode;
    }

    // @public Gets the global {Bounds2} of p, h, k, used for layout
    get pGlobalBounds() { return this.getGlobalBoundsForNode( this.pNode ); }

    get hGlobalBounds() { return this.getGlobalBoundsForNode( this.hNode ); }

    get kGlobalBounds() { return this.getGlobalBoundsForNode( this.kNode ); }

    // @private gets the global bounds of a descendent Node
    getGlobalBoundsForNode( node ) { return node.localToGlobalBounds( node.localBounds ); }
  }

  graphingQuadratics.register( 'FocusAndDirectrixInteractiveEquationNode.EquationNode', EquationNode );

  return FocusAndDirectrixInteractiveEquationNode;
} );
<commit_msg>delete vestigial maxWidth<commit_after>// Copyright 2018, University of Colorado Boulder

/**
 * Alternate vertex form equation with coefficients that can be changed via sliders.
 * Form is y = (1/(4p))(x - h)^2 + k, where p, h, and k can be changed with number pickers
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( require => {
  'use strict';

  // modules
  const CoefficientSlider = require( 'GRAPHING_QUADRATICS/common/view/CoefficientSlider' );
  const GQColors = require( 'GRAPHING_QUADRATICS/common/GQColors' );
  const GQConstants = require( 'GRAPHING_QUADRATICS/common/GQConstants' );
  const GQSymbols = require( 'GRAPHING_QUADRATICS/common/GQSymbols' );
  const graphingQuadratics = require( 'GRAPHING_QUADRATICS/graphingQuadratics' );
  const HBox = require( 'SCENERY/nodes/HBox' );
  const Line = require( 'SCENERY/nodes/Line' );
  const MathSymbols = require( 'SCENERY_PHET/MathSymbols' );
  const Node = require( 'SCENERY/nodes/Node' );
  const NumberDisplay = require( 'SCENERY_PHET/NumberDisplay' );
  const PhetFont = require( 'SCENERY_PHET/PhetFont' );
  const RichText = require( 'SCENERY/nodes/RichText' );
  const Tandem = require( 'TANDEM/Tandem' );
  const VBox = require( 'SCENERY/nodes/VBox' );

  class FocusAndDirectrixInteractiveEquationNode extends Node {

    /**
     * @param {NumberProperty} pProperty - p coefficient of alternate vertex form
     * @param {NumberProperty} hProperty - h coefficient of alternate vertex form
     * @param {NumberProperty} kProperty - k coefficient of alternate vertex form
     * @param {Object} [options]
     */
    constructor( pProperty, hProperty, kProperty, options ) {

      options = _.extend( {
        tandem: Tandem.required
      }, options );

      // equation
      const equationNode = new EquationNode( pProperty, hProperty, kProperty, {
        tandem: options.tandem.createTandem( 'equationNode' ),
        phetioDocumentation: 'the equation that changes as you adjust the sliders'
      } );

      // coefficient controls (labeled sliders)
      const pSlider = new CoefficientSlider( GQSymbols.p, pProperty, {

        // p=0 is not supported by this sim, see https://github.com/phetsims/graphing-quadratics/issues/31
        skipZero: true,
        interval: GQConstants.FOCUS_AND_DIRECTRIX_INTERVAL_P,
        labelColor: GQColors.FOCUS_AND_DIRECTRIX_P,
        tandem: options.tandem.createTandem( 'pSlider' ),
        phetioDocumentation: 'slider for coefficient p'
      } );
      const hSlider = new CoefficientSlider( GQSymbols.h, hProperty, {
        interval: GQConstants.FOCUS_AND_DIRECTRIX_INTERVAL_H,
        labelColor: GQColors.FOCUS_AND_DIRECTRIX_H,
        tandem: options.tandem.createTandem( 'hSlider' ),
        phetioDocumentation: 'slider for coefficient h'
      } );
      const kSlider = new CoefficientSlider( GQSymbols.k, kProperty, {
        interval: GQConstants.FOCUS_AND_DIRECTRIX_INTERVAL_K,
        labelColor: GQColors.FOCUS_AND_DIRECTRIX_K,
        tandem: options.tandem.createTandem( 'kSlider' ),
        phetioDocumentation: 'slider for coefficient k'
      } );

      assert && assert( !options.children, 'FocusAndDirectrixInteractiveEquationNode sets children' );
      options.children = [ equationNode, pSlider, hSlider, kSlider ];

      super( options );

      // horizontally align sliders under their associated values in the equation
      const ySpacing = 3;
      pSlider.x = this.globalToLocalBounds( equationNode.pGlobalBounds ).centerX;
      pSlider.top = equationNode.bottom + ySpacing;
      hSlider.x = this.globalToLocalBounds( equationNode.hGlobalBounds ).centerX;
      hSlider.top = equationNode.bottom + ySpacing;
      kSlider.x = this.globalToLocalBounds( equationNode.kGlobalBounds ).centerX;
      kSlider.top = equationNode.bottom + ySpacing;
    }
  }

  graphingQuadratics.register( 'FocusAndDirectrixInteractiveEquationNode', FocusAndDirectrixInteractiveEquationNode );

  /**
   * The equation that appears above the sliders.
   */
  class EquationNode extends Node {

    /**
     * @param {NumberProperty} pProperty
     * @param {NumberProperty} hProperty
     * @param {NumberProperty} kProperty
     * @param {Object} [options]
     */
    constructor( pProperty, hProperty, kProperty, options ) {

      options = _.extend( {
        tandem: Tandem.required
      }, options );

      assert && assert( pProperty.range, 'missing pProperty.range' );
      assert && assert( hProperty.range, 'missing hProperty.range' );
      assert && assert( kProperty.range, 'missing kProperty.range' );

      // common options for NumberDisplay instances
      const numberDisplayOptions = {
        font: new PhetFont( { size: GQConstants.INTERACTIVE_EQUATION_FONT_SIZE, weight: 'bold' } ),
        backgroundFill: null,
        backgroundStroke: null,
        backgroundLineWidth: 0,
        xMargin: 0,
        yMargin: 0
      };

      // options for other parts of the equation
      const equationOptions = {
        font: new PhetFont( GQConstants.INTERACTIVE_EQUATION_FONT_SIZE ),
        fill: 'black'
      };
      const xyOptions = _.extend( {}, equationOptions, {
        maxWidth: 20 // determined empirically
      } );

      // y
      const yNode = new RichText( GQSymbols.y, xyOptions );

      // =
      const equalsNode = new RichText( MathSymbols.EQUAL_TO, equationOptions );

      // 1
      const numeratorNode = new RichText( '1', equationOptions );

      // 4(
      const fourParenNode = new RichText( '4(', equationOptions );

      // p value
      const pNode = new NumberDisplay( pProperty, pProperty.range, _.extend( {}, numberDisplayOptions, {
        numberFill: GQColors.FOCUS_AND_DIRECTRIX_P,
        decimalPlaces: GQConstants.FOCUS_AND_DIRECTRIX_DECIMALS_P
      } ) );

      // )
      const parenNode = new RichText( ')', equationOptions );

      // 1/4(p)
      const denominatorNode = new HBox( {
        children: [ fourParenNode, pNode, parenNode ]
      } );

      // horizontal line between numerator and denominator
      const fractionLineLength = 1.25 * Math.max( numeratorNode.width, denominatorNode.width );
      const fractionLine = new Line( 0, 0, fractionLineLength, 0, {
        stroke: 'black',
        lineWidth: 1
      } );

      // 1/4p
      const fractionNode = new VBox( {
        spacing: 2,
        children: [ numeratorNode, fractionLine, denominatorNode ],
        scale: 0.85
      } );

      // (
      const anotherParenNode = new RichText( '(', equationOptions );

      // x
      const xNode = new RichText( GQSymbols.x, xyOptions );

      // -
      const minusNode = new RichText( MathSymbols.MINUS, equationOptions );

      // h value
      const hNode = new NumberDisplay( hProperty, hProperty.range, _.extend( {}, numberDisplayOptions, {
        numberFill: GQColors.FOCUS_AND_DIRECTRIX_H,
        decimalPlaces: GQConstants.FOCUS_AND_DIRECTRIX_DECIMALS_H
      } ) );

      // )^2
      const parenSquaredNode = new RichText( ')2', equationOptions );

      // +
      const plusNode = new RichText( MathSymbols.PLUS, equationOptions );

      // k value
      const kNode = new NumberDisplay( kProperty, kProperty.range, _.extend( {}, numberDisplayOptions, {
        numberFill: GQColors.FOCUS_AND_DIRECTRIX_K,
        decimalPlaces: GQConstants.FOCUS_AND_DIRECTRIX_DECIMALS_K
      } ) );

      // layout
      const operatorSpacing = 10; // space around operators
      const termSpacing = 4; // space inside a term
      equalsNode.left = yNode.right + operatorSpacing;
      fractionNode.left = equalsNode.right + operatorSpacing;
      fractionNode.centerY = equalsNode.centerY;
      anotherParenNode.left = fractionNode.right + termSpacing;
      xNode.left = anotherParenNode.right + termSpacing;
      minusNode.left = xNode.right + operatorSpacing;
      hNode.left = minusNode.right + operatorSpacing;
      parenSquaredNode.left = hNode.right + termSpacing;
      plusNode.left = parenSquaredNode.right + operatorSpacing;
      kNode.left = plusNode.right + operatorSpacing;
      hNode.bottom = equalsNode.bottom;
      kNode.bottom = equalsNode.bottom;

      // y = (1/(4p))(x - h)^2 + k
      assert && assert( !options.children, 'EquationNode sets children' );
      options.children = [ yNode, equalsNode, fractionNode,
        anotherParenNode, xNode, minusNode, hNode, parenSquaredNode, plusNode, kNode ];

      super( options );

      // @private needed by methods
      this.pNode = pNode;
      this.hNode = hNode;
      this.kNode = kNode;
    }

    // @public Gets the global {Bounds2} of p, h, k, used for layout
    get pGlobalBounds() { return this.getGlobalBoundsForNode( this.pNode ); }

    get hGlobalBounds() { return this.getGlobalBoundsForNode( this.hNode ); }

    get kGlobalBounds() { return this.getGlobalBoundsForNode( this.kNode ); }

    // @private gets the global bounds of a descendent Node
    getGlobalBoundsForNode( node ) { return node.localToGlobalBounds( node.localBounds ); }
  }

  graphingQuadratics.register( 'FocusAndDirectrixInteractiveEquationNode.EquationNode', EquationNode );

  return FocusAndDirectrixInteractiveEquationNode;
} );
<|endoftext|>