UNPKG

jsfast

Version:

Fastjs(jsfast) is a useful, lightweight JavaScript library for any types of project.

1,529 lines (1,503 loc) 55.3 kB
'use strict'; async function callUntilEnd(func, timeout, immediate = false, continueEvenError = false) { return new Promise((resolve, reject) => { let end = false; const endFunc = () => end; setTimeout(callFunc, immediate ? 0 : timeout); async function callFunc() { try { let res = func(endFunc); if (res instanceof Promise) { res = await res; } if (end || !res) { setTimeout(callFunc, timeout); } else resolve(); } catch (error) { { _dev.warn("fastjs/utils/doUntilEnd", "An error occurred while executing the function", [error.toString()]); } if (continueEvenError) { setTimeout(callFunc, timeout); console.error(error); } else { reject(error); end = true; } } } }); } function catchError(func, onError) { const err = (error) => { { _dev.warn("fastjs/utils/catchError", "An error occurred while executing the function", [error.toString()]); } if (onError) onError(error); else console.error(error); return error; }; try { const res = func(); if (res instanceof Promise) { return res.then((res) => res).catch(err); } return res; } catch (error) { return err(error); } } function secureCall(func) { try { const res = func(); if (res instanceof Promise) { return new Promise((resolve, reject) => { res .then((res) => resolve([res, null])) .catch((error) => resolve([undefined, error])); }); } return [res, null]; } catch (error) { return [undefined, error]; } } var basic = /*#__PURE__*/Object.freeze({ __proto__: null, callUntilEnd: callUntilEnd, catchError: catchError, secureCall: secureCall }); async function copy(text) { try { const input = await createDomElement(text); const selection = selectText(input); copyToClipboard(selection); input.remove(); } catch (error) { { _dev.warn("fastjs/utils/copy", "An error occurred while copying text to clipboard", error); } } async function createDomElement(text) { const { createFastjsDom } = await Promise.resolve().then(function () { return dom$2; }); let input = createFastjsDom("span"); input .html(replaceNewLinesAndSpaces(text)) .push(document.body, "lastElementChild"); return input.el(); function replaceNewLinesAndSpaces(text) { return text.replace(/\n/g, "<br>").replace(/ /g, "&nbsp;"); } } function selectText(element) { const range = document.createRange(); range.setStart(element, 0); range.setEnd(element, element.childNodes.length); const selection = window.getSelection(); if (!selection) return null; selection.removeAllRanges(); selection.addRange(range); return selection; } function copyToClipboard(selection) { if (!selection) { { _dev.warn("fastjs/utils/copy", "selection is null"); } return; } document.execCommand("copy"); } } var dom$3 = /*#__PURE__*/Object.freeze({ __proto__: null, copy: copy }); function rand(min, max, decimal = 0) { { if (min > max) { _dev.warn("fastjs/utils/rand", "min is greater than max, this may cause unexpected results", [`*min: ${min}`, `*max: ${max}`, `decimal: ${decimal}`]); } if (decimal < 0) { _dev.warn("fastjs/utils/rand", "decimal is less than 0, this may cause unexpected results", [`min: ${min}`, `max: ${max}`, `*decimal: ${decimal}`]); } } const prefix = decimal * 10 || 1; [min, max] = [min * prefix, max * prefix]; let num = (Math.floor(Math.pow(10, 14) * Math.random() * Math.random()) % (max - min + 1)) + min; return num / prefix; } function randString(length, options = {}) { const letters = "abcdefghijklmnopqrstuvwxyz"; let choices = ""; if (options.number) choices += "0123456789"; if (options.letter !== false) { if (options.upper) choices += letters.toUpperCase(); if (options.lower !== false) choices += letters; } if (Array.isArray(options.custom)) choices += options.custom.join(""); else if (options?.custom) choices += options.custom; if (options.max) length = rand(length, options.max); let result = ""; for (let i = 0; i < length; i++) { result += choices.charAt(rand(0, choices.length - 1)); } return result; } function uuid() { const s = (len) => randString(len, { number: true }); return `${s(8)}-${s(4)}-4${s(3)}-${s(4)}-${s(12)}`; } var rand$1 = /*#__PURE__*/Object.freeze({ __proto__: null, rand: rand, randString: randString, uuid: uuid }); var index$3 = { ...basic, ...dom$3, ...rand$1 }; function browserCheck(module) { const isBrowser = typeof window !== "undefined"; if (!isBrowser) { throw error(`${module}/browserCheck`, "This module is only available in browser environments."); } } function getStyle(key) { const style = { "fastjs.bold": "\u001b[1m", "fastjs.reverse": "\u001b[7m", "fastjs.red": "\u001b[31m", "fastjs.green": "\u001b[32m", "fastjs.yellow": "\u001b[33m", "fastjs.blue": "\u001b[34m", "fastjs.magenta": "\u001b[35m", "fastjs.cyan": "\u001b[36m", "fastjs.white": "\u001b[37m", "fastjs.gray": "\u001b[90m", "fastjs.bgRed": "\u001b[41m", "fastjs.bgGreen": "\u001b[42m", "fastjs.bgYellow": "\u001b[43m", "fastjs.bgBlue": "\u001b[44m", "fastjs.bgMagenta": "\u001b[45m", "fastjs.bgCyan": "\u001b[46m", "fastjs.bgWhite": "\u001b[47m", "fastjs.bgGray": "\u001b[100m", "fastjs.wrong": "\u001b[41m\u001b[37m\u001b[1m", "fastjs.right": "\u001b[42m\u001b[37m\u001b[1m", "fastjs.warn": "\u001b[43m\u001b[90m\u001b[1m" }; if (!key) return ""; if (Array.isArray(key)) { return key.map((e) => style[e]).join(""); } return style[key] || ""; } function warn(module, message, args = [], styleArgs = []) { args = args.filter((arg) => arg !== ""); args = args.map((arg, k) => typeof arg === "string" && arg[0] !== "&" && args[k - 1]?.[args[k - 1].length - 1] !== "&" ? "\n > " + arg : arg); args = args.map((arg) => { if (typeof arg !== "string") return arg; if (arg[0] === "&") arg = ` ${arg.slice(1)} `; if (arg[arg.length - 1] === "&") arg = `${arg.slice(0, -1)} `; return arg; }); let styleKey = 0; let outputMessage = ""; let outputObjects = []; styleArgs.length ? getStyle(styleArgs[styleArgs.length - 1]) : ""; args.unshift(`[Fastjs warn] ${module}: ${message}`); args.forEach((arg) => { if (typeof arg !== "string") { outputMessage += "%o"; outputObjects.push(arg); return; } if (arg.includes("> *") && !arg.includes("> **")) { let style = styleArgs[styleKey]; arg = arg.replace("*", ""); arg = arg.replace(" >", getStyle(style) + "-->\u001b[0m"); styleKey++; } if (arg.includes("***")) { let style = styleArgs[styleKey]; arg = arg.replace("***", ""); arg = arg.split("> ")[0] + "> " + getStyle(style) + arg.split("> ").slice(1).join("> ") + "\u001b[0m"; styleKey++; } while (arg.includes(`**`)) { let style = styleArgs[styleKey]; arg = arg.replace(`**`, getStyle(style)); arg = arg.replace(`**`, "\u001b[0m"); styleKey++; } outputMessage += arg; }); console.warn(outputMessage, ...outputObjects); } function error(module, message, args = [], styleArgs = []) { // Note: Called utils.rand, but it should be tree-shaked after build(prod mode) const eid = rand(1e7, 1e8 - 1); args.push(`Trace: ${eid}`); warn(module, message, args, styleArgs); return new Error(`[Fastjs error] ${module}: ${message.replace(/[*&]/g, "")}\n > Trace: ${eid}`); } function experimentFeatureWarning(id, name, call) { warn("fastjs/experiment-feature-" + id, `${name} is an experimental feature, it may be removed or changed in the future.`, [`call: `, call], ["fastjs.warn"]); } var _dev = { browserCheck, experimentFeatureWarning, warn, error }; function _selector(selector, parent = document) { _dev.browserCheck("fastjs/dom/selector"); const specialStatements = ["body", "head"]; const result = []; // @ts-ignore if (parent?.construct === "FastjsDom") parent = parent._el; // @ts-ignore if (parent?.construct === "FastjsDomList") parent = parent._list; function select(el, selector) { if (el.set) return el.get("querySelectorAll")(selector); return el.querySelectorAll(selector); } Array.isArray(parent) ? parent.forEach((e) => { result.push(...queryResultToArray(select(e, selector))); }) : result.push(...queryResultToArray(select(parent, selector))); if (result.length === 0) return null; if ((result[0].id && selector.includes(`#${result[0].id}`)) || specialStatements.includes(selector)) return result[0]; const list = []; result.forEach((e) => { list.push(e); }); return list; function queryResultToArray(queryResult) { const result = []; queryResult.forEach((e) => { result.push(e); }); return result; } } function isUndefined(value) { return value === undefined; } function isDom(value) { return value.construct === "FastjsDom"; } function createMethods$4(list) { return { add(el) { list.push(el); return list; }, delete(key, deleteDom = true) { if (deleteDom) list[key].remove(); list.splice(key, 1); return list; }, each(callback) { list.forEach((el, i) => callback(el, el.el(), i)); return list; }, el(key = 0) { return list[key].el(); }, getElement(key = 0) { return this.el(key); }, getDom(key = 0) { return list[key]; }, next(el = "*") { const result = _selector(el, this.toElArray()); if (Array.isArray(result)) return createFastjsDomList(result); if (result === null) return null; return createFastjsDom(result); }, toArray() { return list; }, toElArray() { return list.map((e) => e.el()); } }; } function createFastjsDomList(list) { const domList = []; for (const el of list) { if (el === null || el === undefined) continue; if (isDom(el)) domList.push(el); else if (Array.isArray(el)) domList.push(...el); else domList.push(createFastjsDom(el)); } const _atom = setupAtom(domList); const moduleAtom = new Proxy(_atom, { get(target, key) { if (key in target) return target[key]; if (key in target._list) return target._list[key]; if (key in target._list[0]) { const val = target._list[0][key]; if (typeof val === "function") { return function () { for (const dom of target._list) { const proto = dom[key]; if (typeof proto === "function") { const res = proto.bind(dom, ...arguments)(); if (!isUndefined(res) && res.construct !== "FastjsDom") return res; } } return target; }; } else return val; } return target[key]; }, set(target, key, value) { target[key] = value; if (Number.isInteger(Number(key))) { _atom._list[key] = value; target[key] = value; } return true; } }); moduleAtom._list = new Proxy(domList, { set(target, key, value) { target[Number(key)] = value; _atom[Number(key)] = value; return true; } }); domList.forEach((e, i) => { moduleAtom[i] = e; }); return Object.assign(moduleAtom, createMethods$4(moduleAtom)); } function setupAtom(list) { return { construct: "FastjsDomList", get length() { return list.length; }, set length(value) { list.length = value; } }; } function createMethods$3(dom) { function get(key) { return dom._el[key]; } function set(key, val) { if (findPropInChain(dom._el?.constructor.prototype, key) ?.writable || findPropInChain(dom._el?.constructor.prototype, key)?.set) { dom._el[key] = val; } else _dev.warn("fastjs/dom/set", `key **${key}** is not writable`, [ "*key: " + key, "set<T extends keyof BasicElement>(**key: T**, val: HTMLElement[T]): Dom", "super: ", dom ], ["fastjs.warn"]); return dom; function findPropInChain(obj, prop) { while (obj !== null) { const desc = Object.getOwnPropertyDescriptor(obj, prop); if (desc) return desc; obj = Object.getPrototypeOf(obj); } return null; } } function text(val) { if (val === undefined) return dom._el.textContent || ""; dom._el.textContent = val; return dom; } function html(val) { if (val === undefined) return dom._el.innerHTML; dom._el.innerHTML = val; return dom; } function val(val) { const key = (dom._el.tagName === "TEXTAREA" ? "textContent" : "value"); if (val === undefined) return dom._el[key]; set(key, val); return dom; } const el = () => dom._el; const remove = () => { dom._el.remove(); return dom; }; const focus = () => { dom._el.focus(); return dom; }; const first = () => dom._el.firstElementChild ? createFastjsDom(dom._el.firstElementChild) : null; const last = () => dom._el.lastElementChild ? createFastjsDom(dom._el.lastElementChild) : null; const father = () => { const father = dom._el.parentElement; return father ? createFastjsDom(father) : null; }; const children = () => createFastjsDomList([...dom._el.children]); const next = (selector = "*") => { const result = _selector(selector, dom._el); if (Array.isArray(result)) return createFastjsDomList(result); if (result === null) return null; return createFastjsDom(result); }; const each = (callback, deep = false) => { const children = [...dom._el.children]; children.forEach((v, i) => { callback(createFastjsDom(v), v, i); if (deep) createFastjsDom(v).each(callback, deep); }); return dom; }; function addEvent(event, callback) { let eventTrig = (event) => callback(dom, event); dom._events.push({ type: event, callback: callback, trigger: eventTrig, remove: () => { dom.removeEvent(callback); } }); dom._el.addEventListener(event, eventTrig); return dom; } function removeEvent(typeOrCallback, key) { const attrs = { type: typeof typeOrCallback === "string" ? typeOrCallback : undefined, callback: typeof typeOrCallback === "function" ? typeOrCallback : undefined, key }; if (attrs.callback) { dom._events.forEach((v, i) => { if (v.callback === attrs.callback) { dom._el.removeEventListener(v.type, v.trigger); dom._events.splice(i, 1); } }); } else if (attrs.type) { if (attrs.key !== undefined) { dom._el.removeEventListener(dom._events[attrs.key].type, dom._events[attrs.key].trigger); dom._events.splice(attrs.key, 1); } else { dom._events.forEach((v) => { if (v.type === attrs.type) { dom._el.removeEventListener(v.type, v.trigger); dom._events.splice(dom._events.indexOf(v), 1); } }); } } return dom; } function getStyle(keyOrCallback) { const getStyleProxy = () => { return new Proxy(styles, { get: (target, key) => { return (target.getPropertyValue(key) || target[key] || null); }, set: (target, key, value) => { dom.setStyle(key, value); return Reflect.set(target, key, value); } }); }; const computedStyle = window.getComputedStyle(dom._el); const styles = Object.assign(computedStyle, dom._el.style); if (typeof keyOrCallback === "string") return styles.getPropertyValue(keyOrCallback.replace(/[A-Z]/g, (v) => "-" + v.toLowerCase())); else if (typeof keyOrCallback === "function") keyOrCallback(getStyleProxy(), dom); else return getStyleProxy(); return dom; } function setStyle(strOrObj, val, important) { if (val) dom._el.style.setProperty(strOrObj.replace(/[A-Z]/g, (v) => "-" + v.toLowerCase()), val, important ? "important" : ""); else if (typeof strOrObj === "string") dom._el.style.cssText = strOrObj; else { let key; for (key in strOrObj) { dom.setStyle(key, strOrObj[key]); } } return dom; } function getClass(callback) { const arr = [...dom._el.classList]; if (callback) callback(arr); else return arr; } function setClass(nameOrObj, value = true) { if (typeof nameOrObj === "string") dom._el.classList[value ? "add" : "remove"](nameOrObj); else { for (const key in nameOrObj) { dom.setClass(key, nameOrObj[key]); } } return dom; } const classOp = (name, op) => { name.forEach((v) => { v.split(" ").forEach((v) => { dom.setClass(v, op); }); }); }; function addClass(className) { if (typeof className === "string") classOp([...arguments], true); else className.forEach((v) => dom.addClass(v)); return dom; } function removeClass(className) { if (typeof className === "string") classOp([...arguments], false); else className.forEach((v) => dom.removeClass(v)); return dom; } const clearClass = () => { dom._el.className = ""; return dom; }; function getAttr(param) { const getAttrProxy = () => { const arr = [...dom._el.attributes]; const obj = {}; arr.forEach((v) => { obj[v.name] = v.value; }); return new Proxy(obj, { set: (target, key, value) => { dom.setAttr(key, value); return Reflect.set(target, key, value); } }); }; switch (typeof param) { case "string": return dom._el.getAttribute(param); case "function": param(getAttrProxy(), dom); return dom; default: return getAttrProxy(); } } function setAttr(keyOrAttr, val) { const setAttr = (key, val) => { if (val === null) dom._el.removeAttribute(key); else dom._el.setAttribute(key, val); }; if (typeof keyOrAttr === "string") setAttr(keyOrAttr, val); else { for (const key in keyOrAttr) { setAttr(key, keyOrAttr[key]); } } return dom; } function push(el = document.body, target = "lastElementChild", clone) { // @ts-expect-error Check if el is FastjsDom | FastjsDomList el = el.tagName ? el : el.el(); const isReplace = (target === "replaceElement"); const newElement = createFastjsDom(clone ? dom._el.cloneNode(true) : dom._el); if (isReplace) { const father = createFastjsDom(dom._el.parentElement); if (father === null) { { throw _dev.error("fastjs/dom/push", "father is null", [ "*el: ", el, "target: ", target, "push<T extends PushTarget>(**el?: HTMLElement | FastjsDomList | FastjsDom**, target?: T, clone?: boolean): PushReturn<T>" ], ["fastjs.wrong"]); } } father._el.replaceChild(newElement._el, dom._el); } else if (typeof target === "number") { { if (target > dom._el.children.length) { throw _dev.error("fastjs/dom/push", "target is out of range", [ "*dom(container): ", dom, "target: ", target, "push<T extends PushTarget>(**el?: HTMLElement | FastjsDomList | FastjsDom**, target?: T, clone?: boolean): PushReturn<T>" ], ["fastjs.wrong"]); } } dom._el.insertBefore(newElement._el, dom._el.children[target]); } else { const event = { firstElementChild: () => el.prepend(newElement._el), lastElementChild: () => el.append(newElement._el), randomElementChild, beforeElement: () => el.before(newElement._el), afterElement: () => el.after(newElement._el) }; event[target](); } return { isReplace, newElement: (isReplace && newElement), oldElement: isReplace && dom, index: [...el.children].indexOf(newElement._el), el: newElement, origin: dom, father: newElement.father() }; function randomElementChild() { const children = [...el.children]; if (children.length === 0) el.appendChild(dom._el); else { const pos = rand(0, children.length); if (pos === children.length) el.appendChild(dom._el); else el.insertBefore(dom._el, children[rand(0, children.length - 1)]); } } } function insert(el, target = "last", clone) { // @ts-expect-error Check if el is FastjsDom | FastjsDomList el = el.tagName ? el : el.el(); const newElement = createFastjsDom(clone ? el.cloneNode(true) : el); if (typeof target === "number") { { if (target > el.children.length) { throw _dev.error("fastjs/dom/insert", "target is **out of range**", [ "*el(container): ", el, "target: ", target, "insert<T extends InsertTarget>(**el: HTMLElement | FastjsDomList | FastjsDom**, target: T, clone?: boolean): InsertReturn" ], ["fastjs.wrong"]); } } el.insertBefore(newElement._el, dom._el.children[target]); } else { const event = { first: () => dom._el.prepend(newElement._el), last: () => dom._el.append(newElement._el), random: randomElementChild, before: () => dom._el.before(newElement._el), after: () => dom._el.after(newElement._el) }; event[target](); } return { index: Array.from(el.children).indexOf(newElement._el), added: newElement, origin: dom }; function randomElementChild() { const children = [...dom._el.children]; if (children.length === 0) dom._el.appendChild(newElement._el); else dom._el.insertBefore(newElement._el, children[rand(0, children.length - 1)]); } } return { get, set, text, html, val, el, remove, focus, first, last, father, children, next, each, addEvent, removeEvent, getStyle, setStyle, getClass, setClass, addClass, removeClass, clearClass, getAttr, setAttr, push, insert }; } function createModule(module) { return { ...module(), setCustomProp(name, value) { this[String(name)] = value; return this; }, setCustomProps(props) { for (const key in props) { this[key] = props[key]; } return this; }, getCustomProp(name) { return this[String(name)]; }, setCustomEvent(name, func, setup = false) { this[name] = func; if (setup) func(this, this); return this; }, callCustomEvent(name, ...args) { this[name](this, ...args); return this; }, then(func, time = 0) { { if (typeof func !== "function") { throw _dev.error("fastjs/base/FastjsBaseModule", "Invalid function, **a function is required**.", [ `***func: ${func}`, `time: ${time}`, "then(**func: (e: T) => void**, time: number = 0): T", "FastjsBaseModule.then" ], ["fastjs.wrong"]); } if (typeof time !== "number") { _dev.warn("fastjs/base/FastjsBaseModule", "Invalid time, **a number is required**.", [ `func: ${func}`, `***time: ${time}`, "then(func: (e: T) => void, **time: number = 0**): T", "FastjsBaseModule.then" ], ["fastjs.warn"]); } } const callback = () => func(this); time === 0 ? callback() : setTimeout(callback, time); return this; } }; } function createFastjsDom(el = document.body, props) { if (typeof el === "string") el = document.createElement(el); else if ("construct" in el && el.construct === "FastjsDom") el = el._el; const moduleAtom = createModule(() => ({ construct: "FastjsDom", _events: [], _el: el })); const module = Object.assign(moduleAtom, createMethods$3(moduleAtom)); if (props) mergeProps(module, props); return module; } function mergeProps(el, props) { let key; for (key in props) { if (key === "html") el.html(props.html); else if (key === "text") el.text(props.text); else if (key === "css") el.setStyle(props.css); else if (key === "class") el.addClass(props.class); else if (key === "attr") el.setAttr(props.attr); else if (key === "val") el.val(props.val); else if (key in el._el) el.set(key, props[key]); } } var dom$2 = /*#__PURE__*/Object.freeze({ __proto__: null, createFastjsDom: createFastjsDom }); function selector(target = "body", parent = document) { const result = _selector(target, parent); if (Array.isArray(result)) return createFastjsDomList(result); if (result === null) return null; return createFastjsDom(result); } const dom = function (target = "body", parent = document) { return selector(target, parent); }; dom.select = selector; dom.newEl = createFastjsDom; dom.newElList = createFastjsDomList; var dom$1 = dom; function extractIgnoreTokens(formatString) { const ignoreTokens = []; let processedString = ""; let tokenBuffer = ""; let depth = 0; for (const char of formatString) { if (char === "<") { if (++depth === 1) continue; } else if (char === ">") { depth--; if (depth === 0) { ignoreTokens.push(tokenBuffer); processedString += `{{*${ignoreTokens.length - 1}}}`; tokenBuffer = ""; continue; } } if (depth > 0) tokenBuffer += char; else processedString += char; } if (depth > 0) processedString += `<${tokenBuffer}`; return [processedString, ignoreTokens]; } function getReplacement(date = new Date()) { const replacement = [ ["Y", date.getFullYear()], ["M", date.getMonth() + 1], ["D", date.getDate()], ["H", date.getHours() % 12], ["hh", date.getHours()], ["h", date.getHours()], ["mm", date.getMinutes()], ["m", date.getMinutes()], ["ss", date.getSeconds()], ["s", date.getSeconds()], ["S", date.getMilliseconds()], // A and a should be the last one because it will affect the result of replacement ["A", date.getHours() >= 12 ? "PM" : "AM"], ["a", date.getHours() >= 12 ? "pm" : "am"] ]; return replacement.map((replacement) => replacement[0].length === 1 && typeof replacement[1] === "number" ? [replacement[0], padZero(replacement[1])] : replacement); function padZero(number) { return number < 10 ? "0" + number : number.toString(); } } function createMethods$2(date) { function changeDate(time) { if (typeof time === "string") { time = parseFormatString(date.format, time); } date._date = time; date._createAt = Date.now(); return date; } const changeFormat = (format) => { date.format = format; return date; }; const setZone = (zone) => { date.timezoneDiff = zone * 3600 * 1000; return date; }; const refresh = () => { date._createAt = Date.now(); return date; }; const toNumber = (utc = true) => utc ? date._date : date._date - date.timezoneDiff; const toActiveNumber = (utc = true) => toNumber(utc) + Date.now() - date._createAt; function toString(showOrFormat, format) { const attrs = { format }; if (!showOrFormat) attrs.show = "utc"; else if (typeof showOrFormat === "number" || ["utc", "local"].includes(showOrFormat)) attrs.show = showOrFormat; else attrs.format = showOrFormat; const [formatString, ignoreTokens] = extractIgnoreTokens(attrs.format || date.format); let t = date._date; if (typeof attrs.show === "number") t -= attrs.show * 3600 * 1000; else if (attrs.show === "local") t -= date.timezoneDiff; let result = formatString; for (const replace of getReplacement(new Date(t))) { const format = replace[0]; const replacement = replace[1]; result = result.replace(new RegExp(format, "g"), String(replacement)); } ignoreTokens.forEach((token, index) => { result = result.replace(`{{*${index}}}`, `${token}`); }); return result; } function toActiveString(showOrFormat, format) { if (typeof showOrFormat === "string" && !["utc", "local"].includes(showOrFormat)) { format = showOrFormat; } return createFastjsDate(format || date.format, toActiveNumber()).toString(); } return { changeDate, changeFormat, setZone, refresh, toNumber, toActiveNumber, toString, toActiveString }; } function parseFormatString(formatString, dateString) { let isInIgnoreToken = false; let parsedDate = new Date(); parsedDate.setMilliseconds(0); let is12Hour = ""; let isAm = null; let isToken = false; let dateStringPointer = -1; const allTokens = getReplacement().map((replacement) => replacement[0]); for (let i = 0; i < formatString.length; i++) { dateStringPointer++; const char = formatString[i]; if (char === "<" || char === ">") { isInIgnoreToken = char === "<"; isToken = false; dateStringPointer--; continue; } if (isInIgnoreToken) { continue; } if (allTokens.includes(char)) { if (isToken) { { throw _dev.error("fastjs/date/FastjsDate", "Invalid format string, token cannot be adjacent, did you using the chars like 'hh', 'mm'?", [ "***formatString: " + formatString, "***dateString: " + dateString, "private parseFormatString(formatString: string, dateString: string): number" ], ["fastjs.wrong"]); } } switch (char) { case "Y": parsedDate.setFullYear(Number(dateString.slice(dateStringPointer, dateStringPointer + 4))); dateStringPointer += 3; break; case "M": parsedDate.setMonth(Number(dateString.slice(dateStringPointer, dateStringPointer + 2)) - 1); dateStringPointer += 1; break; case "D": parsedDate.setDate(Number(dateString.slice(dateStringPointer, dateStringPointer + 2))); dateStringPointer += 1; break; case "H": is12Hour = dateString.slice(dateStringPointer, dateStringPointer + 2); dateStringPointer += 1; break; case "A": isAm = dateString.slice(dateStringPointer, dateStringPointer + 2) === "AM"; dateStringPointer += 1; break; case "a": isAm = dateString.slice(dateStringPointer, dateStringPointer + 2) === "am"; dateStringPointer += 1; break; case "h": parsedDate.setHours(Number(dateString.slice(dateStringPointer, dateStringPointer + 2))); dateStringPointer += 1; break; case "m": parsedDate.setMinutes(Number(dateString.slice(dateStringPointer, dateStringPointer + 2))); dateStringPointer += 1; break; case "s": parsedDate.setSeconds(Number(dateString.slice(dateStringPointer, dateStringPointer + 2))); dateStringPointer += 1; break; case "S": parsedDate.setMilliseconds(Number(dateString.slice(dateStringPointer, dateStringPointer + 3))); dateStringPointer += 2; break; } isToken = true; } else { isToken = false; } } if (is12Hour) { if (isAm === null) { { throw _dev.error("fastjs/date/FastjsDate", "Invalid format string, using 12 hours format but missing AM/PM token", [ "***formatString: " + formatString, "***dateString: " + dateString, "private parseFormatString(formatString: string, dateString: string): number" ], ["fastjs.wrong"]); } } if (isAm) { parsedDate.setHours(Number(is12Hour)); } else { parsedDate.setHours(Number(is12Hour) + 12); } } return parsedDate.getTime(); } function createFastjsDate(format = "Y-M-D h:m:s", date = Date.now(), local = false) { if (typeof date === "string") date = parseFormatString(format, date); else if (date instanceof Date) date = date.getTime(); const moduleAtom = createModule(() => ({ construct: "FastjsDate", format, _date: date, _createAt: Date.now(), timezoneDiff: new Date().getTimezoneOffset() * 60 * 1000 })); if (local) moduleAtom._date += moduleAtom.timezoneDiff; const module = Object.assign(moduleAtom, createMethods$2(moduleAtom)); return module; } /** * @description * Parse a date string or timestamp into a parseReturn object */ const parse$1 = (time, format = "Y-M-D h:m:s") => { const fastjsDateObject = createFastjsDate(format, time); const dateString = fastjsDateObject.toString(); const timestamp = fastjsDateObject.toNumber(); const utc = timestamp + new Date().getTimezoneOffset() * 60 * 1000; return { format, date: new Date(timestamp), string: dateString, dateString, timestamp, utcDate: new Date(utc), utcTimestamp: utc, utcDateString: createFastjsDate(format, utc).toString() }; }; /** * @description * Get a parseReturn object of timestamp or now */ const parseTime = (time, format) => parse$1(time, format); /** * @description * Get a parseReturn object of string or now */ const parseDate = (date, format) => parse$1(date, format); /** * @description * Get a string of timestamp or now * - For string input, use parse(t, f?) or parseDate(t, f?) instead * - For string to string(reformat), use reformat(t, f, nf?) instead * - For other output, use parse(t, f?) instead */ // const string = (format: string, date: number = Date.now()): string => parse(date, format).string; const string = (format, date = Date.now()) => parse$1(date, format).string; /** * @description * Reformat a date string into another format * - For other output, use parse(rf(), f?) instead */ const reformat = (format, date, newFormat = "Y-M-D h:m:s") => createFastjsDate(format, date).toString(newFormat); /** * @description * Get a parseReturn object of now */ const now = (format) => parse$1(Date.now(), format); /** * @description * Create a FastjsDate instance */ var index$2 = { parse: parse$1, parseTime, parseDate, string, reformat, now, create: createFastjsDate }; const globalConfig = { timeout: 5000, hooks: { runAll: false }, handler: { handleResponse: async (response, request) => { if (response.headers.get("Content-Type")?.includes("application/json")) return await response.json(); return await response.text(); }, responseCode: (code) => { return code >= 200 && code < 300; } }, check: { ignoreFormatWarning: false, stringBodyWarning: true, unrecommendedMethodWarning: true } }; function createConfig(config = {}) { return { timeout: config.timeout || globalConfig.timeout, headers: config.headers || {}, wait: config.wait || 0, failed: config.failed || (() => 0), callback: config.callback || (() => 0), query: config.query || null, body: config.body || null, hooks: generateHooks() }; function generateHooks() { const requestHooks = { before: [], init: [], success: [], failed: [] }; let key; for (key in requestHooks) { const addHooks = (hooks) => { if (!hooks) return; requestHooks[key].push( // @ts-ignore ...(Array.isArray(hooks) ? hooks : [hooks])); }; if (config.hooks?.[key]) addHooks(config.hooks[key]); if (globalConfig.hooks[key]) addHooks(globalConfig.hooks[key]); } return Object.assign(requestHooks, { runAll: config.hooks?.runAll || globalConfig.hooks.runAll }); } } function addQuery(url, query) { if (!query || Object.keys(query).length === 0) return url; const urlSearchParams = queryToUrlParams(query); if (urlSearchParams.size > 0) url = url + (url.includes("?") ? "&" : "?") + urlSearchParams.toString(); return url; } function queryToUrlParams(query) { if (typeof query !== "string") return new URLSearchParams(query); if (query[0] === "?") { query = query.slice(1); } const urlSearchParams = new URLSearchParams(); query.split("&").forEach((query) => { const [key, value] = query.split("="); urlSearchParams.set(key, value); }); return urlSearchParams; } function transformPathParams(url, query) { const urlComponents = url.split("/"); const pathReg = /^:/; const matchs = []; return [ urlComponents .map((component) => { const key = component.replace(":", ""); if (pathReg.test(component) && query[key]) { matchs.push(key); const data = query[key]; delete query[key]; return data; } return component; }) .join("/"), matchs ]; } function parse(data) { try { return JSON.parse(data); } catch (error) { return data; } } function sendRequest(request, method, url = request.url) { { if (["GET", "HEAD", "OPTIONS"].includes(method) && request.config.body) { _dev.warn("fastjs/request", `Body is not allowed in ${method} request, use POST instead. (HTTP 1.1)`, [ `url: ${url}`, `*method: ${method}`, `*body: `, request.body, "super: ", request ], ["fastjs.warn"]); } } const data = { body: isBodyAllowed(method) ? request.data : null, query: (isBodyAllowed(method) ? null : request.data) || request.config.query }; if (request.config.wait) { if (request.wait) clearTimeout(request.wait); request.wait = setTimeout(() => { passthrough(); request.wait = null; }, request.config.wait); } else passthrough(); return request; function isBodyAllowed(method) { return !["GET", "HEAD", "OPTIONS"].includes(method); } async function passthrough() { const hooks = request.config.hooks; if (!runHooks(hooks.before, [request])) return hookFailed("before", request, null); let pathParamMatches = []; [url, pathParamMatches] = transformPathParams(url, request.data); for (const match of pathParamMatches) { delete request.data[match]; } request.request = new Request(addQuery(url, data.query), { method, headers: request.config.headers, body: data.body ? JSON.stringify(data.body) : undefined }); if (!runHooks(hooks.init, [request])) return hookFailed("init", request, null); fetch(request.request) .then(async (response) => { const data = await globalConfig.handler.handleResponse(response, request); const requestReturn = { headers: [...response.headers.entries()], headersObj: Object.fromEntries(response.headers.entries()), response, data: parse(data), status: response.status, request, resend: () => sendRequest(request, method) }; if (!globalConfig.handler.responseCode(response.status, request)) return handleBadResponse(requestReturn, request); if (!runHooks(hooks.success, [requestReturn, request])) return hookFailed("success", request, requestReturn); matchCallback(request.callback.success, [data, requestReturn], method); matchCallback(request.callback.finally, [request], method); }) .catch((error) => { _dev.warn("fastjs/request", "Failed to send request.", [ `url: ${url}`, `method: ${method}`, `body: `, request.body, `error: ${error.message}`, "super: ", request ], ["fastjs.wrong"]); if (!runHooks(hooks.failed, [error, request])) return hookFailed("failed", request, null); const failedParams = { error, request, intercept: false, hook: null, response: null }; request.config.failed(failedParams); matchCallback(request.callback.failed, [failedParams], method); matchCallback(request.callback.finally, [request], method); }); } } function matchCallback(callback, params, method) { for (let i = 0; i < callback.length; i++) { const call = callback[i]; if (call.method && call.method !== method) continue; call.func(...params); if (call.once) callback.splice(i, 1), i--; } } function handleBadResponse(response, request, resend) { let status = response?.status; let res = response.data; { _dev.warn("fastjs/request", `Request failed with status code ${status}`, [ `url: ${request.request?.url}`, `method: ${request.request?.method}`, `*code: ${status}`, `*response: `, res, "super: ", request ], ["fastjs.wrong"]); } if (!runHooks(request.config.hooks.failed, [status, request])) return hookFailed("failed", request, null); const failedParams = { error: status, request, intercept: false, hook: null, response }; request.config.failed(failedParams); matchCallback(request.callback.failed, [failedParams], null); matchCallback(request.callback.finally, [request], null); } function hookFailed(hook, request, response) { const failedParams = { error: new Error(`Request interrupted by ${hook}`), request, intercept: true, hook, response }; request.config.failed(failedParams); matchCallback(request.callback.failed, [failedParams], null); matchCallback(request.callback.finally, [request], null); } function runHooks(hooks, params) { if (!hooks) return true; if (typeof hooks === "function") return hooks(params[0], params[1]); let result = true; for (const hook of hooks) { if (!hook(params[0], params[1])) { result = false; if (!globalConfig.hooks.runAll) break; } } return result; } function createMethods$1(request) { const send = (method, data = {}, url) => { request.data = Object.assign(request.data, data); return sendRequest(request, method, url); }; const methods = { send, get: (data, url) => send