hmpl-js
Version:
🐜 Server-oriented customizable templating for JavaScript
1,462 lines (1,460 loc) • 47.1 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/main.ts
var main_exports = {};
__export(main_exports, {
compile: () => compile,
stringify: () => stringify
});
module.exports = __toCommonJS(main_exports);
var import_json5 = __toESM(require("json5"));
var import_dompurify = __toESM(require("dompurify"));
var SOURCE = `src`;
var METHOD = `method`;
var ID = `initId`;
var AFTER = `after`;
var REPEAT = `repeat`;
var MEMO = `memo`;
var INDICATORS = `indicators`;
var AUTO_BODY = `autoBody`;
var COMMENT = `hmpl`;
var FORM_DATA = `formData`;
var DISALLOWED_TAGS = `disallowedTags`;
var SANITIZE = `sanitize`;
var ALLOWED_CONTENT_TYPES = "allowedContentTypes";
var REQUEST_INIT_GET = `get`;
var INTERVAL = `interval`;
var RESPONSE_ERROR = `BadResponseError`;
var REQUEST_INIT_ERROR = `RequestInitError`;
var RENDER_ERROR = `RenderError`;
var REQUEST_COMPONENT_ERROR = `RequestComponentError`;
var COMPILE_OPTIONS_ERROR = `CompileOptionsError`;
var PARSE_ERROR = `ParseError`;
var COMPILE_ERROR = `CompileError`;
var DEFAULT_AUTO_BODY = {
formData: true
};
var DEFAULT_FALSE_AUTO_BODY = {
formData: false
};
var REQUEST_OPTIONS = [
SOURCE,
METHOD,
ID,
AFTER,
REPEAT,
INDICATORS,
MEMO,
AUTO_BODY,
ALLOWED_CONTENT_TYPES,
DISALLOWED_TAGS,
SANITIZE,
INTERVAL
];
var VALID_METHODS = [
"get",
"post",
"put",
"delete",
"patch",
"trace",
"options"
];
var CODES = [
100,
101,
102,
103,
300,
301,
302,
303,
304,
305,
306,
307,
308,
400,
401,
402,
403,
404,
405,
406,
407,
408,
409,
410,
411,
412,
413,
414,
415,
416,
417,
418,
421,
422,
423,
424,
425,
426,
428,
429,
431,
451,
500,
501,
502,
503,
504,
505,
506,
507,
508,
510,
511
];
var DISALLOWED_TAGS_VALUES = ["script", "style", "iframe"];
var DEFAULT_SANITIZE = false;
var DEFAULT_ALLOWED_CONTENT_TYPES = ["text/html"];
var DEFAULT_DISALLOWED_TAGS = [];
var checkObject = (val) => {
return typeof val === "object" && !Array.isArray(val) && val !== null;
};
var checkIsStringArray = (arr, currentError) => {
if (!Array.isArray(arr)) return false;
let isArrString = true;
for (let i = 0; i < arr.length; i++) {
const arrItem = arr[i];
if (typeof arrItem !== "string") {
createError(
`${currentError}: In the array, the element with index ${i} is not a string`
);
isArrString = false;
break;
}
}
return isArrString;
};
var checkFunction = (val) => {
return Object.prototype.toString.call(val) === "[object Function]";
};
var createError = (text) => {
throw new Error(text);
};
var createWarning = (text) => {
console.warn(text);
};
var getIsMethodValid = (method) => {
return VALID_METHODS.includes(method.toLowerCase());
};
var getTemplateWrapper = (str, sanitize = false) => {
let sanitizedStr = str;
if (sanitize) {
sanitizedStr = import_dompurify.default.sanitize(str);
}
const elementDocument = new DOMParser().parseFromString(
`<template>${sanitizedStr}</template>`,
"text/html"
);
const elWrapper = elementDocument.childNodes[0].childNodes[0].firstChild;
return elWrapper;
};
var getResponseElements = (response, disallowedTags = [], sanitize) => {
const elWrapper = getTemplateWrapper(response, sanitize);
const elContent = elWrapper["content"];
for (let i = 0; i < disallowedTags.length; i++) {
const tag = disallowedTags[i];
const elements = elContent.querySelectorAll(tag);
for (let j = 0; j < elements.length; j++) {
elContent.removeChild(elements[j]);
}
}
return elWrapper;
};
var getIsNotAllowedContentType = (contentType, allowedContentTypes) => {
if (!contentType) return true;
let isContain = false;
for (let i = 0; i < allowedContentTypes.length; i++) {
const allowedContentType = allowedContentTypes[i];
if (contentType.includes(allowedContentType)) {
isContain = true;
break;
}
}
return !isContain;
};
var makeRequest = (el, mainEl, dataObj, method, source, isRequest, isRequests, isMemo, options = {}, templateObject, allowedContentTypes, disallowedTags, sanitize, reqObject, indicators, currentClearInterval) => {
const {
mode,
cache,
redirect,
get,
referrerPolicy,
signal,
credentials,
timeout,
referrer,
headers,
body,
window: windowOption,
integrity
} = options;
const initRequest = {
method: method.toUpperCase()
};
if (credentials !== void 0) {
initRequest.credentials = credentials;
}
if (body !== void 0) {
initRequest.body = body;
}
if (mode !== void 0) {
initRequest.mode = mode;
}
if (cache !== void 0) {
initRequest.cache = cache;
}
if (redirect !== void 0) {
initRequest.redirect = redirect;
}
if (referrerPolicy !== void 0) {
initRequest.referrerPolicy = referrerPolicy;
}
if (integrity !== void 0) {
initRequest.integrity = integrity;
}
if (referrer !== void 0) {
initRequest.referrer = referrer;
}
const isHaveSignal = signal !== void 0;
if (isHaveSignal) {
initRequest.signal = signal;
}
if (windowOption !== void 0) {
initRequest.window = windowOption;
}
if (options.keepalive !== void 0) {
createWarning(
`${REQUEST_INIT_ERROR}: The "keepalive" property is not yet supported`
);
}
if (headers) {
if (checkObject(headers)) {
const newHeaders = new Headers();
for (const key in headers) {
const value = headers[key];
const valueType = typeof value;
if (valueType === "string") {
newHeaders.set(key, value);
} else {
createError(
`${REQUEST_INIT_ERROR}: Expected type string, but received type ${valueType}`
);
}
}
initRequest.headers = newHeaders;
} else {
createError(
`${REQUEST_INIT_ERROR}: The "headers" property must contain a value object`
);
}
}
if (timeout) {
if (!isHaveSignal) {
initRequest.signal = AbortSignal.timeout(timeout);
} else {
createWarning(
`${REQUEST_INIT_ERROR}: The "signal" property overwrote the AbortSignal from "timeout"`
);
}
}
const isRequestMemo = isMemo && !isRequest && dataObj?.memo;
const getIsNotFullfilledStatus = (status) => status === "rejected" || typeof status === "number" && (status < 200 || status > 299);
const requestContext = getInstanceContext(
void 0,
currentClearInterval
);
const callGetResponse = (reqResponse) => {
if (isRequests) {
reqObject.response = reqResponse;
get?.("response", reqResponse, requestContext, reqObject);
}
get?.("response", mainEl, requestContext);
};
const updateNodes = (content, isClone = true, isNodes = false) => {
if (isRequest) {
templateObject.response = content.cloneNode(true);
get?.("response", content, requestContext);
} else {
let reqResponse = [];
const newContent = isClone ? content.cloneNode(true) : content;
const nodes = [...newContent.content.childNodes];
if (dataObj.nodes) {
const parentNode = dataObj.parentNode;
const newNodes = [];
const nodesLength = dataObj.nodes.length;
for (let i = 0; i < nodesLength; i++) {
const node = dataObj.nodes[i];
if (i === nodesLength - 1) {
for (let j = 0; j < nodes.length; j++) {
const reqNode = nodes[j];
const newNode = parentNode.insertBefore(reqNode, node);
newNodes.push(newNode);
}
}
parentNode.removeChild(node);
}
reqResponse = newNodes.slice();
dataObj.nodes = newNodes;
} else {
const parentNode = el.parentNode;
const newNodes = [];
const nodesLength = nodes.length;
for (let i = 0; i < nodesLength; i++) {
const node = nodes[i];
const newNode = parentNode.insertBefore(node, el);
newNodes.push(newNode);
}
parentNode.removeChild(el);
reqResponse = newNodes.slice();
dataObj.nodes = newNodes;
dataObj.parentNode = parentNode;
}
if (isRequestMemo && isNodes) {
dataObj.memo.nodes = dataObj.nodes;
if (dataObj.memo.isPending) dataObj.memo.isPending = false;
}
callGetResponse(reqResponse);
}
};
let isNotHTMLResponse = false;
const setComment = () => {
if (isRequest) {
templateObject.response = void 0;
get?.("response", void 0, requestContext);
} else {
if (dataObj?.nodes) {
const parentNode = dataObj.parentNode;
const nodesLength = dataObj.nodes.length;
for (let i = 0; i < nodesLength; i++) {
const node = dataObj.nodes[i];
if (i === nodesLength - 1) {
parentNode.insertBefore(dataObj.comment, node);
}
parentNode.removeChild(node);
}
dataObj.nodes = null;
dataObj.parentNode = null;
if (isRequests) {
reqObject.response = void 0;
get?.("response", void 0, requestContext, reqObject);
}
get?.("response", mainEl, requestContext);
}
}
if (isRequestMemo) {
if (dataObj.memo.response !== null) {
dataObj.memo.response = null;
delete dataObj.memo.isPending;
delete dataObj.memo.nodes;
}
}
};
const updateIndicator = (status) => {
if (indicators) {
if (isRequestMemo && status !== "pending" && getIsNotFullfilledStatus(status)) {
if (dataObj.memo.isPending) dataObj.memo.isPending = false;
}
if (status === "pending") {
const content = indicators["pending"];
if (content !== void 0) {
if (isRequestMemo) {
dataObj.memo.isPending = true;
}
updateNodes(content);
}
} else if (status === "rejected") {
const content = indicators["rejected"];
if (content !== void 0) {
updateNodes(content);
} else {
const errorContent = indicators["error"];
if (errorContent !== void 0) {
updateNodes(errorContent);
} else {
setComment();
}
}
} else {
const content = indicators[`${status}`];
if (status > 399) {
if (content !== void 0) {
updateNodes(content);
} else {
const errorContent = indicators["error"];
if (errorContent !== void 0) {
updateNodes(errorContent);
} else {
setComment();
}
}
} else {
if (status < 200 || status > 299) {
isNotHTMLResponse = true;
if (content !== void 0) {
updateNodes(content);
} else {
setComment();
}
}
}
}
}
};
const updateStatusDepenencies = (status) => {
if (isRequests) {
if (reqObject.status !== status) {
reqObject.status = status;
get?.("status", status, requestContext, reqObject);
}
} else {
if (templateObject.status !== status) {
templateObject.status = status;
get?.("status", status, requestContext);
}
}
if (isRequestMemo && getIsNotFullfilledStatus(status)) {
dataObj.memo.response = null;
delete dataObj.memo.nodes;
}
updateIndicator(status);
};
const takeNodesFromCache = () => {
if (dataObj.memo.isPending) {
const parentNode = dataObj.parentNode;
const memoNodes = dataObj.memo.nodes;
const currentNodes = dataObj.nodes;
const nodesLength = currentNodes.length;
const newNodes = [];
for (let i = 0; i < nodesLength; i++) {
const node = currentNodes[i];
if (i === nodesLength - 1) {
for (let j = 0; j < memoNodes.length; j++) {
const reqNode = memoNodes[j];
const newNode = parentNode.insertBefore(reqNode, node);
newNodes.push(newNode);
}
}
parentNode.removeChild(node);
}
dataObj.nodes = newNodes.slice();
dataObj.memo.isPending = false;
dataObj.memo.nodes = newNodes.slice();
}
const reqResponse = dataObj.nodes.slice();
callGetResponse(reqResponse);
};
let requestStatus = 200;
updateStatusDepenencies("pending");
let isRejectedError = true;
let isError = true;
fetch(source, initRequest).then((response) => {
isRejectedError = false;
requestStatus = response.status;
updateStatusDepenencies(requestStatus);
if (!response.ok) {
if (indicators) isError = false;
createError(
`${RESPONSE_ERROR}: Response with status code ${requestStatus}`
);
}
if (Array.isArray(allowedContentTypes) && allowedContentTypes.length !== 0) {
const contentType = response.headers.get("Content-Type");
if (getIsNotAllowedContentType(contentType, allowedContentTypes)) {
createError(
`${RESPONSE_ERROR}: Expected ${allowedContentTypes.map((type) => `"${type}"`).join(", ")}, but received "${contentType}"`
);
}
}
return response.text();
}).then((data) => {
if (!isNotHTMLResponse) {
if (isRequestMemo) {
const { response } = dataObj.memo;
if (response === null) {
dataObj.memo.response = data;
} else {
if (response === data) {
takeNodesFromCache();
return;
} else {
dataObj.memo.response = data;
delete dataObj.memo.nodes;
}
}
}
const templateWrapper = getResponseElements(
data,
disallowedTags,
sanitize
);
if (isRequest) {
templateObject.response = templateWrapper;
get?.("response", templateWrapper, requestContext);
} else {
const reqResponse = [];
const nodes = [
...templateWrapper.content.childNodes
];
if (dataObj) {
updateNodes(templateWrapper, false, true);
} else {
const parentNode = el.parentNode;
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
const reqNode = parentNode.insertBefore(node, el);
if (isRequests) {
reqResponse.push(reqNode);
}
}
parentNode.removeChild(el);
if (isRequests) {
reqObject.response = reqResponse;
get?.("response", reqResponse, requestContext, reqObject);
}
get?.("response", mainEl, requestContext);
}
}
}
}).catch((error) => {
if (isRejectedError) {
updateStatusDepenencies("rejected");
if (!indicators) {
setComment();
}
} else {
if (isError) {
setComment();
}
}
throw error;
});
};
var getInstanceContext = (event, currentClearInterval) => {
const request = {};
if (event !== void 0) {
request.event = event;
}
if (currentClearInterval) {
request.clearInterval = currentClearInterval;
}
return {
request
};
};
var getRequestInitFromFn = (fn, event, currentClearInterval) => {
const context = getInstanceContext(
event,
currentClearInterval
);
const result = fn(context);
return result;
};
var renderTemplate = (currentEl, fn, requests, compileOptions, isMemoUndefined, isAutoBodyUndefined, isAllowedContentTypesUndefined, isDisallowedTagsUndefined, isSanitizeUndefined, isRequest = false) => {
const renderRequest = (req, mainEl) => {
const source = req[SOURCE];
if (source) {
const method = (req[METHOD] || "GET").toLowerCase();
if (!getIsMethodValid(method)) {
createError(
`${REQUEST_COMPONENT_ERROR}: The "${METHOD}" property has only GET, POST, PUT, PATCH, TRACE, OPTIONS or DELETE values`
);
} else {
const after = req[AFTER];
if (after && isRequest)
createError(`${RENDER_ERROR}: EventTarget is undefined`);
const isModeUndefined = !req.hasOwnProperty(REPEAT);
const oldMode = isModeUndefined ? true : req[REPEAT];
const modeAttr = oldMode ? "all" : "one";
const isAll = modeAttr === "all";
const interval = req[INTERVAL];
const isReqMemoUndefined = !req.hasOwnProperty(MEMO);
const isReqIntervalUndefined = !req.hasOwnProperty(INTERVAL);
let isMemo = isMemoUndefined ? false : compileOptions[MEMO];
if (!isReqMemoUndefined) {
if (after) {
if (req[MEMO]) {
if (!isAll) {
createError(
`${REQUEST_COMPONENT_ERROR}: Memoization works in the enabled repetition mode`
);
} else {
isMemo = true;
}
} else {
isMemo = false;
}
} else {
createError(
`${REQUEST_COMPONENT_ERROR}: Memoization works in the enabled repetition mode`
);
}
} else {
if (isMemo) {
if (after) {
if (!isAll) {
isMemo = false;
}
} else {
isMemo = false;
}
}
}
if (!isReqIntervalUndefined) {
if (isAll && after) {
createError(
`${REQUEST_COMPONENT_ERROR}: The "${INTERVAL}" property does not work with repetiton mode yet`
);
}
}
const isReqAutoBodyUndefined = !req.hasOwnProperty(AUTO_BODY);
let autoBody = isAutoBodyUndefined ? false : compileOptions[AUTO_BODY];
if (!isReqAutoBodyUndefined) {
if (after) {
let reqAutoBody = req[AUTO_BODY];
validateAutoBody(reqAutoBody);
if (autoBody === true) {
autoBody = DEFAULT_AUTO_BODY;
}
if (reqAutoBody === true) {
reqAutoBody = DEFAULT_AUTO_BODY;
}
if (reqAutoBody === false) {
autoBody = false;
} else {
const newAutoBody = {
...autoBody === false ? DEFAULT_FALSE_AUTO_BODY : autoBody,
...reqAutoBody
};
autoBody = newAutoBody;
}
} else {
autoBody = false;
createError(
`${REQUEST_COMPONENT_ERROR}: The "${AUTO_BODY}" property does not work without the "${AFTER}" property`
);
}
} else {
if (autoBody === true) {
autoBody = DEFAULT_AUTO_BODY;
}
if (!after) {
autoBody = false;
}
}
const isReqAllowedContentTypesUndefined = !req.hasOwnProperty(
ALLOWED_CONTENT_TYPES
);
let allowedContentTypes = isAllowedContentTypesUndefined ? DEFAULT_ALLOWED_CONTENT_TYPES : compileOptions[ALLOWED_CONTENT_TYPES];
if (!isReqAllowedContentTypesUndefined) {
const currentAllowedContentTypes = req[ALLOWED_CONTENT_TYPES];
validateAllowedContentTypes(currentAllowedContentTypes);
allowedContentTypes = currentAllowedContentTypes;
}
const isReqDisallowedTagsUndefined = !req.hasOwnProperty(DISALLOWED_TAGS);
let disallowedTags = isDisallowedTagsUndefined ? DEFAULT_DISALLOWED_TAGS : compileOptions[DISALLOWED_TAGS];
if (!isReqDisallowedTagsUndefined) {
const currentDisallowedTags = req[DISALLOWED_TAGS];
validateDisallowedTags(currentDisallowedTags);
disallowedTags = currentDisallowedTags;
}
const isReqSanitizeUndefined = !req.hasOwnProperty(SANITIZE);
let sanitize = isSanitizeUndefined ? DEFAULT_SANITIZE : compileOptions[SANITIZE];
if (!isReqSanitizeUndefined) {
const currentSanitize = req[SANITIZE];
validateSanitize(currentSanitize);
sanitize = currentSanitize;
}
const initId = req[ID];
const nodeId = req.nodeId;
let indicators = req.indicators;
if (indicators) {
const parseIndicator = (val) => {
const { trigger, content } = val;
if (!trigger)
createError(
`${REQUEST_COMPONENT_ERROR}: Failed to activate or detect the indicator`
);
if (!content)
createError(
`${REQUEST_COMPONENT_ERROR}: Failed to activate or detect the indicator`
);
if (CODES.indexOf(trigger) === -1 && trigger !== "pending" && trigger !== "rejected" && trigger !== "error") {
createError(
`${REQUEST_COMPONENT_ERROR}: Failed to activate or detect the indicator`
);
}
const elWrapper = getTemplateWrapper(
content
);
return {
...val,
content: elWrapper
};
};
const newOn = {};
const uniqueTriggers = [];
for (let i = 0; i < indicators.length; i++) {
const currentIndicator = parseIndicator(indicators[i]);
const { trigger } = currentIndicator;
if (uniqueTriggers.indexOf(trigger) === -1) {
uniqueTriggers.push(trigger);
} else {
createError(
`${REQUEST_COMPONENT_ERROR}: Indicator trigger must be unique`
);
}
newOn[`${trigger}`] = currentIndicator.content;
}
indicators = newOn;
}
const getOptions = (options, isArray = false) => {
if (isArray) {
if (initId) {
let result;
for (let i = 0; i < options.length; i++) {
const currentOptions = options[i];
if (currentOptions.id === initId) {
result = currentOptions.value;
break;
}
}
if (!result) {
createError(
`${REQUEST_COMPONENT_ERROR}: ID referenced by request not found`
);
}
return result;
} else {
return {};
}
} else {
if (initId)
createError(
`${REQUEST_COMPONENT_ERROR}: ID referenced by request not found`
);
return options;
}
};
const isInterval = interval !== void 0;
const isDataObj = isAll && after || isInterval;
const reqFunction = (reqEl, options, templateObject, data, reqMainEl, isArray = false, reqObject, isRequests = false, currentHMPLElement, event, currentInterval) => {
const id = data.currentId;
if (isRequest) {
if (!reqEl) reqEl = mainEl;
} else {
if (!reqEl) {
let currentEl2;
const { els } = data;
for (let i = 0; i < els.length; i++) {
const e = els[i];
if (e.id === nodeId) {
currentHMPLElement = e;
currentEl2 = e.el;
break;
}
}
reqEl = currentEl2;
}
}
let dataObj = void 0;
if (!isRequest) {
if (isDataObj || indicators) {
dataObj = currentHMPLElement.objNode;
if (!dataObj) {
dataObj = {
id,
nodes: null,
parentNode: null,
comment: reqEl
};
if (isMemo) {
dataObj.memo = {
response: null
};
if (indicators) {
dataObj.memo.isPending = false;
}
}
if (isInterval) {
if (currentInterval) {
dataObj.interval = {
value: currentInterval,
clearInterval: () => clearInterval(currentInterval)
};
}
}
currentHMPLElement.objNode = dataObj;
data.dataObjects.push(dataObj);
data.currentId++;
}
}
}
let currentOptions = getOptions(options, isArray);
const isOptionsFunction = checkFunction(currentOptions);
if (!isOptionsFunction && currentOptions)
currentOptions = { ...currentOptions };
if (autoBody && autoBody.formData && event && !isOptionsFunction) {
const { type, target } = event;
if (type === "submit" && target && target instanceof HTMLFormElement && target.nodeName === "FORM") {
currentOptions.body = new FormData(
target,
event.submitter
);
}
}
let currentClearInterval = currentInterval ? () => clearInterval(currentInterval) : void 0;
currentClearInterval = isRequest ? currentClearInterval : dataObj?.interval?.clearInterval;
const requestInit = isOptionsFunction ? getRequestInitFromFn(
currentOptions,
event,
currentClearInterval
) : currentOptions;
if (!checkObject(requestInit) && requestInit !== void 0)
createError(
`${REQUEST_INIT_ERROR}: Expected an object with initialization options`
);
makeRequest(
reqEl,
reqMainEl,
dataObj,
method,
source,
isRequest,
isRequests,
isMemo,
requestInit,
templateObject,
allowedContentTypes,
disallowedTags,
sanitize,
reqObject,
indicators,
currentClearInterval
);
};
let currentReqFunction = reqFunction;
if (interval) {
validateInterval(interval);
const time = Number(interval);
currentReqFunction = (reqEl, options, templateObject, data, reqMainEl, isArray = false, reqObject, isRequests = false, currentHMPLElement, event) => {
let interval2 = null;
interval2 = setInterval(() => {
reqFunction(
reqEl,
options,
templateObject,
data,
reqMainEl,
isArray,
reqObject,
isRequests,
currentHMPLElement,
event,
interval2
);
}, time);
};
}
let requestFunction = currentReqFunction;
if (after) {
const setEvents = (reqEl, event, selector, options, templateObject, data, isArray, isRequests, reqMainEl, reqObject, currentHMPLElement) => {
const els = reqMainEl.querySelectorAll(selector);
if (els.length === 0) {
createError(`${RENDER_ERROR}: Selectors nodes not found`);
}
const afterFn = isAll ? (evt) => {
currentReqFunction(
reqEl,
options,
templateObject,
data,
reqMainEl,
isArray,
reqObject,
isRequests,
currentHMPLElement,
evt
);
} : (evt) => {
currentReqFunction(
reqEl,
options,
templateObject,
data,
reqMainEl,
isArray,
reqObject,
isRequests,
currentHMPLElement,
evt
);
for (let j = 0; j < els.length; j++) {
const currentAfterEl = els[j];
currentAfterEl.removeEventListener(event, afterFn);
}
};
for (let i = 0; i < els.length; i++) {
const afterEl = els[i];
afterEl.addEventListener(event, afterFn);
}
};
if (after.indexOf(":") > 0) {
const afterArr = after.split(":");
const event = afterArr[0];
const selector = afterArr.slice(1).join(":");
requestFunction = (reqEl, options, templateObject, data, reqMainEl, isArray = false, reqObject, isRequests = false, currentHMPLElement) => {
setEvents(
reqEl,
event,
selector,
options,
templateObject,
data,
isArray,
isRequests,
reqMainEl,
reqObject,
currentHMPLElement
);
};
} else {
createError(
`${REQUEST_COMPONENT_ERROR}: The "${AFTER}" property doesn't work without EventTargets`
);
}
} else {
if (!isModeUndefined) {
createError(
`${REQUEST_COMPONENT_ERROR}: The "${REPEAT}" property doesn't work without "${AFTER}" property`
);
}
}
return requestFunction;
}
} else {
createError(
`${REQUEST_COMPONENT_ERROR}: The "${SOURCE}" property are not found or empty`
);
}
};
let reqFn;
if (isRequest) {
requests[0].el = currentEl;
reqFn = renderRequest(requests[0]);
} else {
let id = -2;
const getRequests = (currrentElement) => {
id++;
if (currrentElement.nodeType == 8) {
let value = currrentElement.nodeValue;
if (value && value.startsWith(COMMENT)) {
value = value.slice(4);
const currentIndex = Number(value);
const currentRequest = requests[currentIndex];
if (Number.isNaN(currentIndex) || currentRequest === void 0) {
createError(
`${PARSE_ERROR}: Request object with id "${currentIndex}" not found`
);
}
currentRequest.el = currrentElement;
currentRequest.nodeId = id;
}
}
if (currrentElement.hasChildNodes()) {
const chNodes = currrentElement.childNodes;
for (let i = 0; i < chNodes.length; i++) {
getRequests(chNodes[i]);
}
}
};
getRequests(currentEl);
if (requests.length > 1) {
const algorithm = [];
for (let i = 0; i < requests.length; i++) {
const currentRequest = requests[i];
algorithm.push(renderRequest(currentRequest, currentEl));
}
reqFn = (reqEl, options, templateObject, data, mainEl, isArray = false) => {
if (!reqEl) {
reqEl = mainEl;
}
const requests2 = [];
const els = data.els;
for (let i = 0; i < els.length; i++) {
const hmplElement = els[i];
const currentReqEl = hmplElement.el;
const currentReqFn = algorithm[i];
const currentReq = {
response: void 0
};
currentReqFn(
currentReqEl,
options,
templateObject,
data,
reqEl,
isArray,
currentReq,
true,
hmplElement
);
requests2.push(currentReq);
}
templateObject.requests = requests2;
};
} else {
const currentRequest = requests[0];
reqFn = renderRequest(currentRequest, currentEl);
}
}
return fn(reqFn);
};
var validateOptions = (currentOptions) => {
const isObject = checkObject(currentOptions);
if (isObject && currentOptions.hasOwnProperty(`${REQUEST_INIT_GET}`)) {
if (!checkFunction(currentOptions[REQUEST_INIT_GET])) {
createError(
`${REQUEST_INIT_ERROR}: The "${REQUEST_INIT_GET}" property has a function value`
);
}
}
};
var validateAllowedContentTypes = (allowedContentTypes, isCompile = false) => {
const currentError = isCompile ? COMPILE_OPTIONS_ERROR : REQUEST_COMPONENT_ERROR;
if (allowedContentTypes !== "*" && !checkIsStringArray(allowedContentTypes, currentError)) {
createError(
`${currentError}: Expected "*" or string array, but got neither`
);
}
};
var validateAutoBody = (autoBody, isCompile = false) => {
const isObject = checkObject(autoBody);
const currentError = isCompile ? COMPILE_OPTIONS_ERROR : REQUEST_COMPONENT_ERROR;
if (typeof autoBody !== "boolean" && !isObject)
createError(
`${currentError}: Expected a boolean or object, but got neither`
);
if (isObject) {
for (const key in autoBody) {
switch (key) {
case FORM_DATA:
if (typeof autoBody[FORM_DATA] !== "boolean")
createError(
`${currentError}: The "${FORM_DATA}" property should be a boolean`
);
break;
default:
createError(`${currentError}: Unexpected property "${key}"`);
break;
}
}
}
};
var validateDisallowedTags = (disallowedTags, isCompile = false) => {
const currentError = isCompile ? COMPILE_OPTIONS_ERROR : REQUEST_COMPONENT_ERROR;
const isArray = Array.isArray(disallowedTags);
if (!isArray)
createError(
`${currentError}: The value of the property "${DISALLOWED_TAGS}" must be an array`
);
for (let i = 0; i < disallowedTags.length; i++) {
const disallowedTag = disallowedTags[i];
if (!DISALLOWED_TAGS_VALUES.includes(disallowedTag)) {
createError(
`${currentError}: The value "${disallowedTag}" is not processed`
);
}
}
};
var validateSanitize = (sanitize, isCompile = false) => {
const currentError = isCompile ? COMPILE_OPTIONS_ERROR : REQUEST_COMPONENT_ERROR;
if (typeof sanitize !== "boolean") {
createError(
`${currentError}: The value of the property "${SANITIZE}" must be a boolean`
);
}
};
var validateIdOptions = (currentOptions) => {
if (!currentOptions.hasOwnProperty("id") || !currentOptions.hasOwnProperty("value")) {
createError(`${REQUEST_INIT_ERROR}: Missing "id" or "value" property`);
}
};
var validateIdentificationOptionsArray = (currentOptions) => {
const ids = [];
for (let i = 0; i < currentOptions.length; i++) {
const idOptions = currentOptions[i];
if (!checkObject(idOptions))
createError(
`${REQUEST_INIT_ERROR}: IdentificationRequestInit is of type object`
);
validateIdOptions(idOptions);
const { id } = idOptions;
const isIdString = typeof idOptions.id === "string";
if (!isIdString && typeof idOptions.id !== "number")
createError(`${REQUEST_INIT_ERROR}: ID must be a string or a number`);
if (ids.indexOf(id) > -1) {
createError(
`${REQUEST_INIT_ERROR}: ID with value ${isIdString ? `"${id}"` : id} already exists`
);
} else {
ids.push(id);
}
}
};
var validateInterval = (time) => {
if (typeof time !== "number") {
createError(
`${REQUEST_COMPONENT_ERROR}: The "${INTERVAL}" value must be number`
);
}
};
var stringify = (info) => {
const formatValue = (value) => {
if (typeof value === "string") {
return `"${value}"`;
}
if (typeof value === "number" || typeof value === "boolean") {
return `${value}`;
}
if (Array.isArray(value)) {
return `[${value.map((item) => formatValue(item)).join(",")}]`;
}
if (typeof value === "object" && value !== null) {
return `{${Object.entries(value).map(([k, v]) => `${k}:${formatValue(v)}`).join(",")}}`;
}
return "";
};
let body = Object.entries(info).map(([key, value]) => `${key}=${formatValue(value)}`).join(" ");
if (body.endsWith("}")) {
body += " ";
}
return `{{#request ${body}}}{{/request}}`;
};
var compile = (template, options = {}) => {
if (typeof template !== "string")
createError(
`${COMPILE_ERROR}: Template was not found or the type of the passed value is not string`
);
if (!template)
createError(`${COMPILE_ERROR}: Template must not be a falsey value`);
if (!checkObject(options))
createError(`${COMPILE_OPTIONS_ERROR}: Options must be an object`);
const isMemoUndefined = !options.hasOwnProperty(MEMO);
if (!isMemoUndefined && typeof options[MEMO] !== "boolean")
createError(
`${COMPILE_OPTIONS_ERROR}: The value of the property ${MEMO} must be a boolean`
);
const isAutoBodyUndefined = !options.hasOwnProperty(AUTO_BODY);
if (!isAutoBodyUndefined) validateAutoBody(options[AUTO_BODY], true);
const isAllowedContentTypesUndefined = !options.hasOwnProperty(
ALLOWED_CONTENT_TYPES
);
if (!isAllowedContentTypesUndefined)
validateAllowedContentTypes(options[ALLOWED_CONTENT_TYPES], true);
const isDisallowedTagsUndefined = !options.hasOwnProperty(DISALLOWED_TAGS);
if (!isDisallowedTagsUndefined)
validateDisallowedTags(options[DISALLOWED_TAGS], true);
const isSanitizeUndefined = !options.hasOwnProperty(SANITIZE);
if (!isSanitizeUndefined) validateSanitize(options[SANITIZE], true);
const requests = [];
const requestsIndexes = [];
const parseTemplate = (str) => {
const parts = [];
let pos = 0;
const openTags = [
{ open: "{{#request", close: "{{/request}}" },
{ open: "{{#r", close: "{{/r}}" }
];
while (pos < str.length) {
const openIndexes = openTags.map((tag) => ({ ...tag, index: str.indexOf(tag.open, pos) })).filter((item) => item.index !== -1);
if (openIndexes.length === 0) {
parts.push(str.slice(pos));
break;
}
const nextOpen = openIndexes.sort((a, b) => a.index - b.index)[0];
parts.push(str.slice(pos, nextOpen.index));
const attrStart = nextOpen.index + nextOpen.open.length;
const attrEnd = str.indexOf("}}", attrStart);
if (attrEnd === -1) {
createError(
`${PARSE_ERROR}: Unclosed block (no ending '}}') for ${nextOpen.open}`
);
}
const rawAttrs = str.slice(attrStart, attrEnd).trim();
const blockEnd = str.indexOf(nextOpen.close, attrEnd);
if (blockEnd === -1) {
createError(
`${PARSE_ERROR}: No closing '${nextOpen.close}' found for ${nextOpen.open}}}`
);
}
const innerContent = str.slice(attrEnd + 2, blockEnd);
if (innerContent.includes(nextOpen.open)) {
createError(
`${PARSE_ERROR}: Nested ${nextOpen.open}}} blocks are not supported`
);
}
const transformedAttrs = safeReplaceEquals(rawAttrs);
if (nextOpen.open.startsWith(openTags[0].open) || nextOpen.open.startsWith(openTags[1].open)) {
const indicators = [];
const indicatorRegex = /{{#indicator\s+([^}]*)}}([\s\S]*?){{\/indicator}}/g;
let match;
while ((match = indicatorRegex.exec(innerContent)) !== null) {
const attrs = match[1].trim();
let contentRaw = match[2].trim();
const indicatorString = "{{#indicator";
if (contentRaw.includes(indicatorString)) {
createError(
`${PARSE_ERROR}: Nested ${indicatorString}}} blocks are not supported`
);
}
const parsedAttrs = safeReplaceEquals(attrs);
contentRaw = contentRaw.replace(/\n/g, " ").replace(/\s+/g, " ").trim();
const content = contentRaw.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$/g, "\\$");
indicators.push(`{${parsedAttrs}, content:'${content}'}`);
}
const indicatorsPart = indicators.length > 0 ? `,indicators:[${indicators.join(",")}]` : "";
parts.push(`{${transformedAttrs}${indicatorsPart}}`);
}
requestsIndexes.push(parts.length - 1);
pos = blockEnd + nextOpen.close.length;
}
return parts;
};
const safeReplaceEquals = (input) => {
let result = "";
const regex = /\s*([a-zA-Z0-9_-]+)\s*=\s*(("[^"]*"|'[^']*'|`[^`]*`|\[[^\]]*\]|\{[^}]*\}|true|false|\d+)(?=\s|,|$))\s*/g;
let match;
while ((match = regex.exec(input)) !== null) {
const key = match[1].trim();
const value = match[2].trim();
result += `${key}:${value},`;
}
return result.replace(/,$/, "").trim();
};
const templateArr = parseTemplate(template);
if (requestsIndexes.length === 0)
createError(`${PARSE_ERROR}: Request object not found`);
const setRequest = (text) => {
const parsedData = import_json5.default.parse(text);
for (const key in parsedData) {
const value = parsedData[key];
if (!REQUEST_OPTIONS.includes(key))
createError(
`${REQUEST_COMPONENT_ERROR}: Property "${key}" is not processed`
);
switch (key) {
case INDICATORS:
if (!Array.isArray(value)) {
createError(
`${REQUEST_COMPONENT_ERROR}: The value of the property "${key}" must be an array`
);
}
break;
case ID:
if (typeof value !== "string" && typeof value !== "number") {
createError(
`${REQUEST_COMPONENT_ERROR}: The value of the property "${key}" must be a string`
);
}
break;
case MEMO:
case REPEAT:
if (typeof value !== "boolean") {
createError(
`${REQUEST_COMPONENT_ERROR}: The value of the property "${key}" must be a boolean value`
);
}
break;
case AUTO_BODY:
validateAutoBody(value);
break;
case ALLOWED_CONTENT_TYPES:
validateAllowedContentTypes(value);
break;
case DISALLOWED_TAGS:
validateDisallowedTags(value);
break;
case SANITIZE:
validateSanitize(value);
break;
case INTERVAL:
validateInterval(value);
break;
default:
if (typeof value !== "string") {
createError(
`${REQUEST_COMPONENT_ERROR}: The value of the property "${key}" must be a string`
);
}
break;
}
}
const requestObject = {
...parsedData
};
requests.push(requestObject);
};
for (let i = 0; i < requestsIndexes.length; i++) {
const reqId = requestsIndexes[i];
const reqVal = templateArr[reqId];
setRequest(reqVal);
const comment = `<!--hmpl${i}-->`;
templateArr[reqId] = comment;
}
template = templateArr.join("");
let isRequest = false;
const getElement = (template2) => {
const elWrapper = getTemplateWrapper(
template2.trim()
);
if (elWrapper.content.childNodes.length > 1 || elWrapper.content.children.length !== 1 && elWrapper.content.childNodes[0].nodeType !== 8) {
createError(
`${RENDER_ERROR}: Template includes only one node of the Element type or one response object`
);
}
const prepareNode = (node) => {
switch (node.nodeType) {
case Node.ELEMENT_NODE:
if (node.tagName === "PRE") return;
break;
case Node.TEXT_NODE:
if (!/\S/.test(node.textContent)) {
node.remove();
return;
}
break;
}
for (let i = 0; i < node.childNodes.length; i++) {
prepareNode(node.childNodes.item(i));
}
};
prepareNode(elWrapper.content.childNodes[0]);
let currentEl = elWrapper.content.firstElementChild;
if (!currentEl) {
const comment = elWrapper.content.firstChild;
const isComment = comment?.nodeType === 8;
if (isComment) {
isRequest = true;
currentEl = comment;
}
}
return currentEl;
};
const templateEl = getElement(template);
const renderFn = (requestFunction) => {
const templateFunction = (options2 = {}) => {
const el = templateEl.cloneNode(true);
const templateObject = {
response: isRequest ? void 0 : el
};
const data = {
dataObjects: [],
els: [],
currentId: 0
};
if (!isRequest) {
let id = -2;
const getRequests = (currrentElement) => {
id++;
if (currrentElement.nodeType == 8) {
const value = currrentElement.nodeValue;
if (value && value.startsWith(COMMENT)) {
const elObj = {
el: currrentElement,
id
};
data.els.push(elObj);
}
}
if (currrentElement.hasChildNodes()) {
const chNodes = currrentElement.childNodes;
for (let i = 0; i < chNodes.length; i++) {
getRequests(chNodes[i]);
}
}
};
getRequests(el);
}
if (checkObject(options2) || checkFunction(options2)) {
validateOptions(options2);
requestFunction(
void 0,
options2,
templateObject,
data,
el
);
} else if (Array.isArray(options2)) {
validateIdentificationOptionsArray(
options2
);
requestFunction(
void 0,
options2,
templateObject,
data,
el,
true
);
} else {
createError(
`${REQUEST_INIT_ERROR}: The type of the value being passed does not match the supported types for RequestInit`
);
}
return templateObject;
};
return templateFunction;
};
return renderTemplate(
templateEl,
renderFn,
requests,
options,
isMemoUndefined,
isAutoBodyUndefined,
isAllowedContentTypesUndefined,
isDisallowedTagsUndefined,
isSanitizeUndefined,
isRequest
);
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
compile,
stringify
});