parse_inline.ts (2123B)
1 import { InlineToken } from '@/lib/markup/token' 2 3 const inlinePatterns: Array<{ 4 marker: string 5 regex?: RegExp 6 token: (...args: string[]) => InlineToken 7 }> = [ 8 { 9 marker: '\n', 10 regex: /^\n+/, 11 token: () => ({ key: 'linebreak' }), 12 }, 13 { 14 marker: '**', 15 token: (text) => ({ key: 'bold', text }), 16 }, 17 { 18 marker: '//', 19 token: (text) => ({ key: 'italic', text }), 20 }, 21 { 22 marker: '__', 23 token: (text) => ({ key: 'underline', text }), 24 }, 25 { 26 marker: '~~', 27 token: (text) => ({ key: 'strikethrough', text }), 28 }, 29 { 30 marker: '`', 31 token: (text) => ({ key: 'code', text }), 32 }, 33 { 34 marker: '[[', 35 regex: /^\[\[([^\]|]+)(?:\|([^\]|]+))?]]/, 36 token: (path) => ({ key: 'link', path, text: path }), 37 }, 38 ] 39 40 !(function (): any { 41 let allMarkers: string[] = [] 42 43 // 각 패턴의 정규식 컴파일 44 for (const pattern of inlinePatterns) { 45 // 마커가 정규식 토큰으로 취급되지 않도록 이스케이프 문자 추가 46 const marker = pattern.marker.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') 47 48 // 일반 텍스트 패턴을 위한 마커 목록에 추가 49 allMarkers.push(marker) 50 51 // 정규식이 정의된 경우 패스 52 if (pattern.regex != null) { 53 continue 54 } 55 56 pattern.regex = new RegExp(`^${marker}([^${marker}]+)${marker}`) 57 } 58 59 // 일반 텍스트 패턴 추가 60 inlinePatterns.push({ 61 marker: '', 62 regex: new RegExp(`^(.+?)(?=${allMarkers.join('|')}|$)`), 63 token: (text) => ({ key: 'text', text }), 64 }) 65 })() 66 67 export function parseInline (src: string): InlineToken[] { 68 const tokens: InlineToken[] = [] 69 70 mainLoop: 71 while (src.length > 0) { 72 for (const pattern of inlinePatterns) { 73 const match = pattern.regex!.exec(src) 74 if (match == null) { 75 continue 76 } 77 78 // 토큰 생성 79 const token = pattern.token(...match.slice(1)) 80 81 // 토큰 목록에 추가 82 tokens.push(token) 83 84 // 소스에서 토큰 길이만큼 잘라냄 85 src = src.slice(match[0].length) 86 continue mainLoop 87 } 88 89 throw new Error(`unreachable`) 90 } 91 92 return tokens 93 }