MasatoMakino/qiita-to-md

View on GitHub
src/MarkdownDownloader.ts

Summary

Maintainability
A
0 mins
Test Coverage
import fs from "fs";
import { createRequire } from "module";
import path from "path";
import { ImageDownloader, QiitaRequest } from "./index.js";
import { Options } from "./Options.js";

export class MarkdownDownloader {
  public static async download(options: Options) {
    const require = createRequire(import.meta.url);
    const tokenJson = require(options.token);
    QiitaRequest.token = tokenJson.token;

    const user = await QiitaRequest.getAuthenticatedUser();
    return await MarkdownDownloader.getItems(user.items_count, options);
  }

  /**
   * 記事リストを取得する。
   * @param itemsCount
   * @param options
   */
  static async getItems(itemsCount: number, options: Options) {
    const MAX_ITEM_PER_PAGE = 100;
    const pageNum = Math.ceil(itemsCount / MAX_ITEM_PER_PAGE);

    const items = [];
    for (let i = 1; i <= pageNum; i++) {
      const result = await QiitaRequest.listAuthenticatedUserItems({
        page: i.toString(),
        per_page: MAX_ITEM_PER_PAGE.toString(),
      });

      for (let item of result) {
        items.push(await this.reformatItem(item, options));
      }
    }
    return items;
  }

  /**
   * 記事保存用のディレクトリを作成する。
   */
  static makeDir(options: Options): void {
    //TODO 非同期化
    const option = {
      recursive: true,
    };
    fs.mkdirSync(path.resolve(options.contentsDir, options.jsonDir), option);
  }

  /**
   * 記事本文を整形する。
   * Qiitaサーバーに保存された画像はローカルに取得、リンクを書き換える。
   * @param item
   * @param options
   */
  static async makeBody(item, options: Options) {
    let body = await ImageDownloader.getMarkdownImages(
      item.body,
      options.staticDir,
      options.imgDir
    );
    body = await ImageDownloader.getHTMLImages(
      body,
      options.staticDir,
      options.imgDir
    );
    return body;
  }

  static async reformatItem(item, options: Options) {
    this.makeDir(options);
    if (item.body.includes("�")) {
      console.warn(
        `[Qiita-to-MD] 記事ID : ${item.id}, タイトル : ${item.title} でJSONのパースに失敗しています。出力されたファイルを確認してください。`
      );
    }
    const bodyContent = await this.makeBody(item, options);
    return {
      title: item.title,
      created_at: item.created_at,
      id: item.id,
      categories: MarkdownDownloader.getTagArray(item.tags),
      bodyContent,
    };
  }

  /**
   * タグの名称のみを配列化する。
   * @param tags
   */
  static getTagArray(tags) {
    return tags.map((val) => {
      return val.name;
    });
  }
}