|
291 | 291 | if (m) { |
292 | 292 | openTag = m[1].replace(/\\/g, ''); |
293 | 293 | if (openTag === '↓↓') closeTag = '↑↑'; |
294 | | - else if (openTag.startsWith('{')) closeTag = openTag.endsWith('}') ? '{/' + openTag.substring(1) : '{/' + openTag.substring(1).replace(/[:\-].*/, '') + '}'; |
| 294 | + else if (openTag.startsWith('{')) { |
| 295 | + closeTag = openTag.endsWith('}') ? '{/' + openTag.substring(1) : '{/' + openTag.substring(1).replace(/[:\-].*/, '') + '}'; |
| 296 | + } |
295 | 297 | } |
296 | 298 | } |
297 | 299 | return { ...r, openTag, closeTag }; |
298 | 300 | }); |
299 | 301 | } |
300 | | - parse(str) { return this.render(this.tokenize(str)); } |
| 302 | + |
| 303 | + parse(str) { |
| 304 | + return this.render(this.tokenize(str)); |
| 305 | + } |
| 306 | + |
301 | 307 | tokenize(str) { |
302 | 308 | let tokens = [], i = 0, len = str.length; |
303 | 309 | while (i < len) { |
304 | 310 | if (str[i] === '\\' && i + 1 < len) { tokens.push({ type: 'text', val: str[i + 1] }); i += 2; continue; } |
305 | | - if (str.startsWith('; |
307 | | - if (c1 > -1) { |
308 | | - let c2 = str.indexOf(')', c1 + 2); |
309 | | - if (c2 > -1) { tokens.push({ type: 'img', alt: str.slice(i + 2, c1), url: str.slice(c1 + 2, c2) }); i = c2 + 1; continue; } |
310 | | - } |
311 | | - } |
312 | | - if (str.startsWith('[', i)) { |
313 | | - let c1 = str.indexOf('](', i + 1); |
314 | | - if (c1 > -1) { |
315 | | - let c2 = str.indexOf(')', c1 + 2); |
316 | | - if (c2 > -1) { tokens.push({ type: 'link', content: this.tokenize(str.slice(i + 1, c1)), url: str.slice(c1 + 2, c2) }); i = c2 + 1; continue; } |
317 | | - } |
318 | | - } |
319 | 311 | let matched = false; |
320 | 312 | for (let r of this.customRules) { |
321 | 313 | if (r.regex) { |
|
333 | 325 | if (outer.indexOf(r.openTag, r.openTag.length) > -1) { |
334 | 326 | let out = outer.substring(0, r.openTag.length), innerD = 0, sIdx = -1; |
335 | 327 | for (let k = r.openTag.length; k < outer.length - r.closeTag.length; ) { |
336 | | - if (outer[k] === '\\' && k + 1 < outer.length) { if (innerD === 0) out += outer.substring(k, k+2); k += 2; continue; } |
| 328 | + if (outer[k] === '\\' && k + 1 < outer.length) { |
| 329 | + if (innerD === 0) out += outer.substring(k, k+2); |
| 330 | + k += 2; continue; |
| 331 | + } |
337 | 332 | if (outer.startsWith(r.openTag, k)) { if (innerD === 0) sIdx = k; innerD++; k += r.openTag.length; } |
338 | 333 | else if (outer.startsWith(r.closeTag, k)) { |
339 | 334 | innerD--; k += r.closeTag.length; |
|
371 | 366 | } |
372 | 367 | } |
373 | 368 | if (matched) continue; |
374 | | - let urlMatch = str.slice(i).match(/^https?:\/\/[^\s<]+/); |
375 | | - if (urlMatch) { |
376 | | - let url = urlMatch[0], trailing = ''; |
377 | | - let pMatch = url.match(/([.,;:!?。,、!?]+)$/); |
378 | | - if (pMatch) { url = url.substring(0, url.length - pMatch[0].length); trailing = pMatch[0]; } |
379 | | - tokens.push({ type: 'autolink', url }); |
380 | | - if (trailing) tokens.push({ type: 'text', val: trailing }); |
381 | | - i += urlMatch[0].length; continue; |
382 | | - } |
383 | 369 | tokens.push({ type: 'text', val: str[i] }); i++; |
384 | 370 | } |
385 | 371 | return tokens.reduce((a, c) => { |
386 | 372 | if (c.type === 'text' && a.length && a[a.length - 1].type === 'text') a[a.length - 1].val += c.val; |
387 | 373 | else a.push(c); return a; |
388 | 374 | }, []); |
389 | 375 | } |
| 376 | + |
390 | 377 | render(tokens) { |
391 | 378 | return tokens.map(t => { |
392 | 379 | if (t.type === 'text') return t.val; |
393 | | - if (t.type === 'img') return `<img src="${t.url}" alt="${t.alt}" class="card-img" loading="lazy" />`; |
394 | | - if (t.type === 'link') return `<a href="${t.url}" ${t.url.startsWith('#') ? '' : 'target="_blank" rel="noopener noreferrer"'} class="card-link">${this.render(t.content)}</a>`; |
395 | | - if (t.type === 'autolink') return `<a href="${t.url}" target="_blank" class="card-link" rel="noopener noreferrer">${t.url.replace(/^https?:\/\//, '').replace(/\/$/, '')}</a>`; |
396 | | - if (t.type === 'custom_regex') return t.rule.replacement.replace(/\$(\d)/g, (m, p1) => this.parse(t.match[parseInt(p1)] || '')); |
| 380 | + if (t.type === 'custom_regex') return t.rule.replacement.replace(/\$(\d)/g, (_, p1) => this.parse(t.match[parseInt(p1)] || '')).replace(/@(\d)/g, (_, p1) => t.match[parseInt(p1)] || ''); |
397 | 381 | if (t.type === 'custom_prefix') return t.rule.replacement.replace(/\$1/g, this.parse(t.content)); |
398 | 382 | return ''; |
399 | 383 | }).join(''); |
|
0 commit comments