<commit_before>var Q = require("q"), 
	PromiseUtil = require("./PromiseUtil");

// This data structure defines the page interface.
//
// Each item represents a method that page objects (and middleware) may override.
//
// The keys here are method names.
//
// The values are tuples containing:
//   - Number of arguments to the method.
//   - Default implementation of the method.
//   - Normalization function applied to method output.
//
// Note that each of these methods also receives an additional argument,
// which is the next implementation of the method in the call chain.
//     - Middleware implementations _should_ call this in most cases.*
//     - Page implementations _may_ call this (it will be the default implementation).
//
// * Consider carefully before deciding not to call `next()` in middleware.
// Other middleware (and the page itself) may exhibit undefined behavior if a
// given method is not called.  Generally, only skip calling `next()` for
// short-circuit responses (e.g. a redirect from `handleRoute`).
//
var PAGE_METHODS = {
	handleRoute        : [1, () => ({code: 200}), Q],
	getTitle           : [0, () => "", Q],
	getScripts         : [0, () => [], standardizeScripts],
	getSystemScripts   : [0, () => [], standardizeScripts],
	getHeadStylesheets : [0, () => [], standardizeStyles],
	getMetaTags        : [0, () => [], standardizeMetaTags],
	getCanonicalUrl    : [0, () => "", Q],
	getBase            : [0, () => null, Q],
	getBodyClasses     : [0, () => [], Q],
	getElements        : [0, () => [], standardizeElements],
	handleComplete     : [0, () => null, Q],
};

// These `standardize*` functions show what will happen to the output of your
// page methods.
//
// For middleware authors: Be aware that these standardization functions will
// have been applied to the output of `next()` before you get access to it.
//
// These functions are also exposed via `PageUtil.standardize*`.

/**
 * This method takes in anything returned from a Page.getElements call and
 * returns the elements in a standardized format: an array of EarlyPromises of
 * ReactElements.
 */
function standardizeElements(elements) {

	// The return value could be a single element or an array.
	// First, let's make sure that it's an array.
	// Then, ensure that all elements are EarlyPromises.
	return PageUtil
		.makeArray(elements)
		.map(element => PromiseUtil.early(Q(element)));
}

function standardizeMetaTags(metaTags) {
	return PageUtil.makeArray(metaTags).map(metaTag => Q(metaTag));
}

function standardizeScripts(scripts) {
	return PageUtil.makeArray(scripts).map((script) => {
		if (script.href || script.text) {
			if (!script.type) script.type = "text/javascript";
			return script;
		}

		// if the answer was a string, let's make a script object
		return {href:script, type:"text/javascript"};
	})
}

function standardizeStyles(styles) {
	return PageUtil.makeArray(styles).map((style) => {
		if (style.href || style.text) {
			if (!style.type) style.type = "text/css";
			if (!style.media) style.media = "";

			return style;
		}

		// if the answer was a string, let's make a script object
		return {href:style, type:"text/css", media:""};
	})
}


var PageUtil = module.exports = {
	standardizeElements,
	standardizeMetaTags,
	standardizeScripts,
	standardizeStyles,

	/**
	 * Given an array of page instances, return an object that implements the page interface. This returned object's
	 * methods delegate to the first page in the pages array, passing the second page's implementation as the next
	 * variable (and the second page's implementation gets the third page's next, and so on). 
	 */
	createPageChain(pages) {
		var chain  = {}
		,   create = PageUtil.createObjectFunctionChain.bind(PageUtil, pages)
		Object.keys(PAGE_METHODS).forEach(method => {
			chain[method] = create
				.apply(null, [method].concat(PAGE_METHODS[method]));
		});
		return chain;
	},

	/**
	 * Given an array of objects and a function name, this returns a function that will call functionName on the first
	 * object, adding a next parameter to the end that is a function to call to the next object's implementation of functionName, and so on
	 * down the line. It is a way to make a middleware-like chain of functions, but the functions will be bound to the object in 
	 * question from objects.
	 * 
	 * The last object in the array will also receive a next parameter, which will call defaultImpl.
	 * 
	 * standardizeReturnValue will be called on every return value from functionName so that next will always return the same type. This
	 * is useful when a function can return one of many different types.
	 */
	createObjectFunctionChain(objects, functionName, argumentCount, defaultImpl, standardizeReturnValue) {<commit_msg>Increase verbosity in `createPageChain`<commit_after>var Q = require("q"), 
	PromiseUtil = require("./PromiseUtil");

// This data structure defines the page interface.
//
// Each item represents a method that page objects (and middleware) may override.
//
// The keys here are method names.
//
// The values are tuples containing:
//   - Number of arguments to the method.
//   - Default implementation of the method.
//   - Normalization function applied to method output.
//
// Note that each of these methods also receives an additional argument,
// which is the next implementation of the method in the call chain.
//     - Middleware implementations _should_ call this in most cases.*
//     - Page implementations _may_ call this (it will be the default implementation).
//
// * Consider carefully before deciding not to call `next()` in middleware.
// Other middleware (and the page itself) may exhibit undefined behavior if a
// given method is not called.  Generally, only skip calling `next()` for
// short-circuit responses (e.g. a redirect from `handleRoute`).
//
var PAGE_METHODS = {
	handleRoute        : [1, () => ({code: 200}), Q],
	getTitle           : [0, () => "", Q],
	getScripts         : [0, () => [], standardizeScripts],
	getSystemScripts   : [0, () => [], standardizeScripts],
	getHeadStylesheets : [0, () => [], standardizeStyles],
	getMetaTags        : [0, () => [], standardizeMetaTags],
	getCanonicalUrl    : [0, () => "", Q],
	getBase            : [0, () => null, Q],
	getBodyClasses     : [0, () => [], Q],
	getElements        : [0, () => [], standardizeElements],
	handleComplete     : [0, () => null, Q],
};

// These `standardize*` functions show what will happen to the output of your
// page methods.
//
// For middleware authors: Be aware that these standardization functions will
// have been applied to the output of `next()` before you get access to it.
//
// These functions are also exposed via `PageUtil.standardize*`.

/**
 * This method takes in anything returned from a Page.getElements call and
 * returns the elements in a standardized format: an array of EarlyPromises of
 * ReactElements.
 */
function standardizeElements(elements) {

	// The return value could be a single element or an array.
	// First, let's make sure that it's an array.
	// Then, ensure that all elements are EarlyPromises.
	return PageUtil
		.makeArray(elements)
		.map(element => PromiseUtil.early(Q(element)));
}

function standardizeMetaTags(metaTags) {
	return PageUtil.makeArray(metaTags).map(metaTag => Q(metaTag));
}

function standardizeScripts(scripts) {
	return PageUtil.makeArray(scripts).map((script) => {
		if (script.href || script.text) {
			if (!script.type) script.type = "text/javascript";
			return script;
		}

		// if the answer was a string, let's make a script object
		return {href:script, type:"text/javascript"};
	})
}

function standardizeStyles(styles) {
	return PageUtil.makeArray(styles).map((style) => {
		if (style.href || style.text) {
			if (!style.type) style.type = "text/css";
			if (!style.media) style.media = "";

			return style;
		}

		// if the answer was a string, let's make a script object
		return {href:style, type:"text/css", media:""};
	})
}


var PageUtil = module.exports = {
	standardizeElements,
	standardizeMetaTags,
	standardizeScripts,
	standardizeStyles,

	/**
	 * Given an array of page instances, return an object that implements the page interface. This returned object's
	 * methods delegate to the first page in the pages array, passing the second page's implementation as the next
	 * variable (and the second page's implementation gets the third page's next, and so on). 
	 */
	createPageChain(pages) {

		// This will be our return value.  It will be a mapping of
		// method names on page objects to chained function calls.
		var pageChain = {};

		for (var method in PAGE_METHODS){

			if (PAGE_METHODS.hasOwnProperty(method)){

				var [
					argumentCount,
					defaultImpl,
					standardizeReturnValue
				] = PAGE_METHODS[method];

				pageChain[method] = PageUtil
					.createObjectFunctionChain(
						pages,
						method,
						argumentCount,
						defaultImpl,
						standardizeReturnValue
					);
			}
		}

		return pageChain;
	},

	/**
	 * Given an array of objects and a function name, this returns a function that will call functionName on the first
	 * object, adding a next parameter to the end that is a function to call to the next object's implementation of functionName, and so on
	 * down the line. It is a way to make a middleware-like chain of functions, but the functions will be bound to the object in 
	 * question from objects.
	 * 
	 * The last object in the array will also receive a next parameter, which will call defaultImpl.
	 * 
	 * standardizeReturnValue will be called on every return value from functionName so that next will always return the same type. This
	 * is useful when a function can return one of many different types.
	 */
	createObjectFunctionChain(objects, functionName, argumentCount, defaultImpl, standardizeReturnValue) {
{'fraction_non_alphanumeric': 0.10946896340841912, 'fraction_numerical': 0.0028539394557129754, 'mean_word_length': 3.5091911764705883, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 34, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7518334', 'n_tokens_mistral': 2878, 'n_tokens_neox': 2665, 'n_words': 1098}