JSdoc을 Markdown으로 변환하기

date
Nov 14, 2022
thumbnail
https://thumbnail.hyeok.dev/JSDoc%20to%20MD.png?theme=light&md=1&fontSize=100px&images=https%3A%2F%2Fthumbnail.hyeok.dev%2Fassets%2FblogIcon.svg
slug
JSdoc을 Markdown으로 변환하기
author
status
Published
tags
JavaScript
React
summary
최근 Toss의 오픈 소스 Slash가 공개되었는데 엄청나게 방대한 양의 문서들이 있었다. 이 많은 유틸들을 어떻게 문서화했는지 궁금해서 파일을 뜯어보았다. 기본적인 베이스는 Docusorous로 마크다운 사이트 빌드 프레임워크를 사용 중이었고 내부 글들은 JSDOC으로 관리되고 있었다.
type
Post
updatedAt
Jan 24, 2023 11:30 AM

서론

최근 Toss의 오픈 소스 Slash가 공개되었는데 엄청나게 방대한 양의 문서들이 있었다. 이 많은 유틸들을 어떻게 문서화했는지 궁금해서 파일을 뜯어보았다.
기본적인 베이스는 Docusorous로 마크다운 사이트 빌드 프레임워크를 사용 중이었고 내부 글들은 JSDOC으로 관리되고 있었다.
그럼 여기서 유추할 수 있는 것이 여러 파일들 중에 ts, tsx 파일들만 filter해서 JSDOC에 있는 텍스트를 읽어온 후 마크다운으로 변환한다고 볼 수 있다.
Docusorous는 공식 홈페이지에 문서화가 잘되어있으니 주요 포인트인 변환과정을 살펴보자.

본론

본격적으로 파일을 뜯어보자.
필요한 라이브러리는 node의 파일 시스템 fs, 특정 파일을 쉽게 filter해주는 fast-glob 마크다운을 생성해주는 documentation이 필요하다.
glob를 통해 파일들을 불러와보자.
const files = await glob('fileTest/**/*.{js,jsx}', {
    ignore: ['**/*.{spec,test,d,setup,stories,config}.{js,jsx}'],
});
fileTest 라는 폴더에 있는 js와 jsx를 모두 불러오는데 test 같이 문서화에 필요없는 파일들은 제외한다.
export function filterFilesByContent(files, condition) {
    return files.filter((file) => {
        const content = fs.readFileSync(file, 'utf-8');
        return condition(content);
    })
}
위에서 파일들을 전부 읽어오는데 condition에 filter 값을 걸어주면 된다.
const DOCS_IGNORE = '/** @gdsc-docs-ignore */';
const filteredContent = filterFilesByContent(files, content => !content.includes(DOCS_IGNORE));
예를 들어 이런 식이다.
export function pathsToBuildEntries(paths) {
    return paths.map(path => ({
        source: path,
        destination: `${destinationFilter('fileTest/docs',path)}.docs.md`,
    }));
}
다음으로 소스의 위치, 마크다운을 생성할 위치를 string으로 변경해준다. 나는 별도의 docs 폴더에 생성할 예정이라 filter함수로 경로를 변경해줬다.
const entries = pathsToBuildEntries(filteredContent);
const buildMarkdown = async (source) => {
  return build(source, {
        external: [],
        shallow: true,
        extension: 'js',
    }).then(formats.md)
}


const generateMarkdown = async (source, destination, markdown) => {
    const filename = getFilename(source, { withExtension: false });
    const title = `---\ntitle: ${filename}\n---\n`;
    const markdownWithTitle = `${title}${markdown}`;

    fs.writeFileSync(destination, markdownWithTitle);
};
다음으로 파일을 생성하는 작업인데 documentation의 build함수를 통해서 마크다운을 생성하고 fs.writeFileSync로 파일을 저장? 만들어준다.
export async function generateMarkdownFromEntries(entries) {
    await Promise.all(
        entries.map( async ({ source, destination }) => {
            const markdown = await buildMarkdown(source);
            await generateMarkdown(source, destination, markdown);
        })
    );
}
마지막으로 파일을 생성해준다. 파일 생성은 비동기작업이라 Promise.all로 감싸주었다.
notion image
notion image