"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.HotFile = void 0;
const fs = __importStar(require("fs"));
const node_fetch_1 = __importDefault(require("node-fetch"));
const Hot_1 = require("./Hot");
/**
 * A file to process.
 */
class HotFile {
    constructor(copy = {}) {
        this.page = copy.page || null;
        this.name = copy.name || "";
        this.url = copy.url || "";
        this.localFile = copy.localFile || "";
        this.content = copy.content || "";
        this.throwAllErrors = copy.throwAllErrors || false;
    }
    /**
     * Set the content of this file.
     */
    setContent(content) {
        this.content = content;
    }
    /**
     * Get the content of this file.
     */
    getContent() {
        return (this.content);
    }
    /**
     * Make a HTTP get request.
     */
    static httpGet(url) {
        return __awaiter(this, void 0, void 0, function* () {
            try {
                let res = yield (0, node_fetch_1.default)(url);
                if (res.ok === false)
                    throw new Error(`${res.status}: ${res.statusText}`);
                let content = yield res.text();
                return (content);
            }
            catch (ex) {
                return (JSON.stringify({ "error": `${ex.message} - Could not fetch ${url}` }));
            }
        });
    }
    /**
     * Load content from a url.
     */
    loadUrl() {
        return __awaiter(this, void 0, void 0, function* () {
            let t0 = null;
            if (Hot_1.Hot.CurrentPage != null) {
                if (Hot_1.Hot.Debugger != null) {
                    if (Hot_1.Hot.Debugger.benchmark === true) {
                        t0 = performance.now();
                        Hot_1.Hot.CurrentPage.processor.logger.info(`Downloading file "${this.name}" from "${this.url}"...`);
                    }
                }
            }
            this.content = yield HotFile.httpGet(this.url);
            if (Hot_1.Hot.CurrentPage != null) {
                if (Hot_1.Hot.Debugger != null) {
                    if (Hot_1.Hot.Debugger.benchmark === true) {
                        let t1 = performance.now();
                        let elapsed = t1 - t0;
                        Hot_1.Hot.CurrentPage.processor.logger.info(`Downloaded file "${this.name}" from "${this.url}" in ${elapsed.toFixed(2)} ms.`);
                    }
                }
            }
            return (this.content);
        });
    }
    /**
     * Load content from a local file.
     */
    loadLocalFile() {
        return __awaiter(this, void 0, void 0, function* () {
            let promise = new Promise((resolve, reject) => {
                fs.readFile(this.localFile, (err, data) => {
                    if (err != null)
                        throw err;
                    let content = data.toString();
                    this.content = content;
                    resolve(this.content);
                });
            });
            return (promise);
        });
    }
    /**
     * Load the contents of the file.
     */
    load() {
        return __awaiter(this, void 0, void 0, function* () {
            let content = "";
            if (this.url !== "")
                content = yield this.loadUrl();
            if (this.localFile !== "")
                content = yield this.loadLocalFile();
            return (content);
        });
    }
    /**
     * Process string content. This will take in a regular expression and
     * parse the content based on the regex. When the regex content is found
     * contentProcessor will be executed with the regex content found. When
     * the regex content is not found, offContentProcessor will be called with
     * the content outside of the regex.
     *
     * @param content The content to parse.
     * @param contentRegex The regex to use to parse the content.
     * @param contentProcessor The content found inside the regex.
     * @param offContentProcessor The content found outside of the regex.
     * @param numRemoveFromBeginning The number of characters to remove from the
     * beginning of the found content.
     * @param numRemoveFromEnd The number of characters to remove from the end of
     * the found content.
     */
    static processContent(content, contentRegex, contentProcessor, offContentProcessor, numRemoveFromBeginning = 2, numRemoveFromEnd = 2) {
        let result = contentRegex.exec(content);
        let previousIndex = 0;
        let output = "";
        while (result != null) {
            let start = result.index - numRemoveFromBeginning;
            let end = contentRegex.lastIndex + numRemoveFromEnd;
            // Get the previous section.
            let prevContent = content.substr(previousIndex, (start - previousIndex));
            previousIndex = end;
            output += offContentProcessor(prevContent);
            // Process the content found from the regex
            let contentFound = result[0];
            output += contentProcessor(contentFound);
            // Move on to the next section to parse.
            result = contentRegex.exec(content);
        }
        // Append whatever else is after the last parsed section.
        let lastContent = content.substr(previousIndex);
        output += offContentProcessor(lastContent);
        return (output);
    }
    /**
     * Process any content that could have nested values. This will
     * take in a regular expression and
     * parse the content based on the regex. When the regex content is found
     * contentProcessor will be executed with the regex content found. When
     * the regex content is not found, offContentProcessor will be called with
     * the content outside of the regex.
     *
     * @fixme Needs to be able to ignore any characters found inside comments
     * or a string. For example, if the following is used ```${"Test }"}``` It
     * will error out.
     *
     * @param content The content to parse.
     * @param startChars The starting characters to search for.
     * @param endChars The ending characters to search for.
     * @param triggerChar The found character where parsing will start from.
     * @param contentProcessor The content found inside the regex.
     * @param offContentProcessor The content found outside of the regex.
     * @param numRemoveFromBeginning The number of characters to remove from the
     * beginning of the found content.
     * @param numRemoveFromEnd The number of characters to remove from the end of
     * the found content.
     */
    static processNestedContent(content, startChars, endChars, triggerChar, contentProcessor, offContentProcessor, numRemoveFromBeginning = 2, numRemoveFromEnd = 1) {
        let pos = content.indexOf(startChars);
        let previousIndex = 0;
        let startTriggerPos = content.indexOf(triggerChar, pos);
        let output = "";
        while (pos > -1) {
            let end = content.indexOf(endChars, pos);
            let nestedCounter = 0;
            if (triggerChar !== "") {
                // Reverse search the trigger characters and count the number of 
                // occurrences.
                let rpos = content.lastIndexOf(triggerChar, end - numRemoveFromEnd);
                while (rpos > -1) {
                    if (rpos === startTriggerPos)
                        break;
                    rpos = content.lastIndexOf(triggerChar, rpos - numRemoveFromEnd);
                    nestedCounter++;
                }
            }
            // If there's nested trigger characters, get the last occurrence of 
            // the end character.
            if (nestedCounter > 0) {
                let epos = content.indexOf(endChars, end + numRemoveFromEnd);
                let tempepos = epos;
                while ((epos > -1) && (nestedCounter > 0)) {
                    if (tempepos < 0)
                        break;
                    // Make sure we aren't discovering endChars that we shouldn't be.
                    let posOutsideOfContent = content.lastIndexOf(startChars, tempepos - numRemoveFromEnd);
                    if (posOutsideOfContent > epos)
                        break;
                    epos = tempepos;
                    tempepos = content.indexOf(endChars, epos + numRemoveFromEnd);
                    nestedCounter--;
                }
                end = epos;
            }
            let offContentStr = content.substr(previousIndex, (pos - previousIndex));
            output += offContentProcessor(offContentStr);
            let foundContent = content.substr(pos + numRemoveFromBeginning, (end - (pos + numRemoveFromBeginning)));
            output += contentProcessor(foundContent, pos, end);
            // Get the next content
            pos = content.indexOf(startChars, end + numRemoveFromEnd);
            startTriggerPos = content.indexOf(triggerChar, pos);
            previousIndex = end + numRemoveFromEnd;
        }
        // Append whatever else is after the last parsed section.
        let lastContent = content.substr(previousIndex);
        output += offContentProcessor(lastContent);
        return (output);
    }
    /**
     * Parse a function from a string. Ex: <(a, b, c)=>{return (a + b + c);}>
     */
    static parseFunction(str, callbackA, callbackB) {
        str = HotFile.processHotDomBlocks(str, "\`");
        let startIndex = str.indexOf("<(");
        while (startIndex > -1) {
            const endIndex = str.indexOf(")", startIndex);
            const arrowIndex = str.indexOf("=>", endIndex);
            const braceIndex = str.indexOf("{", arrowIndex);
            let nextPos = endIndex;
            if ((startIndex !== -1) &&
                (endIndex !== -1) && (arrowIndex !== -1) &&
                (braceIndex !== -1)) {
                let possibleEnds = ["}>", "}A>", "}a>", "}R>", "}RA>", "}Ra>"];
                let endPos = -1;
                let foundEnd = null;
                // Find the nearest end tag
                for (let i = 0; i < possibleEnds.length; i++) {
                    let possibleEnd = possibleEnds[i];
                    let possibleEndPos = str.indexOf(possibleEnd, arrowIndex);
                    if (possibleEndPos > -1 && (endPos == -1 || possibleEndPos < endPos)) {
                        endPos = possibleEndPos;
                        foundEnd = possibleEnd;
                    }
                }
                if (endPos > -1) {
                    const a = str.slice(startIndex + 2, endIndex).trim().split(",").map(arg => arg.trim());
                    const b = str.slice(braceIndex + 1, endPos).trim();
                    callbackA(a);
                    let out = callbackB(b, foundEnd);
                    str = str.slice(0, startIndex) + out + str.slice(endPos + foundEnd.length);
                    nextPos = endPos;
                }
            }
            startIndex = str.indexOf("<(", nextPos);
        }
        return (str);
    }
    /**
     * Process \<hot-dom> blocks.
     */
    static processHotDomBlocks(input, quotes = "\`") {
        let output = input.replace(/\<hot\-dom\>([\s\S]*?)\<\/hot\-dom\>/gi, (match, innerContent) => {
            // Replace ${...} inside the hot-dom content with wrapped version
            let transformed = innerContent.replace(/\$\{(.*?)\}/g, (_, expr) => {
                return `#$%#@{HotStaq.sanitizeHTML(${expr.trim()})}`;
            });
            transformed = innerContent.replace(/\$\\\{(.*?)\}/g, (_, expr) => {
                return `#$%#@{HotStaq.sanitizeHTML(${expr.trim()})}`;
            });
            // Return string that will be interpreted at runtime
            return `HotStaq.addHtmlUnsafe(null,${quotes}${transformed}${quotes})`;
        });
        output = output.replace(/\<hot\-dom\-escape\>([\s\S]*?)\<\/hot\-dom\-escape\>/gi, (match, innerContent) => {
            // Replace ${...} inside the hot-dom content with wrapped version
            let transformed = innerContent.replace(/\$\{(.*?)\}/g, (_, expr) => {
                return `^$&#@{HotStaq.sanitizeHTML(${expr.trim()})}`;
            });
            transformed = innerContent.replace(/\$\\\{(.*?)\}/g, (_, expr) => {
                return `^$&#@{HotStaq.sanitizeHTML(${expr.trim()})}`;
            });
            // Return string that will be interpreted at runtime
            return `HotStaq.addHtmlUnsafe(null,${quotes}${transformed}${quotes})`;
        });
        return (output);
    }
    /**
     * Parse all the content into a single JavaScript file to be executed. async/await is used
     * in the processed JavaScript file, which means the .hott files parsed may use async/await
     * within the code.
     *
     * Will parse the following in order:
     * * <* JavaScript content to execute and output. Will output using Hot.echo. *>
     * * @( Safely creates DOM from HTML content with any user input that was supplied. Any user inputs should be passed using @{input} )
     * * STR{ Execute some JS, and output a string using JSON.stringify. }
     * * ${ Execute some JS, and output the result. }
     * * <(arguments)=>{ Some JS to execute at a later time. }>
     * 	* This entire block will be parsed as a function, and will immediately output "Hot.CurrentPage.callFunction" in its place.
     * * ?( Execute some JS, must return a string which will be attached to the HTML DOM object it's used on. )
     *
     * @param thisContent The content to parse.
     * @param throwAllErrors If set to true, any error that occurs will be thrown as an exception.
     * @param options The options to use when parsing the content.
     */
    static parseContent(thisContent, throwAllErrors, parserOptions = null) {
        if (parserOptions == null) {
            parserOptions = {
                outputCommands: true,
                allowStringify: true
            };
        }
        let STRINGIFY_START = "JSON.stringify (";
        let STRINGIFY_END = ")";
        if (parserOptions.allowStringify === false) {
            STRINGIFY_START = "";
            STRINGIFY_END = "";
        }
        // Assemble the JS to evaluate. This will take all content outside of 
        // <* and *> and wrap a Hot.echo around it. Any JS found inside of the 
        // <* and *> will be executed as is.
        let output = HotFile.processContent(thisContent, new RegExp("(?=\\<\\*)([\\s\\S]*?)(?=\\*\\>)", "g"), (regexFound) => {
            // A little hack, since I suck at Regex :(
            regexFound = regexFound.substr(2);
            return (`${regexFound}`);
        }, (offContent) => {
            if (offContent === "")
                return ("");
            let tempOutput = offContent;
            let tempOutput2 = HotFile.processNestedContent(tempOutput, "STR{", "}", "{", (regexFound2, startPos, endPos) => {
                let out = "";
                if (parserOptions.outputCommands === true)
                    out = `*&&%*%@#@!echoOutput (JSON.stringify(${regexFound2}), ${throwAllErrors});*&!#%@!@*!`;
                else
                    out = `*&&%*%@#@!${STRINGIFY_START}${regexFound2}${STRINGIFY_END}, ${throwAllErrors});*&!#%@!@*!`;
                return (out);
            }, (offContent3) => {
                return (offContent3);
            }, 4, 1);
            let funcArgsStr = "";
            let tempOutput3 = HotFile.parseFunction(tempOutput2, (funcArgs) => {
                funcArgsStr = JSON.stringify(funcArgs);
            }, (funcBody, endType) => {
                //const escapedBody: string = funcBody.replace(/[\\'"\n\r\t]/g, '\\$&');
                const escapedBody = funcBody.replace(/\`/g, "\\`");
                let functionCall = "Hot.CurrentPage.callFunction";
                let isAsync = "false";
                if (endType === "}A>") {
                    functionCall = "await Hot.CurrentPage.callAsyncFunction";
                    isAsync = "true";
                }
                if (endType === "}a>") {
                    functionCall = "Hot.CurrentPage.callAsyncFunction";
                    isAsync = "true";
                }
                if (endType === "}R>")
                    functionCall = "return Hot.CurrentPage.callFunction";
                if (endType === "}RA>") {
                    functionCall = "return await Hot.CurrentPage.callAsyncFunction";
                    isAsync = "true";
                }
                if (endType === "}Ra>") {
                    functionCall = "return Hot.CurrentPage.callAsyncFunction";
                    isAsync = "true";
                }
                let newValue = `*&&%*%@#@!{
const newFuncName = createFunction (null, ${funcArgsStr}, \`${escapedBody}\`, ${isAsync});
Hot.echo (\`${functionCall} (this, '\${newFuncName}', arguments);\`);
}*&!#%@!@*!`;
                // Replace any ${ with ${&&!*#!!
                newValue = newValue.replace(/\$\{/g, "${&&!*#!!");
                return (newValue);
            });
            let tempOutput4 = HotFile.processNestedContent(tempOutput3, "${", "}", "{", (regexFound2, startPos, endPos) => {
                let out = "";
                let outputCmds = parserOptions.outputCommands;
                if (regexFound2.indexOf("&&!*#!!") > -1) {
                    const tempStr = regexFound2.replace(/&&\!\*\#\!\!/g, "");
                    return (`\${(typeof (${tempStr}) !== "undefined") ? ${tempStr} : "\${${tempStr}}"}`);
                }
                if (outputCmds === true) {
                    let escapeOutput = (content) => {
                        return (content.replace(/[`]/g, '\\`'));
                    };
                    out = `*&&%*%@#@!try { Hot.echo (${regexFound2}); }catch (ex){Hot.echo (\`\\\${${escapeOutput(regexFound2)}}\`);}*&!#%@!@*!`;
                    if (throwAllErrors === true)
                        out = `*&&%*%@#@!Hot.echo (${regexFound2});*&!#%@!@*!`;
                }
                else
                    out = `*&&%*%@#@!${regexFound2}*&!#%@!@*!`;
                return (out);
            }, (offContent3) => {
                return (offContent3);
                /*let escapedContent: string = JSON.stringify (offContent3);
                let out: string = `echoOutput (${escapedContent}, ${throwAllErrors});\n`;

                return (out);*/
            });
            tempOutput4 = HotFile.processHotDomBlocks(tempOutput4);
            let tempOutput5 = "";
            // Any ?() will be ignored in production mode.
            if (Hot_1.Hot.Mode === Hot_1.DeveloperMode.Production) {
                tempOutput5 = HotFile.processNestedContent(tempOutput4, "?(", ")", "(", (regexFound2, startPos, endPos) => {
                    return ("");
                }, (offContent3) => {
                    return (offContent3);
                    /*let out: string = `echoOutput (${offContent3}, ${throwAllErrors});\n`;

                    return (out);*/
                });
            }
            if (Hot_1.Hot.Mode === Hot_1.DeveloperMode.Development) {
                tempOutput5 = HotFile.processNestedContent(tempOutput4, "?(", ")", "(", (regexFound2, startPos, endPos) => {
                    let foundStr = "";
                    try {
                        // Check to see if it be parsed. If so, stringify it.
                        JSON.parse(regexFound2);
                        if (parserOptions.allowStringify === true)
                            foundStr = JSON.stringify(regexFound2);
                        else
                            foundStr = `${regexFound2}`;
                    }
                    catch (ex) {
                        // If valid JSON is not received, don't worry about it, pass it 
                        // along to the function below for it to be parsed in the page.
                        // The exception should be thrown there instead.
                        foundStr = `${regexFound2}`;
                    }
                    /// @fixme Make this a callable function and pass foundStr, etc.
                    let out = "";
                    if (parserOptions.outputCommands === true) {
                        out = `*&&%*%@#@!{
const testElm = createTestElement (${foundStr});
Hot.echo (\`data-test-object-name = "\${testElm.name}" data-test-object-func = "\${testElm.func}" data-test-object-value = "\${testElm.value}"\`);
}*&!#%@!@*!\n`;
                    }
                    else {
                        let createTestElement = (foundStr2) => {
                            let testElm = null;
                            try {
                                let obj = foundStr2;
                                if (typeof (foundStr2) === "string")
                                    obj = JSON.parse(foundStr2);
                                if (typeof (obj) === "string")
                                    testElm = new Hot_1.Hot.HotTestElement(obj);
                                if (obj instanceof Array)
                                    testElm = new Hot_1.Hot.HotTestElement(obj[0], obj[1], obj[2]);
                                if (obj["name"] != null)
                                    testElm = new Hot_1.Hot.HotTestElement(obj);
                                if (Hot_1.Hot.CurrentPage.testElements[testElm.name] != null)
                                    throw new Error(`Test element ${testElm.name} already exists!`);
                            }
                            catch (ex) {
                                throw new Error(`Error processing test element ${foundStr2} in ${Hot_1.Hot.CurrentPage.name}. Error: ${ex.message}`);
                            }
                            return (testElm);
                        };
                        const testElm = createTestElement(foundStr);
                        out = `*&&%*%@#@!data-test-object-name = "${testElm.name}" data-test-object-func = "${testElm.func}" data-test-object-value = "${testElm.value}"*&!#%@!@*!`;
                    }
                    return (out);
                }, (offContent3) => {
                    return (offContent3);
                    /*let out: string = `echoOutput (${offContent3}, ${throwAllErrors});\n`;

                    return (out);*/
                });
            }
            let tempOutput6 = HotFile.processNestedContent(tempOutput5, "*&&%*%@#@!", "*&!#%@!@*!", "*&&%*%@#@!", (regexFound, startPos, endPos) => {
                return (regexFound);
            }, (offContent) => {
                let escapedContent = "";
                if (parserOptions.allowStringify === true)
                    escapedContent = JSON.stringify(offContent);
                else
                    escapedContent = offContent;
                let out = "";
                if (parserOptions.outputCommands === true)
                    out = `echoOutput (${escapedContent}, ${throwAllErrors});\n`;
                else
                    out = escapedContent;
                return (out);
            }, "*&&%*%@#@!".length, "*&!#%@!@*!".length);
            /// @fixme Temporary hack. These delimiters should be removed from tempOutput when 
            /// executing processNestedContent.
            tempOutput6 = tempOutput6.replace(/\*\&\&\%\*\%\@\#\@\!/g, "");
            tempOutput6 = tempOutput6.replace(/\*\&\!\#\%\@\!\@\*\!/g, "");
            return (tempOutput6);
        }, 0);
        // Replace all instances of #$%#@{ with ${
        output = output.replace(/\#\$\%\#\@\{/g, "${");
        // Replace all instances of ^$&#@{ with $\\{
        output = output.replace(/\^\$\&\#\@\{/g, "$\\\\{");
        return (output);
    }
    /**
     * Process the content in this file. This treats each file as one large JavaScript
     * file. Any text outside of the <* *> areas will be treated as:
     *
     * 		Hot.echoUnsafe ("text");
     *
     * @fixme The regex's in the offContent functions need to be fixed. There's several
     * test cases where they will fail.
     */
    process() {
        return __awaiter(this, arguments, void 0, function* (args = null) {
            let t0 = null;
            if (Hot_1.Hot.Debugger != null) {
                if (Hot_1.Hot.Debugger.benchmark === true) {
                    t0 = performance.now();
                    Hot_1.Hot.Debugger.processCount++;
                }
            }
            let thisContent = this.content;
            if (args != null) {
                if (args instanceof Array)
                    throw new Error(`In ${this.name}, the passed arguments received cannot be an array!`);
            }
            let tempArgs = Hot_1.Hot.Arguments;
            Hot_1.Hot.Mode = this.page.processor.mode;
            Hot_1.Hot.Arguments = args;
            Hot_1.Hot.CurrentPage = this.page;
            Hot_1.Hot.PublicKeys = this.page.processor.publicKeys;
            Hot_1.Hot.API = this.page.getAPI();
            Hot_1.Hot.TesterAPI = this.page.getTesterAPI();
            let output = HotFile.parseContent(thisContent, this.throwAllErrors);
            // Execute the assembled JS file.
            let returnedOutput = null;
            try {
                let executionContent = `
			var Hot = arguments[0];
			var PassedHotFile = arguments[1];

			`;
                // Output the arguments so it's usable in the entire document.
                if (typeof (args) === "string")
                    throw new Error(`The passing arguments cannot be a string!`);
                for (let key in args) {
                    let newVar = "";
                    let newVarValue = args[key];
                    let newVarValueStr = JSON.stringify(newVarValue);
                    newVar = `var ${key} = ${newVarValueStr};\n`;
                    executionContent += newVar;
                }
                let contentName = this.name;
                if (contentName === "")
                    contentName = this.localFile;
                if (contentName === "")
                    contentName = this.url;
                executionContent += `
			/**
			 * Helper function to output content.
			 */
			function echoOutput (content, throwErrors)
			{
				if (throwErrors == null)
					throwErrors = true;

				if (throwErrors === true)
				{
					Hot.echoUnsafe (content);

					return;
				}

				try
				{
					Hot.echoUnsafe (content);
				}
				catch (ex)
				{
					Hot.echoUnsafe ("");
				}
			}

			/**
			 * Outputs a \${JS Content} value.
			 */
			function outputStr (value, possibleValue)
			{
				let result = \`\\\${\${value}}\`;

				try
				{
					if (possibleValue != null)
						result = possibleValue;
					else
						result = eval (value);
				}
				catch (ex)
				{
				}

				return (result);
			}

			/**
			 * Create a function for later execution on this page.
			 */
			function createFunction (name, args, funcBody, isAsync)
			{
				return (Hot.CurrentPage.addFunction (name, args, funcBody, isAsync));
			}

			/**
			 * Create a test element.
			 */
			function createTestElement (foundStr)
			{
				let testElm = null;

				try
				{
					let obj = foundStr;

					if (typeof (foundStr) === "string")
						obj = JSON.parse (foundStr);

					if (typeof (obj) === "string")
						testElm = new Hot.HotTestElement (obj);

					if (obj instanceof Array)
						testElm = new Hot.HotTestElement (obj[0], obj[1], obj[2]);

					if (obj["name"] != null)
						testElm = new Hot.HotTestElement (obj);

					if (Hot.CurrentPage.testElements[testElm.name] != null)
						throw new Error (\`Test element \${testElm.name} already exists!\`);

					Hot.CurrentPage.addTestElement (testElm);
				}
				catch (ex)
				{
					throw new Error (
			\`Error processing test element \${foundStr} in \${Hot.CurrentPage.name}. Error: \${ex.message}\`
						);
				}

				return (testElm);
			}

			async function runContent (CurrentHotFile)
			{\n`;
                executionContent += output;
                executionContent += `
			}

			return (runContent (PassedHotFile).then (() =>
			{
				return ({
						hot: Hot,
						output: Hot.Output,
						data: JSON.stringify (Hot.Data)
					});
			}));`;
                /// @fixme Prior to execution compile any TypeScript and make it ES5 compatible.
                let func = new Function(executionContent);
                returnedOutput = yield func.apply(this, [Hot_1.Hot, this]);
            }
            catch (ex) {
                if (ex instanceof SyntaxError) {
                    /// @fixme Put what's in the content variable into a prev content variable?
                    /// Then once there's no longer any syntax errors being thrown, execute the 
                    /// code? This would also require saving any HTML outside of the *> and <* 
                    /// then echoing it out. The throw below would have to be removed as well.
                    throw ex;
                }
                else
                    throw ex;
            }
            Hot_1.Hot.Data = returnedOutput.hot.Data;
            let finalOutput = returnedOutput.output;
            Hot_1.Hot.Output = "";
            Hot_1.Hot.Arguments = tempArgs;
            if (Hot_1.Hot.Debugger != null) {
                if (Hot_1.Hot.Debugger.benchmark === true) {
                    let t1 = performance.now();
                    let elapsed = t1 - t0;
                    Hot_1.Hot.Debugger.processTotalTime += elapsed;
                    if (Hot_1.Hot.Debugger.processCount > 0)
                        Hot_1.Hot.Debugger.processAvgTime = (Hot_1.Hot.Debugger.processTotalTime / Hot_1.Hot.Debugger.processCount);
                    let from = this.localFile;
                    if (this.url !== "")
                        from = this.url;
                    Hot_1.Hot.CurrentPage.processor.logger.info(`Processed file "${this.name}" from "${from}" in ${elapsed.toFixed(2)} ms. Average time: ${Hot_1.Hot.Debugger.processAvgTime.toFixed(2)} ms.`);
                }
            }
            return (finalOutput);
        });
    }
}
exports.HotFile = HotFile;
//# sourceMappingURL=HotFile.js.map