본문 바로가기

vscode-with-tistory

vscode extension 개발일기6: markdown-it모듈, 포스트 정보 파싱 테스트

블로그 포스팅 구현하기

블로그 포스팅을 구현하기 위해서는 아래의 4가지 조건을 모두 만족해야 한다. 해당 기능을 구현하기 위한 로그를 작성한다.

  1. 마크다운을 html로 변경
  2. 이미지 업로드
  3. 필요에 따라 첨부파일 업로드 수행
  4. 동일한 글이 중복되어 올라가는 것을 방지.

마크다운을 html로 변경

해당 기능을 구현하기 위해선 2가지 선택사항이 존재한다.

  • [x] 외부 모듈을 사용
  • [ ] 직접 구현

외부 모듈을 사용하면 마크다운을 html로 변경 가능한 범위를 파악해야 하고 외부 모듈에 의해 제공할 수 있는 기능이 제한된다.

직접 구현은 자유롭게 기능을 구현할 수 있으나 여러 사람에 의해 검증된 외부 모듈에 비해 항상 비슷한 상황에서 오류없이 동작한다는 보장이 없다. 또한 직접 개발하므로 개발 기간이 더 늘어냐게 된다.

필자의 선택은 외부 모듈을 이용하여 구현하는 것이 직접 구현하는 것보다 이미 검증된 모듈을 사용하는 것이 더 안전하고 개발 속도를 단축시킬 것이라고 생각하여 외부 모듈을 이용하기로 하였다.

외부모듈은 MIT라이센스를 가지고 VSC내에 내장되어 있는 Markdown Preview에서도 사용하는 markdown-it 모듈을 사용하기로 하였다. markdown-it모듈에는 다음과 같은 옵션들을 통해 마크다운을 html로 변경하는데 영향을 줄 수 있다. 영향들은 다음과 같다.

옵션선택1: html태그 허용 여부

마크다운으로 깃 블로그 사용하는 사람들 중에 html태그를 직접 삽입하는 사람들이 존재한다. html태그를 직접 삽입함으로서 여러 이점을 얻을 수 있다. 예를들면 html과 css를 설명하는 글을 작성할 때 직접 html과 css코드를 삽입하여 보여줄 수 있다. 하지만 필자는 해당 기능을 허용하지 않기로 하였다. 이유는 markdown-it모듈에서 해당 옵션은 권장되지 않기 때문이다. script같은 태그를 이용한 xss공격에 대해 필터링을 할 수 없다고 명시되어있기 때문이다. 굳이 VSC에서 이런 위험을 감소하여 사용할 필요는 없다고 생각하여 사용을 불허하였다

옵션 선택2: 유니코드 범위를 넘어가는 이모지 ⇒ 가능

깃 블로그를 운영해본 사람들은 이모지를 사용해봤거나 사용한 것을 본 적이 있을 것이다. vscode에서 마크다운을 이용하여 작성하는 사람들에게 이모지를 허용할 지에 대해 조사해보았다. markdown-it-emoji를 통해 이모지를 읽을 수 있다는 것을 확인했고 mocha로 테스트하여 가능한지 확인해보았다

markdown-it 테스트1. html태그 변환 여부

간단하게 # 를 h1태그로 변경하는지 확인하였다.

markdown-it

마크다운을 html로 변경하였을 때 값이 변경된다. 단 결과물에 개행이 포함된다. 이는 trim함수를 사용하면 해결할 수 있으니 변환은 가능하다고 볼 수 있다.

markdown-it 테스트2: emoji판단 여부

유니코드 범위를 넘는 emoji는 판단이 가능한지 테스트를 수행한다. 가장 잘쓰이는 emoji인 체크표시()를 인식하는지 확인하였다.

markdownEmoji

잘 통과되었다.


티스토리 블로그 포스팅 테스트

markdown-it모듈을 통해 html로 바꾸고 티스토리로 포스팅을 테스트 하였다. 이때 MIT라이센스를 가진 테스트 파일을 깃허브에서 찾아 사용하였다.

markdown-test-file/TEST.md at master · mxstbr/markdown-test-file

거의 대부분 적용이 되지만 다음과 같은 문제가 발생하였다.

  1. 코드블록이 강조되지 않은다.
  2. 블록 쿼터가 인용표시(킅따옴표)로 나온다.

1번의 문제같은 경우 티스토리에서 제공하는 플러그인인 Syntax Highlight를 사용하면 해결할 수 있다. 그러나 플러그인의 문제를 플러그인으로 해결하라 하는 것이 영 마음에 들지 않은다. 일단 해결방법이 존재하니 이는 보류하기로 하였다.

2번의 문제는 티스토리에서 제공하는 웹에서 마크다운을 사용할 때에도 같은 문제점이 발생된다. 티스토리에서 마크다운모드로 작성하고 기본모드로 들어가면 적절히 적용되지만 다시 마크다운 모드로 들어가 수정하지 않고 기본 모드로 돌아가면 문제가 발생한다. 해당 문제점이 발견되는 원인을 분석하니 data-ke-style가 추가되어서 발생되는 문제로 보인다. 이 문제점을 해결하면 1번문제의 해결방법이 사라진다. 계륵이기도 하다.

1번과 2번 문제점을 해결하는 방법이 있나 찾아보았는데 블로그 테마의 css를 변경하면 해결할 수 있다. 결국 외부 플러그인을 사용하는 것인데 vscode extension으로 해결할 수 없다는 것이 아쉽다.


티스토리 블로그 포스팅 테스트 markdown-it 모듈 테스트의 코드는 밑의 커밋로그에 작성되어 있다.

test markdown-it · dev-green-flamingo/vscode-with-tistory@9e03d88

포스트 정보 파싱

github로 블로그를 작성할 경우 파일의 상단에 다음과 같은 정보를 작성한다.

---
title:  "title"
date:   2021-09-17
post: true
tag:
- javascript
- 자바스크립트
comments: true
---

vscode-with-tistory 에서도 정보를 작성할 수 있도록 하여 사용자가 vscode로 게시글을 작성할 수 있도록 보조해야 해당 extension을 사용하는 의미가 있다고 생각한다.

단 github블로그의 옵션을 그대로 사용하기에는 티스토리에서 제공해주지 않은 조건이 있다. 그래서 다음과 같은 옵션으로 약간 수정하였다.

vscode-with-tistory 게시글 설정

---
title: text
date: yyyy-MM-dd hh:mm:ss
post: public | protect | private | true | false
tag:
- javascript
- 자바스크립트
comments: boolean
password: text
category: text
url: text
postId: int
---

옵션의 설명은 다음과 같다.

  • title: 포스트 제목
  • date(option): dateFormat형식으로 날짜와 시간을 작성하면 해당 날짜와 시간으로 예약글을 걸어준다. 값이 없거나 과거 시간으로 작성을 하면 현재 시간으로 변경된다. 단 게시글을 수정하여 재전송할 경우 미래시간으로 입력하지 않은 이상 게시글의 날짜는 최초로 포스팅한 날짜와 시간에서 바뀌지 않은다.
  • post(option): 게시글의 공개, 보호, 비밀글 여부를 public, protect, private로 지정할 수 있다. 기본값은 private를 가진다. 이때 true, false는 각각 public, private를 가리킨다. 해당 정보가 존재하는 이유는 깃허브 블로그로 운영할 때 작성한 파일들을 그대로 사용할 수 있도록 보조를 해주기 위함이다.
  • tag(option): 하위에 -(하이푼)으로 태그 이름들을 작성한다. 개행으로 태그를 분리한다.
  • comments(option): 댓글 작성의 여부를 작성한다. 기본값은 true이다.
  • password: 게시글에 패스워드를 지정한다.
  • url: 게시글의 url 경로를 숫자가 아닌 문자로 작성할 경우 url경로를 직접 지정할 수 있다.
  • cataegory: 게시글의 카테고리를 선택한다.
  • postId: 등록된 게시글의 ID값을 가진다. 등록된 게시글임을 파악한다. 이를 통해 해당 파일이 티스토리에 이미 올라와있는지, 아닌지를 판별한다.

옵션 파싱

작성된 md파일에서 포스트에 제목, 태그등의 정보들을 파싱이 필요하다.해당 정보들은 --- 을 이용하여 감싸져 있는 형태로 ---으로 시작하고 --- 로 종료한다.

이를 구현하는 방법 중 하나는 정규식을 사용하는 것이다. 파일을 모두 읽고 정규식으로 구하면 코드도 깔끔하고 구현 난이도고 용이할 것이다. 이유는 조건을 만족하는 정규식만 작성하면 풀 수 있기 때문이다.

그러나 이러한 방식은 파일을 모두 읽고 찾아야 하고 사용자가 입력해주는 데이터는 100%정확하다는 보장이 없기 때문에 사용하지 않았다. 만약 파일을 모두 읽고 정규식으로 탐색하였을 때 정규식의 결과가 없으면 파일을 읽는데 사용된 자원이 낭비되었기 때문이다.

그래서 파일을 모두 읽고 찾는 것이 아닌 파일을 읽는 과정에서 정보를 찾아내는 것이 1번의 파일 읽기로 정보와 마크다운 데이터를 분리할 수 있어서 더 효율적이라고 생각해서 파일을 1줄씩 읽으며 정보를 찾아내는 로직으로 작성하였다.

기능완성이 우선이니 테스트 유닛에서 최적화는 생각하지 않고 기능을 완성하기로 하였다.

정규식

기능을 구현하기 위해 2개의 정규식을 사용하였다. 1개는 정보의 key와 value를 받아오는 정규식이고 다른 하나는 tag정보를 받아오는 정규식이다. 2개의 정규식으로 나눈 이유는 파일을 한줄씩 읽기 때문이다. 정보는 대부분 key: value형태로 입력되어있다. 그러나 tag만은 예외이다. tag정보는 개행을 기준으로 나누어져있기 때문에 파일을 한줄씩 읽으면서 정보를 탐색하는 정규식을 사용할 수 없다고 생각했다.

정규식는 다음과 같다.

  • 정보를 찾아오는 정규식: /^(?<key>title|date|post|tag|comments|password|categoru|url|postId):\s*?(?<value>.+)?/u
  • 태그 정보를 받아오는 정규식: /(?<=^-\x20).*/u

정보를 찾아오는 정규식 같은 경우에는 파싱할 정보의 key들을 string으로 나열하는 것보다 array로 key들을 모아놓고 동적 정규식으로 작성하는 것이 더 편해서 해당 방식으로 구현하였다.

const kindOfOption = ["title","date","post","tag","comments","password",
"category","url","postId",];
const regexOption = new RegExp(
	`^(?<key>${kindOfOption.join("|")}):\s*?(?<value>.+)?`,
	"u"
);

parsing option test

기능 구현하면서 fs모듈에는 파일을 1줄씩 읽는 모듈이 없어서 readline모듈과 같이 사용해서 구현해야 하는 것 때문에 난감했다. 그래도 구현되어서 다행이다. 그러나 최적화를 생각하지 않고 작성한 코드라 코드를 읽는 것이 불편하다. 최적화하고싶은 코드이다. 이제 해당 코드를 extension에 옮기면서 최적화를 하여 적용시키면 구현 완료이다.


참고

Markdown Extension