Preprocessor
마크다운 본문의 wikilink를 일반 마크다운 링크로 변환하고, 임베딩과 private 태그를 처리하는 전처리 모듈.
전처리는 4단계 파이프라인으로 동작한다:
임베딩 → private 태그 제거 → wikilink 변환 → 스마트 따옴표.
이 순서는 핵심 불변량이다 — 임베딩된 콘텐츠에 {prv} 태그가 있으면
임베딩이 먼저 처리된 후 private 태그가 제거되어야 한다.
또한 코드 블록 내부의 wikilink는 변환하지 않아야 한다.
module preprocess
-- 전처리 파이프라인의 단계
abstract sig Stage {
order: one Int
}
one sig Embed extends Stage {} { order = 1 }
one sig PrivateTag extends Stage {} { order = 2 }
one sig WikilinkReplace extends Stage {} { order = 3 }
one sig SmartQuote extends Stage {} { order = 4 }
-- 마크다운 토큰: 코드 블록 내부이거나 아니거나
sig Token {
inCodeBlock: one Bool,
processedBy: set Stage
}
-- 코드 블록 내부의 토큰은 wikilink 변환 대상이 아님
fact codeBlockProtection {
all t: Token | t.inCodeBlock = True implies
WikilinkReplace not in t.processedBy
}
-- 임베딩은 항상 private 태그보다 먼저 처리됨
-- (임베딩된 콘텐츠의 prv 태그가 올바르게 제거되려면)
fact embedBeforePrivate {
Embed.order < PrivateTag.order
}
-- private 태그는 wikilink보다 먼저 처리됨
-- (prv 태그 안의 wikilink가 불필요하게 변환되지 않으려면)
fact privateBeforeWikilink {
PrivateTag.order < WikilinkReplace.order
}
-- 코드 블록 보호가 위반되면: wikilink가 코드 안에서도 변환됨
assert codeBlockSafe {
no t: Token | t.inCodeBlock = True and WikilinkReplace in t.processedBy
}
-- 파이프라인 순서가 전순서(total order)임
assert pipelineIsTotalOrder {
all disj s1, s2: Stage | s1.order != s2.order
}
check codeBlockSafe for 5
check pipelineIsTotalOrder for 5 but 6 IntBool 시그니처는 Alloy 표준 관용구다:
abstract sig Bool {}
one sig True, False extends Bool {}Wikilink 변환
존재하는 페이지의 wikilink는 /<baseUrlPath>/PageName 형식의 링크로 변환된다.
존재하지 않는 페이지는 #private-link로 변환된다.
| md | baseUrlPath | pagenameSet | allMetaMap | expected |
|---|---|---|---|---|
See [[Foo]] and [[Missing]]. | pages | Set(["Foo"]) | Map() | See [Foo](/pages/Foo) and [Missing](#private-link). |
[[SomePage|표시 이름]] | pages | Set(["SomePage"]) | Map() | [표시 이름](/pages/SomePage) |
Private 태그 제거
{prv}...{/prv} 태그는 내용 전체가 제거된다.
{prv alt="대체텍스트"}...{/prv}는 대체 텍스트로 치환된다.
| md | baseUrlPath | pagenameSet | allMetaMap | expected |
|---|---|---|---|---|
Before {prv}secret{/prv} After | p | Set() | Map() | Before After |
Before {prv alt="공개"}secret{/prv} After | p | Set() | Map() | Before 공개 After |
스마트 따옴표 정규화
Curly 따옴표(U+2018 등)를 직선 따옴표로 변환한다.
| md | baseUrlPath | pagenameSet | allMetaMap | expected |
|---|---|---|---|---|
‘hello’ “world” | p | Set() | Map() | 'hello' "world" |