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
JavaScript
"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 = {
'"': """,
"\n": "
"
};
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 = {
"&": "&",
"<": "<",
">": ">",
'"': """,
"'": "'"
};
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(/"/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
});