@ecency/render-helper 2.4.33 → 2.4.35
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.
- package/dist/browser/index.js +173 -48
- package/dist/browser/index.js.map +1 -1
- package/dist/node/index.cjs +173 -48
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.mjs +173 -48
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/node/index.cjs
CHANGED
|
@@ -4,11 +4,11 @@ var xmldom = require('@xmldom/xmldom');
|
|
|
4
4
|
var xss = require('xss');
|
|
5
5
|
var multihash = require('multihashes');
|
|
6
6
|
var querystring = require('querystring');
|
|
7
|
+
var lruCache = require('lru-cache');
|
|
7
8
|
var remarkable = require('remarkable');
|
|
8
9
|
var linkify$1 = require('remarkable/linkify');
|
|
9
10
|
var htmlparser2 = require('htmlparser2');
|
|
10
11
|
var domSerializerModule = require('dom-serializer');
|
|
11
|
-
var lruCache = require('lru-cache');
|
|
12
12
|
var he = require('he');
|
|
13
13
|
|
|
14
14
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -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
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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
|
-
|
|
224
|
-
|
|
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() === "") {
|
|
@@ -325,6 +414,14 @@ function sanitizeHtml(html) {
|
|
|
325
414
|
});
|
|
326
415
|
}
|
|
327
416
|
var proxyBase = "https://images.ecency.com";
|
|
417
|
+
var urlHashCache = new lruCache.LRUCache({ max: 500 });
|
|
418
|
+
function getUrlHash(url) {
|
|
419
|
+
const cached = urlHashCache.get(url);
|
|
420
|
+
if (cached) return cached;
|
|
421
|
+
const hash = multihash__default.default.toB58String(Buffer.from(url));
|
|
422
|
+
urlHashCache.set(url, hash);
|
|
423
|
+
return hash;
|
|
424
|
+
}
|
|
328
425
|
function setProxyBase(p2) {
|
|
329
426
|
proxyBase = p2;
|
|
330
427
|
}
|
|
@@ -375,7 +472,7 @@ function proxifyImageSrc(url, width = 0, height = 0, _format = "match") {
|
|
|
375
472
|
if (pHash) {
|
|
376
473
|
return `${proxyBase}/p/${pHash}?${qs}`;
|
|
377
474
|
}
|
|
378
|
-
const b58url =
|
|
475
|
+
const b58url = getUrlHash(realUrl.toString());
|
|
379
476
|
return `${proxyBase}/p/${b58url}?${qs}`;
|
|
380
477
|
}
|
|
381
478
|
var SRCSET_WIDTHS = [320, 600, 800, 1024, 1280];
|
|
@@ -1607,7 +1704,6 @@ function markdownToHTML(input, forApp, parentDomain = "ecency.com", seoContext,
|
|
|
1607
1704
|
output = serializer.serializeToString(doc);
|
|
1608
1705
|
} catch (error) {
|
|
1609
1706
|
try {
|
|
1610
|
-
output = md.render(input);
|
|
1611
1707
|
const preSanitized = sanitizeHtml(output);
|
|
1612
1708
|
const dom = htmlparser2__namespace.parseDocument(preSanitized, {
|
|
1613
1709
|
// lenient options - don't throw on malformed HTML
|
|
@@ -1647,7 +1743,7 @@ function simpleMarkdownToHTML(input) {
|
|
|
1647
1743
|
const html = getMd().render(input);
|
|
1648
1744
|
return sanitizeHtml(html);
|
|
1649
1745
|
}
|
|
1650
|
-
var cache = new lruCache.LRUCache({ max:
|
|
1746
|
+
var cache = new lruCache.LRUCache({ max: 500 });
|
|
1651
1747
|
function setCacheSize(size) {
|
|
1652
1748
|
cache = new lruCache.LRUCache({ max: size });
|
|
1653
1749
|
}
|
|
@@ -1678,6 +1774,40 @@ var gifLinkRegex = /\.(gif)$/i;
|
|
|
1678
1774
|
function isGifLink(link) {
|
|
1679
1775
|
return gifLinkRegex.test(link);
|
|
1680
1776
|
}
|
|
1777
|
+
var BACKTICK_FENCE_RE = /```[\s\S]*?```/g;
|
|
1778
|
+
var TILDE_FENCE_RE = /~~~[\s\S]*?~~~/g;
|
|
1779
|
+
var INLINE_CODE_RE = /`[^`\n]*`/g;
|
|
1780
|
+
var INDENTED_CODE_RE = /^(?: {4}|\t).+$/gm;
|
|
1781
|
+
var MD_IMAGE_RE = /!\[[^\]]*\]\(\s*([^)\s]+)(?:\s+["'][^"']*["'])?\s*\)/;
|
|
1782
|
+
var HTML_IMAGE_RE = /<img\b[^>]*?\bsrc\s*=\s*["']([^"']+)["']/i;
|
|
1783
|
+
var SAFE_URL_RE = /^https?:\/\//i;
|
|
1784
|
+
function findFirstImageUrl(body) {
|
|
1785
|
+
if (!body) return null;
|
|
1786
|
+
const cleaned = body.replace(BACKTICK_FENCE_RE, "").replace(TILDE_FENCE_RE, "").replace(INLINE_CODE_RE, "").replace(INDENTED_CODE_RE, "");
|
|
1787
|
+
const mdMatch = cleaned.match(MD_IMAGE_RE);
|
|
1788
|
+
const htmlMatch = cleaned.match(HTML_IMAGE_RE);
|
|
1789
|
+
if (mdMatch) {
|
|
1790
|
+
const url = mdMatch[1];
|
|
1791
|
+
if (!url || !SAFE_URL_RE.test(url) || url.includes("(")) {
|
|
1792
|
+
return null;
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
const mdValid = !!mdMatch;
|
|
1796
|
+
const htmlValid = !!(htmlMatch && htmlMatch[1] && SAFE_URL_RE.test(htmlMatch[1]));
|
|
1797
|
+
if (mdValid && htmlValid) {
|
|
1798
|
+
return (mdMatch.index ?? 0) < (htmlMatch.index ?? 0) ? mdMatch[1] : htmlMatch[1];
|
|
1799
|
+
}
|
|
1800
|
+
if (mdValid) return mdMatch[1];
|
|
1801
|
+
if (htmlValid) return htmlMatch[1];
|
|
1802
|
+
return null;
|
|
1803
|
+
}
|
|
1804
|
+
function proxifyFound(src, width, height, format) {
|
|
1805
|
+
const decoded = he__default.default.decode(src);
|
|
1806
|
+
if (isGifLink(decoded)) {
|
|
1807
|
+
return proxifyImageSrc(decoded, 0, 0, format);
|
|
1808
|
+
}
|
|
1809
|
+
return proxifyImageSrc(decoded, width, height, format);
|
|
1810
|
+
}
|
|
1681
1811
|
function getImage(entry, width = 0, height = 0, format = "match") {
|
|
1682
1812
|
let meta;
|
|
1683
1813
|
if (typeof entry.json_metadata === "object") {
|
|
@@ -1709,6 +1839,10 @@ function getImage(entry, width = 0, height = 0, format = "match") {
|
|
|
1709
1839
|
}
|
|
1710
1840
|
return proxifyImageSrc(meta.image[0], width, height, format);
|
|
1711
1841
|
}
|
|
1842
|
+
const fast = findFirstImageUrl(entry.body);
|
|
1843
|
+
if (fast) {
|
|
1844
|
+
return proxifyFound(fast, width, height, format);
|
|
1845
|
+
}
|
|
1712
1846
|
const html = markdown2Html(entry);
|
|
1713
1847
|
const doc = createDoc(html);
|
|
1714
1848
|
if (!doc) {
|
|
@@ -1720,16 +1854,16 @@ function getImage(entry, width = 0, height = 0, format = "match") {
|
|
|
1720
1854
|
if (!src) {
|
|
1721
1855
|
return null;
|
|
1722
1856
|
}
|
|
1723
|
-
|
|
1724
|
-
if (isGifLink(decodedSrc)) {
|
|
1725
|
-
return proxifyImageSrc(decodedSrc, 0, 0, format);
|
|
1726
|
-
}
|
|
1727
|
-
return proxifyImageSrc(decodedSrc, width, height, format);
|
|
1857
|
+
return proxifyFound(src, width, height, format);
|
|
1728
1858
|
}
|
|
1729
1859
|
return null;
|
|
1730
1860
|
}
|
|
1731
1861
|
function catchPostImage(obj, width = 0, height = 0, format = "match") {
|
|
1732
1862
|
if (typeof obj === "string") {
|
|
1863
|
+
const fast = findFirstImageUrl(obj);
|
|
1864
|
+
if (fast) {
|
|
1865
|
+
return proxifyFound(fast, width, height, format);
|
|
1866
|
+
}
|
|
1733
1867
|
const html = markdown2Html(obj);
|
|
1734
1868
|
const doc = createDoc(html);
|
|
1735
1869
|
if (!doc) {
|
|
@@ -1741,11 +1875,7 @@ function catchPostImage(obj, width = 0, height = 0, format = "match") {
|
|
|
1741
1875
|
if (!src) {
|
|
1742
1876
|
return null;
|
|
1743
1877
|
}
|
|
1744
|
-
|
|
1745
|
-
if (isGifLink(decodedSrc)) {
|
|
1746
|
-
return proxifyImageSrc(decodedSrc, 0, 0, format);
|
|
1747
|
-
}
|
|
1748
|
-
return proxifyImageSrc(decodedSrc, width, height, format);
|
|
1878
|
+
return proxifyFound(src, width, height, format);
|
|
1749
1879
|
}
|
|
1750
1880
|
return null;
|
|
1751
1881
|
}
|
|
@@ -1758,6 +1888,20 @@ function catchPostImage(obj, width = 0, height = 0, format = "match") {
|
|
|
1758
1888
|
cacheSet(key, res);
|
|
1759
1889
|
return res;
|
|
1760
1890
|
}
|
|
1891
|
+
var summaryRenderer = new remarkable.Remarkable({
|
|
1892
|
+
html: true,
|
|
1893
|
+
breaks: true,
|
|
1894
|
+
typographer: false
|
|
1895
|
+
});
|
|
1896
|
+
summaryRenderer.core.ruler.enable(["abbr"]);
|
|
1897
|
+
summaryRenderer.block.ruler.enable(["footnote", "deflist"]);
|
|
1898
|
+
summaryRenderer.inline.ruler.enable([
|
|
1899
|
+
"footnote_inline",
|
|
1900
|
+
"ins",
|
|
1901
|
+
"mark",
|
|
1902
|
+
"sub",
|
|
1903
|
+
"sup"
|
|
1904
|
+
]);
|
|
1761
1905
|
var joint = (arr, limit = 200) => {
|
|
1762
1906
|
let result = "";
|
|
1763
1907
|
if (arr) {
|
|
@@ -1783,25 +1927,6 @@ function postBodySummary(entryBody, length = 200, platform = "web") {
|
|
|
1783
1927
|
return "";
|
|
1784
1928
|
}
|
|
1785
1929
|
entryBody = cleanReply(entryBody);
|
|
1786
|
-
const mdd = new remarkable.Remarkable({
|
|
1787
|
-
html: true,
|
|
1788
|
-
breaks: true,
|
|
1789
|
-
typographer: false
|
|
1790
|
-
}).use(linkify$1.linkify);
|
|
1791
|
-
mdd.core.ruler.enable([
|
|
1792
|
-
"abbr"
|
|
1793
|
-
]);
|
|
1794
|
-
mdd.block.ruler.enable([
|
|
1795
|
-
"footnote",
|
|
1796
|
-
"deflist"
|
|
1797
|
-
]);
|
|
1798
|
-
mdd.inline.ruler.enable([
|
|
1799
|
-
"footnote_inline",
|
|
1800
|
-
"ins",
|
|
1801
|
-
"mark",
|
|
1802
|
-
"sub",
|
|
1803
|
-
"sup"
|
|
1804
|
-
]);
|
|
1805
1930
|
const entities = entryBody.match(ENTITY_REGEX);
|
|
1806
1931
|
const entityPlaceholders = [];
|
|
1807
1932
|
if (entities && platform !== "web") {
|
|
@@ -1814,7 +1939,7 @@ function postBodySummary(entryBody, length = 200, platform = "web") {
|
|
|
1814
1939
|
}
|
|
1815
1940
|
let text2 = "";
|
|
1816
1941
|
try {
|
|
1817
|
-
text2 =
|
|
1942
|
+
text2 = summaryRenderer.render(entryBody);
|
|
1818
1943
|
} catch (err) {
|
|
1819
1944
|
console.error("[postBodySummary] Failed to render markdown:", {
|
|
1820
1945
|
error: err instanceof Error ? err.message : String(err),
|