@ecency/render-helper 2.4.34 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -206,23 +206,112 @@ function createParser() {
206
206
  var DOMParser = createParser();
207
207
 
208
208
  // src/helper.ts
209
+ function isSpaceChar(c) {
210
+ return c === 32 || c === 9 || c === 10 || c === 13 || c === 12;
211
+ }
212
+ function isAsciiLetter(c) {
213
+ return c >= 65 && c <= 90 || c >= 97 && c <= 122;
214
+ }
215
+ function isTagNameChar(c) {
216
+ return isAsciiLetter(c) || c >= 48 && c <= 57;
217
+ }
218
+ function isAttrNameChar(c) {
219
+ return isAsciiLetter(c) || c >= 48 && c <= 57 || c === 45 || c === 95 || c === 58 || c === 46;
220
+ }
209
221
  function removeDuplicateAttributes(html) {
210
- const tagRegex = /<([a-zA-Z][a-zA-Z0-9]*)\s+((?:[^>"']+|"[^"]*"|'[^']*')*?)\s*(\/?)>/g;
211
- return html.replace(tagRegex, (match, tagName, attrsString, selfClose) => {
212
- const seenAttrs = /* @__PURE__ */ new Set();
213
- const cleanedAttrs = [];
214
- const attrRegex = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)\s*(?:=\s*(?:"[^"]*"|'[^']*'|[^\s/>]+))?/g;
215
- let attrMatch;
216
- while ((attrMatch = attrRegex.exec(attrsString)) !== null) {
217
- const attrName = attrMatch[1].toLowerCase();
218
- if (!seenAttrs.has(attrName)) {
219
- seenAttrs.add(attrName);
220
- cleanedAttrs.push(attrMatch[0]);
222
+ const n = html.length;
223
+ let out = "";
224
+ let i = 0;
225
+ while (i < n) {
226
+ const lt = html.indexOf("<", i);
227
+ if (lt < 0) {
228
+ out += html.slice(i);
229
+ break;
230
+ }
231
+ out += html.slice(i, lt);
232
+ if (lt + 1 >= n || !isAsciiLetter(html.charCodeAt(lt + 1))) {
233
+ out += "<";
234
+ i = lt + 1;
235
+ continue;
236
+ }
237
+ let p2 = lt + 1;
238
+ while (p2 < n && isTagNameChar(html.charCodeAt(p2))) p2++;
239
+ const tagName = html.slice(lt + 1, p2);
240
+ if (p2 >= n || !isSpaceChar(html.charCodeAt(p2))) {
241
+ out += "<";
242
+ i = lt + 1;
243
+ continue;
244
+ }
245
+ const attrs = [];
246
+ const seen = /* @__PURE__ */ new Set();
247
+ let q = p2;
248
+ while (q < n) {
249
+ while (q < n && isSpaceChar(html.charCodeAt(q))) q++;
250
+ if (q >= n) break;
251
+ const ch = html.charCodeAt(q);
252
+ if (ch === 62) break;
253
+ if (ch === 47 && q + 1 < n && html.charCodeAt(q + 1) === 62) break;
254
+ const nameStart = q;
255
+ while (q < n && isAttrNameChar(html.charCodeAt(q))) q++;
256
+ if (q === nameStart) {
257
+ q++;
258
+ continue;
259
+ }
260
+ const attrName = html.slice(nameStart, q);
261
+ let r = q;
262
+ while (r < n && isSpaceChar(html.charCodeAt(r))) r++;
263
+ let valueEnd = q;
264
+ if (r < n && html.charCodeAt(r) === 61) {
265
+ r++;
266
+ while (r < n && isSpaceChar(html.charCodeAt(r))) r++;
267
+ if (r < n) {
268
+ const v = html.charCodeAt(r);
269
+ if (v === 34 || v === 39) {
270
+ const quote = html[r];
271
+ const end = html.indexOf(quote, r + 1);
272
+ if (end < 0) {
273
+ const gt = html.indexOf(">", r + 1);
274
+ valueEnd = gt < 0 ? n : gt;
275
+ } else {
276
+ valueEnd = end + 1;
277
+ }
278
+ } else {
279
+ let s = r;
280
+ while (s < n) {
281
+ const k = html.charCodeAt(s);
282
+ if (isSpaceChar(k) || k === 62) break;
283
+ s++;
284
+ }
285
+ valueEnd = s;
286
+ }
287
+ } else {
288
+ valueEnd = r;
289
+ }
290
+ }
291
+ const fullAttr = html.slice(nameStart, valueEnd);
292
+ q = valueEnd;
293
+ const key = attrName.toLowerCase();
294
+ if (!seen.has(key)) {
295
+ seen.add(key);
296
+ attrs.push(fullAttr);
221
297
  }
222
298
  }
223
- const attrsJoined = cleanedAttrs.length > 0 ? ` ${cleanedAttrs.join(" ")}` : "";
224
- return `<${tagName}${attrsJoined}${selfClose ? " /" : ""}>`;
225
- });
299
+ let selfClose = false;
300
+ if (q < n && html.charCodeAt(q) === 47) {
301
+ selfClose = true;
302
+ q++;
303
+ }
304
+ if (q >= n || html.charCodeAt(q) !== 62) {
305
+ out += "<";
306
+ i = lt + 1;
307
+ continue;
308
+ }
309
+ q++;
310
+ const attrsJoined = attrs.length > 0 ? " " + attrs.join(" ") : "";
311
+ out += "<" + tagName + attrsJoined + (selfClose ? " /" : "") + ">";
312
+ i = q;
313
+ }
314
+ return out;
226
315
  }
227
316
  function createDoc(html) {
228
317
  if (html.trim() === "") {
@@ -1615,7 +1704,6 @@ function markdownToHTML(input, forApp, parentDomain = "ecency.com", seoContext,
1615
1704
  output = serializer.serializeToString(doc);
1616
1705
  } catch (error) {
1617
1706
  try {
1618
- output = md.render(input);
1619
1707
  const preSanitized = sanitizeHtml(output);
1620
1708
  const dom = htmlparser2__namespace.parseDocument(preSanitized, {
1621
1709
  // lenient options - don't throw on malformed HTML
@@ -1667,10 +1755,25 @@ function cacheSet(key, value) {
1667
1755
  }
1668
1756
 
1669
1757
  // src/markdown-2-html.ts
1758
+ var isNodeRuntime = typeof process !== "undefined" && typeof process?.versions?.node === "string";
1759
+ var slowRenderThresholdMs = isNodeRuntime ? 500 : 0;
1760
+ function setSlowRenderThresholdMs(ms) {
1761
+ slowRenderThresholdMs = Math.max(0, ms);
1762
+ }
1763
+ function logIfSlow(durationMs, context) {
1764
+ if (slowRenderThresholdMs > 0 && durationMs >= slowRenderThresholdMs) {
1765
+ console.warn(
1766
+ `[render-helper] slow markdown render: ${durationMs.toFixed(0)}ms ${context}`
1767
+ );
1768
+ }
1769
+ }
1670
1770
  function markdown2Html(obj, forApp = true, _webp = false, parentDomain = "ecency.com", seoContext, renderOptions) {
1671
1771
  if (typeof obj === "string") {
1672
1772
  const cleanedStr = cleanReply(obj);
1673
- return markdownToHTML(cleanedStr, forApp, parentDomain, seoContext, renderOptions);
1773
+ const t02 = performance.now();
1774
+ const res2 = markdownToHTML(cleanedStr, forApp, parentDomain, seoContext, renderOptions);
1775
+ logIfSlow(performance.now() - t02, `body_len=${obj.length}`);
1776
+ return res2;
1674
1777
  }
1675
1778
  const key = `${makeEntryCacheKey(obj)}-md-${forApp ? "app" : "site"}-${parentDomain}${seoContext ? `-seo${seoContext.authorReputation ?? ""}-${seoContext.postPayout ?? ""}` : ""}${renderOptions?.embedVideosDirectly ? "-embed" : ""}`;
1676
1779
  const item = cacheGet(key);
@@ -1678,7 +1781,12 @@ function markdown2Html(obj, forApp = true, _webp = false, parentDomain = "ecency
1678
1781
  return item;
1679
1782
  }
1680
1783
  const cleanBody = cleanReply(obj.body);
1784
+ const t0 = performance.now();
1681
1785
  const res = markdownToHTML(cleanBody, forApp, parentDomain, seoContext, renderOptions);
1786
+ logIfSlow(
1787
+ performance.now() - t0,
1788
+ `author=@${obj.author} permlink=${obj.permlink} body_len=${obj.body?.length ?? 0}`
1789
+ );
1682
1790
  cacheSet(key, res);
1683
1791
  return res;
1684
1792
  }
@@ -1900,6 +2008,7 @@ exports.proxifyImageSrc = proxifyImageSrc;
1900
2008
  exports.renderPostBody = markdown2Html;
1901
2009
  exports.setCacheSize = setCacheSize;
1902
2010
  exports.setProxyBase = setProxyBase;
2011
+ exports.setSlowRenderThresholdMs = setSlowRenderThresholdMs;
1903
2012
  exports.simpleMarkdownToHTML = simpleMarkdownToHTML;
1904
2013
  //# sourceMappingURL=index.cjs.map
1905
2014
  //# sourceMappingURL=index.cjs.map