| "use strict"; |
| module.exports = codegen; |
| |
| /** |
| * Begins generating a function. |
| * @memberof util |
| * @param {string[]} functionParams Function parameter names |
| * @param {string} [functionName] Function name if not anonymous |
| * @returns {Codegen} Appender that appends code to the function's body |
| */ |
| function codegen(functionParams, functionName) { |
| |
| /* istanbul ignore if */ |
| if (typeof functionParams === "string") { |
| functionName = functionParams; |
| functionParams = undefined; |
| } |
| |
| var body = []; |
| |
| /** |
| * Appends code to the function's body or finishes generation. |
| * @typedef Codegen |
| * @type {function} |
| * @param {string|Object.<string,*>} [formatStringOrScope] Format string or, to finish the function, an object of additional scope variables, if any |
| * @param {...*} [formatParams] Format parameters |
| * @returns {Codegen|Function} Itself or the generated function if finished |
| * @throws {Error} If format parameter counts do not match |
| */ |
| |
| function Codegen(formatStringOrScope) { |
| // note that explicit array handling below makes this ~50% faster |
| |
| // finish the function |
| if (typeof formatStringOrScope !== "string") { |
| var source = toString(); |
| if (codegen.verbose) |
| console.log("codegen: " + source); // eslint-disable-line no-console |
| source = "return " + source; |
| if (formatStringOrScope) { |
| var scopeKeys = Object.keys(formatStringOrScope), |
| scopeParams = new Array(scopeKeys.length + 1), |
| scopeValues = new Array(scopeKeys.length), |
| scopeOffset = 0; |
| while (scopeOffset < scopeKeys.length) { |
| scopeParams[scopeOffset] = scopeKeys[scopeOffset]; |
| scopeValues[scopeOffset] = formatStringOrScope[scopeKeys[scopeOffset++]]; |
| } |
| scopeParams[scopeOffset] = source; |
| return Function.apply(null, scopeParams).apply(null, scopeValues); // eslint-disable-line no-new-func |
| } |
| return Function(source)(); // eslint-disable-line no-new-func |
| } |
| |
| // otherwise append to body |
| var formatParams = new Array(arguments.length - 1), |
| formatOffset = 0; |
| while (formatOffset < formatParams.length) |
| formatParams[formatOffset] = arguments[++formatOffset]; |
| formatOffset = 0; |
| formatStringOrScope = formatStringOrScope.replace(/%([%dfijs])/g, function replace($0, $1) { |
| var value = formatParams[formatOffset++]; |
| switch ($1) { |
| case "d": case "f": return String(Number(value)); |
| case "i": return String(Math.floor(value)); |
| case "j": return JSON.stringify(value); |
| case "s": return String(value); |
| } |
| return "%"; |
| }); |
| if (formatOffset !== formatParams.length) |
| throw Error("parameter count mismatch"); |
| body.push(formatStringOrScope); |
| return Codegen; |
| } |
| |
| function toString(functionNameOverride) { |
| return "function " + (functionNameOverride || functionName || "") + "(" + (functionParams && functionParams.join(",") || "") + "){\n " + body.join("\n ") + "\n}"; |
| } |
| |
| Codegen.toString = toString; |
| return Codegen; |
| } |
| |
| /** |
| * Begins generating a function. |
| * @memberof util |
| * @function codegen |
| * @param {string} [functionName] Function name if not anonymous |
| * @returns {Codegen} Appender that appends code to the function's body |
| * @variation 2 |
| */ |
| |
| /** |
| * When set to `true`, codegen will log generated code to console. Useful for debugging. |
| * @name util.codegen.verbose |
| * @type {boolean} |
| */ |
| codegen.verbose = false; |