마크다운 fenced 메타 파싱 분리
This commit is contained in:
172
lib/markdown-fenced-meta.js
Normal file
172
lib/markdown-fenced-meta.js
Normal file
@@ -0,0 +1,172 @@
|
||||
/**
|
||||
* 닫힘 표식까지의 행 목록을 반환한다.
|
||||
* @param {Array<string>} lines - 전체 마크다운 행
|
||||
* @param {number} startIndex - 본문 시작 인덱스
|
||||
* @returns {{contentLines: Array<string>, endLine: number, nextIndex: number}} 블록 본문과 다음 인덱스
|
||||
*/
|
||||
export const collectFencedLines = (lines, startIndex) => {
|
||||
const contentLines = []
|
||||
let index = startIndex
|
||||
|
||||
while (index < lines.length && lines[index].trim() !== ':::') {
|
||||
contentLines.push(lines[index])
|
||||
index += 1
|
||||
}
|
||||
|
||||
return {
|
||||
contentLines,
|
||||
endLine: index < lines.length ? index : Math.max(lines.length - 1, startIndex - 1, 0),
|
||||
nextIndex: index < lines.length ? index + 1 : lines.length
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 북마크 fenced 블록 본문에서 URL·제목·설명·썸네일을 파싱한다.
|
||||
* @param {string} raw - fenced 내부 텍스트
|
||||
* @returns {{url: string, title: string, description: string, thumbnail: string}} 북마크 메타
|
||||
*/
|
||||
export const parseBookmarkMeta = (raw) => {
|
||||
const lines = raw.split('\n').map((line) => line.trim()).filter(Boolean)
|
||||
const meta = {
|
||||
url: '',
|
||||
title: '',
|
||||
description: '',
|
||||
thumbnail: ''
|
||||
}
|
||||
|
||||
for (const line of lines) {
|
||||
const kv = line.match(/^(\w+)=(.*)$/)
|
||||
|
||||
if (kv) {
|
||||
const key = kv[1].toLowerCase()
|
||||
const value = kv[2].trim()
|
||||
|
||||
if (key === 'url') {
|
||||
meta.url = value
|
||||
} else if (key === 'title') {
|
||||
meta.title = value
|
||||
} else if (key === 'description' || key === 'desc') {
|
||||
meta.description = value
|
||||
} else if (key === 'thumbnail' || key === 'image') {
|
||||
meta.thumbnail = value
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if (!meta.url && /^https?:\/\//i.test(line)) {
|
||||
meta.url = line
|
||||
continue
|
||||
}
|
||||
|
||||
if (meta.url && !meta.title) {
|
||||
meta.title = line
|
||||
continue
|
||||
}
|
||||
|
||||
if (meta.url && meta.title && !meta.description) {
|
||||
meta.description = line
|
||||
}
|
||||
}
|
||||
|
||||
return meta
|
||||
}
|
||||
|
||||
/**
|
||||
* 회원가입(CTA) fenced 블록 본문에서 표시 문구를 파싱한다.
|
||||
* @param {string} raw - fenced 내부 텍스트
|
||||
* @returns {{title: string, description: string, button: string, placeholder: string}} CTA 메타
|
||||
*/
|
||||
export const parseSignupMeta = (raw) => {
|
||||
const meta = {
|
||||
title: '뉴스레터에 가입하세요',
|
||||
description: '새 글이 올라오면 받아보실 수 있어요.',
|
||||
button: '구독하기',
|
||||
placeholder: 'you@example.com'
|
||||
}
|
||||
const lines = raw.split('\n').map((line) => line.trim()).filter(Boolean)
|
||||
|
||||
for (const line of lines) {
|
||||
const kv = line.match(/^(\w+)=(.*)$/)
|
||||
|
||||
if (!kv) {
|
||||
continue
|
||||
}
|
||||
|
||||
const key = kv[1].toLowerCase()
|
||||
const value = kv[2].trim()
|
||||
|
||||
if (key === 'title') {
|
||||
meta.title = value
|
||||
} else if (key === 'description' || key === 'desc') {
|
||||
meta.description = value
|
||||
} else if (key === 'button') {
|
||||
meta.button = value
|
||||
} else if (key === 'placeholder') {
|
||||
meta.placeholder = value
|
||||
}
|
||||
}
|
||||
|
||||
return meta
|
||||
}
|
||||
|
||||
/**
|
||||
* 미디어 fenced 블록 본문에서 URL과 표시 메타를 파싱한다.
|
||||
* @param {string} raw - fenced 내부 텍스트
|
||||
* @returns {{url: string, title: string, description: string, poster: string, caption: string, fileName: string, size: string}} 미디어 메타
|
||||
*/
|
||||
export const parseMediaMeta = (raw) => {
|
||||
const meta = {
|
||||
url: '',
|
||||
title: '',
|
||||
description: '',
|
||||
poster: '',
|
||||
caption: '',
|
||||
fileName: '',
|
||||
size: ''
|
||||
}
|
||||
const lines = raw.split('\n').map((line) => line.trim()).filter(Boolean)
|
||||
|
||||
for (const line of lines) {
|
||||
const kv = line.match(/^(\w+)=(.*)$/)
|
||||
|
||||
if (kv) {
|
||||
const key = kv[1].toLowerCase()
|
||||
const value = kv[2].trim()
|
||||
|
||||
if (key === 'url' || key === 'src') {
|
||||
meta.url = value
|
||||
} else if (key === 'title') {
|
||||
meta.title = value
|
||||
} else if (key === 'description' || key === 'desc') {
|
||||
meta.description = value
|
||||
} else if (key === 'poster' || key === 'thumbnail') {
|
||||
meta.poster = value
|
||||
} else if (key === 'caption') {
|
||||
meta.caption = value
|
||||
} else if (key === 'name' || key === 'filename' || key === 'file') {
|
||||
meta.fileName = value
|
||||
} else if (key === 'size') {
|
||||
meta.size = value
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if (!meta.url && (/^https?:\/\//i.test(line) || line.startsWith('/'))) {
|
||||
meta.url = line
|
||||
continue
|
||||
}
|
||||
|
||||
if (meta.url && !meta.title) {
|
||||
meta.title = line
|
||||
continue
|
||||
}
|
||||
|
||||
if (meta.url && meta.title && !meta.description) {
|
||||
meta.description = line
|
||||
}
|
||||
}
|
||||
|
||||
return meta
|
||||
}
|
||||
Reference in New Issue
Block a user