UNPKG

rjweb-server

Version:

Easy and Robust Way to create a Web Server with Many Easy-to-use Features in NodeJS

314 lines (313 loc) 8.84 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var HTMLBuilder_exports = {}; __export(HTMLBuilder_exports, { default: () => HTMLBuilder, getFunctionArguments: () => getFunctionArguments, parseAttributes: () => parseAttributes }); module.exports = __toCommonJS(HTMLBuilder_exports); var import_rjutils_collection = require("rjutils-collection"); const f = (attribute) => { const replace = { '"': "&quot;", "\n": "&#xa" }; return attribute.replace(/["]|\n/g, (m) => replace[m]); }; const fF = (fn) => { let fnString = fn.toString(); let addStart = "", addEnd = "}"; fnString = fnString.replace("async", () => { addStart += "async"; return ""; }).replace("=>", () => { addStart += " function"; return "{"; }); return addStart + fnString + addEnd; }; const fH = (text) => { const replace = { "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#039;" }; return text.replace(/[&<>"']/g, (m) => replace[m]); }; const getFunctionArguments = (fn) => { return fn.toString().replace(/[/][/].*$/mg, "").replace(/\s+/g, "").replace(/[/][*][^/*]*[*][/]/g, "").split("){", 1)[0].replace(/^[^(]*[(]/, "").replace(/=[^,]+/g, "").split(",").filter(Boolean); }; const parseAttributes = (attributes, fnArguments) => { const result = []; Object.entries(attributes).forEach(([key, attribute]) => { let value = ""; switch (typeof attribute) { case "object": { if (Array.isArray(attribute)) { if (key === "class") { value = attribute.join(" "); } else { value = f(JSON.stringify(attribute)); } } else { if (key === "style") { Object.entries(attribute).forEach(([key2, val]) => { value += `${f(key2)}:${f(JSON.stringify(val)).replace(/&quot;/g, "")};`; }); } else { value = f(JSON.stringify(attribute)); } } break; } case "function": { value = f(`${fnArguments.map((arg) => `let ${arg.name}=${f(JSON.stringify(arg.value))};`).join("")}(${fF(attribute)})(this)`); break; } default: { value = f(String(attribute)); break; } } result.push(`${key.replace(/"/g, "")}="${value}"`); }); return result.join(" "); }; class HTMLBuilder { constructor(route, fnArguments = [], getEvery = [], everyId = { n: 0 }) { this.html = ""; this.fnArguments = fnArguments; this.getEveries = getEvery; this.route = route; this.everyId = everyId; } /** * Add a new HTML Tag * @example * ``` * ctr.printHTML((html) => html * .t('div', {}, (t) => t * .t('p', {}, (t) => t * .raw('hello world!') * ) * .t('p', {}, 'hello world!') * ) * ) * ``` * @since 6.6.0 */ t(tag, attributes, callback) { this.html += `<${tag} ${parseAttributes(attributes, this.fnArguments)}>`; if (typeof callback === "function") { const builder = new HTMLBuilder(this.route, [...this.fnArguments], this.getEveries, this.everyId); callback(builder); this.html += builder.html; } else { this.html += fH(String(callback)); } this.html += `</${tag}>`; return this; } /** * Add a new HTML Component * @example * ``` * const component = new HTMLComponent((html, options) => html * .t('p', {}, options?.hello) * ) * * ctr.printHTML((html) => html * .t('div', {}, (t) => t * .t('p', {}, (t) => t * .raw('hello world!') * ) * .c(component, { hello: 'Hello world!' }) * ) * ) * ``` * @since 6.7.0 */ c(component, options) { const builder = component["toBuilder"](this.route, [...this.fnArguments], this.getEveries, this.everyId, options); this.html += builder.html; return this; } /** * Add raw Content * @example * ``` * ctr.printHTML((html) => html * .t('div', {}, (t) => t * .t('p', {}, (t) => t * .raw('hello world!') * ) * ) * ) * ``` * @since 6.6.0 */ raw(content) { this.html += content; return this; } /** * Add escaped Content * @example * ``` * ctr.printHTML((html) => html * .t('div', {}, (t) => t * .t('p', {}, (t) => t * .escaped('hello world!') * ) * ) * ) * ``` * @since 6.6.2 */ escaped(content) { this.html += fH(String(content)); return this; } /** * Register Variables that will be added to every context * @warning This is required for native functions because they are being replicated 1:1 * @example * ``` * const version = '1.0.0' * * ctr.printHTML((html) => html * .var({ version }) * .t('button', { onclick() { alert(version) } }, (t) => t * .raw('click me for version!') * ) * ) * ``` * @since 6.6.0 */ var(variables) { Object.keys(variables).forEach((key) => { this.fnArguments.push({ name: key, value: variables[key] }); }); return this; } /** * Register Variables that will be added to every context * @example * ``` * const version = '1.0.0' * const showVersion = true * * ctr.printHTML((html) => html * .var({ version }) * .if(showVersion, (html) => html * .t('button', { onclick: () => { alert(version) } }, (t) => t * .raw('click me for version!') * ) * ) * ) * ``` * @since 6.6.1 */ if(state, callback) { if (state) { if (typeof callback === "function") { const builder = new HTMLBuilder(this.route, [...this.fnArguments], this.getEveries, this.everyId); callback(builder); this.html += builder.html; } else { this.html += String(callback); } } return this; } /** * Fetch a custom function every x ms * @example * ``` * const getNumbers = () => Array.from({ length: 5 }).map(() => Math.random()) * * ctr.printHTML((html) => html * .getEvery(getNumbers, 1000, (t, numbers) => t * .forEach(numbers, (t, number) => t * .if(number > 0.5, (t) => t * .t('h1', {}, 'Number is bigger than 0.5!') * ) * .t('p', {}, (t) => t * .raw(`Crazy Number: ${number}`) * ) * ) * ) * ) * ``` * @since 6.6.0 */ getEvery(getter, interval, callback) { const id = `${this.route.replace("/", "-")}___rId___${this.everyId.n++}___${(0, import_rjutils_collection.hashStr)({ text: callback.toString(), algorithm: "sha1" })}`; this.html += `<div id="${id}" style="display: contents;"></div>`; this.html += `<script type="text/javascript">setInterval(function(){var e=new XMLHttpRequest;e.onreadystatechange=function(){e.readyState===XMLHttpRequest.DONE&&e.status>199&&e.status<300&&(document.getElementById("${id}").innerHTML=e.responseText)},e.open("GET","/___rjweb-html-auto/${id}",!0),e.send()},${interval})</script>`; this.getEveries.push({ getter, callback, fnArguments: [...this.fnArguments, { name: getFunctionArguments(callback)[1].replace(")", ""), value: null }], id }); return this; } /** * Loop over an Array of Items * @example * ``` * const items = [ * 'Ben', * 'John', * 'Pork' * ] * * ctr.printHTML((html) => html * .t('div', {}, (t) => t * .forEach(items, (t, name) => t * .t('p', {}, (t) => t * .raw(`I love ${name}`) * ) * ) * ) * ) * ``` * @since 6.6.0 */ forEach(items, callback) { items.forEach((item) => { const builder = new HTMLBuilder(this.route, [...this.fnArguments, { name: getFunctionArguments(callback)[1].replace(")", ""), value: item }], this.getEveries, this.everyId); callback(builder, item); this.html += builder.html; }); return this; } } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { getFunctionArguments, parseAttributes });