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') }