UNPKG

elysia

Version:

Ergonomic Framework for Human

367 lines (364 loc) 15.1 kB
// src/universal/utils.ts var isBun = typeof Bun < "u"; // src/utils.ts var hasHeaderShorthand = "toJSON" in new Headers(); var primitiveHooks = [ "start", "request", "parse", "transform", "resolve", "beforeHandle", "afterHandle", "mapResponse", "afterResponse", "trace", "error", "stop", "body", "headers", "params", "query", "response", "type", "detail" ], primitiveHookMap = primitiveHooks.reduce( (acc, x) => (acc[x] = !0, acc), {} ); var isBun2 = typeof Bun < "u", hasBunHash = isBun2 && typeof Bun.hash == "function", checksum = (s) => { if (hasBunHash) return Bun.hash(s); let h = 9; for (let i = 0; i < s.length; ) h = Math.imul(h ^ s.charCodeAt(i++), 9 ** 9); return h = h ^ h >>> 9; }; var StatusMap = { Continue: 100, "Switching Protocols": 101, Processing: 102, "Early Hints": 103, OK: 200, Created: 201, Accepted: 202, "Non-Authoritative Information": 203, "No Content": 204, "Reset Content": 205, "Partial Content": 206, "Multi-Status": 207, "Already Reported": 208, "Multiple Choices": 300, "Moved Permanently": 301, Found: 302, "See Other": 303, "Not Modified": 304, "Temporary Redirect": 307, "Permanent Redirect": 308, "Bad Request": 400, Unauthorized: 401, "Payment Required": 402, Forbidden: 403, "Not Found": 404, "Method Not Allowed": 405, "Not Acceptable": 406, "Proxy Authentication Required": 407, "Request Timeout": 408, Conflict: 409, Gone: 410, "Length Required": 411, "Precondition Failed": 412, "Payload Too Large": 413, "URI Too Long": 414, "Unsupported Media Type": 415, "Range Not Satisfiable": 416, "Expectation Failed": 417, "I'm a teapot": 418, "Misdirected Request": 421, "Unprocessable Content": 422, Locked: 423, "Failed Dependency": 424, "Too Early": 425, "Upgrade Required": 426, "Precondition Required": 428, "Too Many Requests": 429, "Request Header Fields Too Large": 431, "Unavailable For Legal Reasons": 451, "Internal Server Error": 500, "Not Implemented": 501, "Bad Gateway": 502, "Service Unavailable": 503, "Gateway Timeout": 504, "HTTP Version Not Supported": 505, "Variant Also Negotiates": 506, "Insufficient Storage": 507, "Loop Detected": 508, "Not Extended": 510, "Network Authentication Required": 511 }, InvertedStatusMap = Object.fromEntries( Object.entries(StatusMap).map(([k, v]) => [v, k]) ); var encoder = new TextEncoder(); var ELYSIA_FORM_DATA = Symbol("ElysiaFormData"), ELYSIA_REQUEST_ID = Symbol("ElysiaRequestId"); var supportPerMethodInlineHandler = (() => { if (typeof Bun > "u") return !0; let semver = Bun.version.split("."); return !(+semver[0] < 1 || +semver[1] < 2 || +semver[2] < 14); })(); // src/sucrose.ts var separateFunction = (code) => { code.startsWith("async") && (code = code.slice(5)), code = code.trimStart(); let index = -1; if (code.charCodeAt(0) === 40 && (index = code.indexOf("=>", code.indexOf(")")), index !== -1)) { let bracketEndIndex = index; for (; bracketEndIndex > 0 && code.charCodeAt(--bracketEndIndex) !== 41; ) ; let body = code.slice(index + 2); return body.charCodeAt(0) === 32 && (body = body.trimStart()), [ code.slice(1, bracketEndIndex), body, { isArrowReturn: body.charCodeAt(0) !== 123 } ]; } if (/^(\w+)=>/g.test(code) && (index = code.indexOf("=>"), index !== -1)) { let body = code.slice(index + 2); return body.charCodeAt(0) === 32 && (body = body.trimStart()), [ code.slice(0, index), body, { isArrowReturn: body.charCodeAt(0) !== 123 } ]; } if (code.startsWith("function")) { index = code.indexOf("("); let end = code.indexOf(")"); return [ code.slice(index + 1, end), code.slice(end + 2), { isArrowReturn: !1 } ]; } let start = code.indexOf("("); if (start !== -1) { let sep = code.indexOf(` `, 2), parameter = code.slice(0, sep), end = parameter.lastIndexOf(")") + 1, body = code.slice(sep + 1); return [ parameter.slice(start, end), "{" + body, { isArrowReturn: !1 } ]; } let x = code.split(` `, 2); return [x[0], x[1], { isArrowReturn: !1 }]; }, bracketPairRange = (parameter) => { let start = parameter.indexOf("{"); if (start === -1) return [-1, 0]; let end = start + 1, deep = 1; for (; end < parameter.length; end++) { let char = parameter.charCodeAt(end); if (char === 123 ? deep++ : char === 125 && deep--, deep === 0) break; } return deep !== 0 ? [0, parameter.length] : [start, end + 1]; }, bracketPairRangeReverse = (parameter) => { let end = parameter.lastIndexOf("}"); if (end === -1) return [-1, 0]; let start = end - 1, deep = 1; for (; start >= 0; start--) { let char = parameter.charCodeAt(start); if (char === 125 ? deep++ : char === 123 && deep--, deep === 0) break; } return deep !== 0 ? [-1, 0] : [start, end + 1]; }, removeColonAlias = (parameter) => { for (; ; ) { let start = parameter.indexOf(":"); if (start === -1) break; let end = parameter.indexOf(",", start); end === -1 && (end = parameter.indexOf("}", start) - 1), end === -2 && (end = parameter.length), parameter = parameter.slice(0, start) + parameter.slice(end); } return parameter; }, retrieveRootParamters = (parameter) => { let hasParenthesis = !1; parameter.charCodeAt(0) === 40 && (parameter = parameter.slice(1, -1)), parameter.charCodeAt(0) === 123 && (hasParenthesis = !0, parameter = parameter.slice(1, -1)), parameter = parameter.replace(/( |\t|\n)/g, "").trim(); let parameters = []; for (; ; ) { let [start, end] = bracketPairRange(parameter); if (start === -1) break; parameters.push(parameter.slice(0, start - 1)), parameter.charCodeAt(end) === 44 && end++, parameter = parameter.slice(end); } parameter = removeColonAlias(parameter), parameter && (parameters = parameters.concat(parameter.split(","))); let parameterMap = /* @__PURE__ */ Object.create(null); for (let p of parameters) { if (p.indexOf(",") === -1) { parameterMap[p] = !0; continue; } for (let q of p.split(",")) parameterMap[q.trim()] = !0; } return { hasParenthesis, parameters: parameterMap }; }, findParameterReference = (parameter, inference) => { let { parameters, hasParenthesis } = retrieveRootParamters(parameter); return parameters.query && (inference.query = !0), parameters.headers && (inference.headers = !0), parameters.body && (inference.body = !0), parameters.cookie && (inference.cookie = !0), parameters.set && (inference.set = !0), parameters.server && (inference.server = !0), parameters.route && (inference.route = !0), parameters.url && (inference.url = !0), parameters.path && (inference.path = !0), hasParenthesis ? `{ ${Object.keys(parameters).join(", ")} }` : Object.keys(parameters).join(", "); }, findEndIndex = (type, content, index) => { let regex = new RegExp( `${type.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[\\n\\t,; ]` ); index !== void 0 && (regex.lastIndex = index); let match = regex.exec(content); return match ? match.index : -1; }; var findAlias = (type, body, depth = 0) => { if (depth > 5) return []; let aliases = [], content = body; for (; ; ) { let index = findEndIndex(" = " + type, content); if (index === -1 && (index = findEndIndex("=" + type, content)), index === -1) { let lastIndex = content.indexOf(" = " + type); if (lastIndex === -1 && (lastIndex = content.indexOf("=" + type)), lastIndex + 3 + type.length !== content.length) break; index = lastIndex; } let part = content.slice(0, index), lastPart = part.lastIndexOf(" "), variable = part.slice(lastPart !== -1 ? lastPart + 1 : -1); if (variable === "}") { let [start, end] = bracketPairRangeReverse(part); aliases.push(removeColonAlias(content.slice(start, end))), content = content.slice(index + 3 + type.length); continue; } for (; variable.charCodeAt(0) === 44; ) variable = variable.slice(1); for (; variable.charCodeAt(0) === 9; ) variable = variable.slice(1); variable.includes("(") || aliases.push(variable), content = content.slice(index + 3 + type.length); } for (let alias of aliases) { if (alias.charCodeAt(0) === 123) continue; let deepAlias = findAlias(alias, body); deepAlias.length > 0 && aliases.push(...deepAlias); } return aliases; }, extractMainParameter = (parameter) => { if (!parameter) return; if (parameter.charCodeAt(0) !== 123) return parameter; if (parameter = parameter.slice(2, -2), !parameter.includes(",")) return parameter.indexOf("...") !== -1 ? parameter.slice(parameter.indexOf("...") + 3) : void 0; let spreadIndex = parameter.indexOf("..."); if (spreadIndex !== -1) return parameter.slice(spreadIndex + 3).trimEnd(); }, inferBodyReference = (code, aliases, inference) => { let access = (type, alias) => new RegExp( `${alias}\\.(${type})|${alias}\\["${type}"\\]|${alias}\\['${type}'\\]` ).test(code); for (let alias of aliases) if (alias) { if (alias.charCodeAt(0) === 123) { let parameters = retrieveRootParamters(alias).parameters; parameters.query && (inference.query = !0), parameters.headers && (inference.headers = !0), parameters.body && (inference.body = !0), parameters.cookie && (inference.cookie = !0), parameters.set && (inference.set = !0), parameters.server && (inference.server = !0), parameters.url && (inference.url = !0), parameters.route && (inference.route = !0), parameters.path && (inference.path = !0); continue; } if (!inference.query && (access("query", alias) || code.includes("return " + alias) || code.includes("return " + alias + ".query")) && (inference.query = !0), !inference.headers && access("headers", alias) && (inference.headers = !0), !inference.body && access("body", alias) && (inference.body = !0), !inference.cookie && access("cookie", alias) && (inference.cookie = !0), !inference.set && access("set", alias) && (inference.set = !0), !inference.server && access("server", alias) && (inference.server = !0), !inference.route && access("route", alias) && (inference.route = !0), !inference.url && access("url", alias) && (inference.url = !0), !inference.path && access("path", alias) && (inference.path = !0), inference.query && inference.headers && inference.body && inference.cookie && inference.set && inference.server && inference.route && inference.url && inference.path) break; } return aliases; }, removeDefaultParameter = (parameter) => { for (; ; ) { let index = parameter.indexOf("="); if (index === -1) break; let commaIndex = parameter.indexOf(",", index), bracketIndex = parameter.indexOf("}", index), end = [commaIndex, bracketIndex].filter((i) => i > 0).sort((a, b) => a - b)[0] || -1; if (end === -1) { parameter = parameter.slice(0, index); break; } parameter = parameter.slice(0, index) + parameter.slice(end); } return parameter.split(",").map((i) => i.trim()).join(", "); }, isContextPassToFunction = (context, body, inference) => { try { let captureFunction = new RegExp(`\\w\\((.*?)?${context}`, "gs"); captureFunction.test(body); let nextChar = body.charCodeAt(captureFunction.lastIndex); return nextChar === 41 || nextChar === 44 ? (inference.query = !0, inference.headers = !0, inference.body = !0, inference.cookie = !0, inference.set = !0, inference.server = !0, inference.url = !0, inference.route = !0, inference.path = !0, !0) : !1; } catch { return console.log( "[Sucrose] warning: unexpected isContextPassToFunction error, you may continue development as usual but please report the following to maintainers:" ), console.log("--- body ---"), console.log(body), console.log("--- context ---"), console.log(context), !0; } }, pendingGC, caches = {}, clearSucroseCache = (delay = 0) => { pendingGC && clearTimeout(pendingGC), pendingGC = setTimeout(() => { caches = {}, pendingGC = void 0, isBun && Bun.gc(!1); }, delay); }, mergeInference = (a, b) => ({ body: a.body || b.body, cookie: a.cookie || b.cookie, headers: a.headers || b.headers, query: a.query || b.query, set: a.set || b.set, server: a.server || b.server, url: a.url || b.url, route: a.route || b.route, path: a.path || b.path }), sucrose = (lifeCycle, inference = { query: !1, headers: !1, body: !1, cookie: !1, set: !1, server: !1, url: !1, route: !1, path: !1 }) => { let events = []; lifeCycle.request?.length && events.push(...lifeCycle.request), lifeCycle.beforeHandle?.length && events.push(...lifeCycle.beforeHandle), lifeCycle.parse?.length && events.push(...lifeCycle.parse), lifeCycle.error?.length && events.push(...lifeCycle.error), lifeCycle.transform?.length && events.push(...lifeCycle.transform), lifeCycle.afterHandle?.length && events.push(...lifeCycle.afterHandle), lifeCycle.mapResponse?.length && events.push(...lifeCycle.mapResponse), lifeCycle.afterResponse?.length && events.push(...lifeCycle.afterResponse), lifeCycle.handler && typeof lifeCycle.handler == "function" && events.push(lifeCycle.handler); for (let i = 0; i < events.length; i++) { let e = events[i]; if (!e) continue; let event = typeof e == "object" ? e.fn : e; if (typeof event != "function") continue; let content = event.toString(), key = checksum(content), cachedInference = caches[key]; if (cachedInference) { inference = mergeInference(inference, cachedInference); continue; } let fnInference = { query: !1, headers: !1, body: !1, cookie: !1, set: !1, server: !1, url: !1, route: !1, path: !1 }, [parameter, body] = separateFunction(content), rootParameters = findParameterReference(parameter, fnInference), mainParameter = extractMainParameter(rootParameters); if (mainParameter) { let aliases = findAlias(mainParameter, body.slice(1, -1)); aliases.splice(0, -1, mainParameter); let code = body; code.charCodeAt(0) === 123 && code.charCodeAt(body.length - 1) === 125 && (code = code.slice(1, -1)), isContextPassToFunction(mainParameter, code, fnInference) || inferBodyReference(code, aliases, fnInference), !fnInference.query && code.includes("return " + mainParameter + ".query") && (fnInference.query = !0); } if (caches[key] || (caches[key] = fnInference), inference = mergeInference(inference, fnInference), inference.query && inference.headers && inference.body && inference.cookie && inference.set && inference.server && inference.url && inference.route && inference.path) break; } return inference; }; export { bracketPairRange, bracketPairRangeReverse, clearSucroseCache, extractMainParameter, findAlias, findParameterReference, inferBodyReference, isContextPassToFunction, mergeInference, removeColonAlias, removeDefaultParameter, retrieveRootParamters, separateFunction, sucrose };