Files
sori.studio/lib/markdown-quote.js

115 lines
3.4 KiB
JavaScript

import { QUOTE_BACKGROUND_OPTIONS } from './markdown-callout.js'
import { hasQuoteMarker, stripQuoteMarker } from './markdown-live-edit.js'
/**
* 인용 마커 줄인지 확인한다.
* @param {string} line - 마크다운 행
* @returns {boolean} 인용 마커 줄 여부
*/
export const isQuoteMarkerLine = (line) => {
const trimmed = String(line ?? '').trim()
return trimmed === '>' || /^>\s/.test(trimmed)
}
/**
* 인용 마커를 제거한 본문을 반환한다.
* @param {string} line - 마크다운 행
* @returns {string} 인용 본문
*/
export const getQuoteLineBody = (line) => String(line ?? '').trim().replace(/^>\s?/, '')
/**
* 인용 옵션 줄을 파싱한다.
* @param {string} value - 인용 본문 줄
* @returns {{ quoteBackground: string }|null} 인용 옵션
*/
export const parseQuoteOptions = (value) => {
const raw = String(value ?? '').trim()
const bracketMatch = raw.match(/^\[!(.+)\]$/)
const braceMatch = raw.match(/^\{(.+)\}$/)
const optionSource = bracketMatch?.[1] || braceMatch?.[1] || ''
if (!optionSource) {
return null
}
const tokens = optionSource.trim().split(/\s+/)
let quoteBackground = ''
tokens.forEach((token) => {
const [key, rawOptionValue] = token.split('=')
const optionValue = String(rawOptionValue || '').trim()
if (key?.toLowerCase() === 'bg' && QUOTE_BACKGROUND_OPTIONS.includes(optionValue)) {
quoteBackground = optionValue
}
})
return quoteBackground ? { quoteBackground } : null
}
/**
* 인용 줄 마크다운을 만든다.
* @param {string} value - 편집 값
* @param {boolean} raw - 원문 모드 여부
* @returns {string} 마크다운 줄
*/
export const formatQuoteLine = (value, raw) => {
if (raw) {
if (!hasQuoteMarker(value)) {
return String(value ?? '').trim()
}
return value
}
const clean = stripQuoteMarker(value)
return clean ? `> ${clean}` : '> '
}
/**
* 인용 블록의 본문 시작 줄을 반환한다.
* @param {Object} block - 인용 블록
* @returns {number} 본문 시작 줄
*/
export const getQuoteContentStartLine = (block) => {
if (typeof block?.meta?.quoteContentStartLine === 'number') {
return block.meta.quoteContentStartLine
}
return block?.meta?.startLine ?? 0
}
/**
* 인용 블록을 편집 가능한 줄 단위로 분리한다.
* @param {Object} block - 인용 블록
* @returns {Array<{ text: string, sourceLine: number, sourceIndex: number }>} 줄 목록
*/
export const getQuoteLineEntries = (block) => {
const contentStartLine = getQuoteContentStartLine(block)
const endLine = block?.meta?.endLine ?? block?.meta?.startLine ?? contentStartLine
const lineCount = Math.max(1, endLine - contentStartLine + 1)
const fromText = String(block?.text ?? '').split('\n')
while (fromText.length < lineCount) {
fromText.push('')
}
return fromText.slice(0, lineCount).map((text, index) => ({
text,
sourceLine: contentStartLine + index,
sourceIndex: contentStartLine + index - (block?.meta?.startLine ?? contentStartLine)
}))
}
/**
* IME·브라우저 자동 목록 보정으로 생긴 인용 접두를 정리한다.
* @param {string} value - 인용 본문
* @returns {string} 정리된 본문
*/
export const normalizeQuoteEditableValue = (value) => {
return String(value ?? '').replace(/\r/g, '').split('\n').map((line) => {
return line.replace(/^>\.\s?/, '')
}).join('\n')
}