fenced 블록 탐색 helper 통합

This commit is contained in:
2026-07-24 15:20:47 +09:00
parent 578ee889ee
commit 5f6d950721
7 changed files with 107 additions and 63 deletions

View File

@@ -48,7 +48,7 @@
| lib/markdown-iframe-embed.js | 게시물 본문 iframe 블록의 코드 판별과 안전 속성 추출 |
| lib/markdown-html-block.js | 게시물 본문 HTML 블록의 parser 기반 허용 태그·속성 sanitizer, 실행 URL·인라인 style 제거와 새 창 링크 rel 보정 |
| lib/markdown-callout.js | 인용 막대 색상·콜아웃 배경색 옵션, 선언 줄 파싱·직렬화 |
| lib/markdown-fenced-meta.js | 공개 Markdown fenced 블록 본문 수집과 북마크·회원가입·미디어 메타 파싱 |
| lib/markdown-fenced-meta.js | Markdown fenced 블록 시작·종료 줄 탐색, 본문 수집, 북마크·회원가입·미디어 메타 파싱 |
| lib/markdown-quote.js | 공개 Markdown 인용 줄 판별·옵션 파싱·라이브 편집 줄 변환 |
| lib/brand-color.js | 사이트 브랜드 컬러 기본값·hex 검증·정규화 |
| lib/markdown-image.js | 이미지 마크다운 직렬화·파싱, 단독 이미지 URL 판별 |
@@ -110,7 +110,7 @@
| tests/markdown-html-block.test.js | HTML sanitizer 단위 회귀 테스트 |
| tests/content-in-article-ad.test.js | 공개 본문 인아티클 광고 삽입 위치 계산 단위 회귀 테스트 |
| tests/markdown-block-context.test.js | 관리자 블록 설정 패널의 활성 블록 컨텍스트 단위 회귀 테스트 |
| tests/markdown-fenced-meta.test.js | Markdown fenced 블록 본문 수집과 메타 파싱 단위 회귀 테스트 |
| tests/markdown-fenced-meta.test.js | Markdown fenced 블록 시작·종료 줄 탐색, 본문 수집, 메타 파싱 단위 회귀 테스트 |
| tests/markdown-quote.test.js | Markdown 인용 옵션 파싱과 편집 줄 변환 단위 회귀 테스트 |
| tests/multipart-file-upload.test.js | multipart 스트리밍·제한 단위 회귀 테스트 |
| tests/csp-report.test.js | CSP URL 최소화·payload 형식 단위 회귀 테스트 |

View File

@@ -1,5 +1,11 @@
# 업데이트 이력
## v1.11.53
- 관리자 블록 컨텍스트의 fenced 블록 시작·종료 줄 탐색 helper를 `lib/markdown-fenced-meta.js`로 통합.
- fenced 블록 시작·종료 탐색과 닫힘 표식 경계 단위 테스트를 추가.
- `markdown-block-context`는 활성 블록 종류별 컨텍스트 조립에 집중하도록 정리.
## v1.11.52
- 관리자 블록 컨텍스트의 인용 줄 판별·옵션 파싱 중복을 `lib/markdown-quote.js` 공통 helper로 통합.

View File

@@ -3,64 +3,7 @@ import { CALLOUT_BACKGROUND_OPTIONS, parseCalloutOptions } from './markdown-call
import { parseCodeFenceLine } from './markdown-code-block.js'
import { parseToggleOpenerLine } from './markdown-toggle.js'
import { getQuoteLineBody, isQuoteMarkerLine, parseQuoteOptions } from './markdown-quote.js'
/**
* fenced 블록 시작 줄 인덱스를 찾는다.
* @param {string[]} lines - 본문 줄 목록
* @param {number} currentLine - 현재 줄
* @param {string} opener - 시작 토큰
* @returns {number} 시작 줄 또는 -1
*/
const findFencedBlockStart = (lines, currentLine, opener) => {
for (let index = currentLine; index >= 0; index -= 1) {
if ((lines[index] || '').trim() === opener) {
return index
}
if ((lines[index] || '').trim() === ':::') {
break
}
}
return -1
}
/**
* 조건에 맞는 fenced 블록 시작 줄 인덱스를 찾는다.
* @param {string[]} lines - 본문 줄 목록
* @param {number} currentLine - 현재 줄
* @param {(line: string) => boolean} predicate - 시작 줄 판별 함수
* @returns {number} 시작 줄 또는 -1
*/
const findFencedBlockStartBy = (lines, currentLine, predicate) => {
for (let index = currentLine; index >= 0; index -= 1) {
if (predicate((lines[index] || '').trim())) {
return index
}
if ((lines[index] || '').trim() === ':::') {
break
}
}
return -1
}
/**
* fenced 블록 종료 줄 인덱스를 찾는다.
* @param {string[]} lines - 본문 줄 목록
* @param {number} startLine - 시작 줄
* @returns {number} 종료 줄 또는 -1
*/
const findFencedBlockEnd = (lines, startLine) => {
for (let index = startLine + 1; index < lines.length; index += 1) {
if ((lines[index] || '').trim() === ':::') {
return index
}
}
return -1
}
import { findFencedBlockEnd, findFencedBlockStart, findFencedBlockStartBy } from './markdown-fenced-meta.js'
/**
* 단독 URL 줄인지 확인한다.

View File

@@ -1,3 +1,61 @@
/**
* fenced 블록 시작 줄 인덱스를 찾는다.
* @param {string[]} lines - 본문 줄 목록
* @param {number} currentLine - 현재 줄
* @param {string} opener - 시작 토큰
* @returns {number} 시작 줄 또는 -1
*/
export const findFencedBlockStart = (lines, currentLine, opener) => {
for (let index = currentLine; index >= 0; index -= 1) {
if ((lines[index] || '').trim() === opener) {
return index
}
if ((lines[index] || '').trim() === ':::') {
break
}
}
return -1
}
/**
* 조건에 맞는 fenced 블록 시작 줄 인덱스를 찾는다.
* @param {string[]} lines - 본문 줄 목록
* @param {number} currentLine - 현재 줄
* @param {(line: string) => boolean} predicate - 시작 줄 판별 함수
* @returns {number} 시작 줄 또는 -1
*/
export const findFencedBlockStartBy = (lines, currentLine, predicate) => {
for (let index = currentLine; index >= 0; index -= 1) {
if (predicate((lines[index] || '').trim())) {
return index
}
if ((lines[index] || '').trim() === ':::') {
break
}
}
return -1
}
/**
* fenced 블록 종료 줄 인덱스를 찾는다.
* @param {string[]} lines - 본문 줄 목록
* @param {number} startLine - 시작 줄
* @returns {number} 종료 줄 또는 -1
*/
export const findFencedBlockEnd = (lines, startLine) => {
for (let index = startLine + 1; index < lines.length; index += 1) {
if ((lines[index] || '').trim() === ':::') {
return index
}
}
return -1
}
/**
* 닫힘 표식까지의 행 목록을 반환한다.
* @param {Array<string>} lines - 전체 마크다운 행

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "sori.studio",
"version": "1.11.52",
"version": "1.11.53",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "sori.studio",
"version": "1.11.52",
"version": "1.11.53",
"hasInstallScript": true,
"dependencies": {
"@nuxtjs/tailwindcss": "^6.14.0",

View File

@@ -1,6 +1,6 @@
{
"name": "sori.studio",
"version": "1.11.52",
"version": "1.11.53",
"private": true,
"type": "module",
"imports": {

View File

@@ -2,11 +2,48 @@ import assert from 'node:assert/strict'
import test from 'node:test'
import {
collectFencedLines,
findFencedBlockEnd,
findFencedBlockStart,
findFencedBlockStartBy,
parseBookmarkMeta,
parseMediaMeta,
parseSignupMeta
} from '../lib/markdown-fenced-meta.js'
test('fenced 블록 시작과 종료 줄을 찾는다', () => {
const lines = [
'이전',
':::gallery',
'![a](/a.webp)',
':::',
'다음'
]
assert.equal(findFencedBlockStart(lines, 2, ':::gallery'), 1)
assert.equal(findFencedBlockEnd(lines, 1), 3)
})
test('닫힘 표식 너머의 fenced 블록 시작은 현재 블록으로 보지 않는다', () => {
const lines = [
':::gallery',
'![a](/a.webp)',
':::',
'본문'
]
assert.equal(findFencedBlockStart(lines, 3, ':::gallery'), -1)
})
test('조건 기반 fenced 블록 시작 줄을 찾는다', () => {
const lines = [
':::callout emoji=none bg=blue',
'본문',
':::'
]
assert.equal(findFencedBlockStartBy(lines, 1, (line) => line.startsWith(':::callout')), 0)
})
test('fenced 블록 닫힘 표식까지의 본문과 다음 줄을 수집한다', () => {
assert.deepEqual(collectFencedLines([
':::bookmark',