dh_demo

DreamHanks demo project
git clone git://git.lair.cx/dh_demo
Log | Files | Refs | README

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 }