text: const file = require('./file');
  const sgf = require('staged-git-files');
  const path = require('path');
  const sortByHeading = require('./sortByHeading');
  const chineseFormat = require('./chineseFormat');
  const util = require('util');
  const exec = util.promisify(require('child_process').exec);
  
  /**
   * Processors are objects contains two methods:
   * `rules(list)`, and `handler(str)`
   * rules filters required file document object
   * and handler get document string and return formatted document
   */
  const processors = [sortByHeading, chineseFormat];
  
  // Helpers
  const loopSideBar = (children, type, lang, prefix) =>
      children
          .filter((e) => e !== '')
          .map((x) => ({
              path: path.resolve(__dirname, '..', prefix, `./${x}.md`),
              type,
              lang,
          }));
  const loopNav = (nav, lang) =>
      nav.flatMap((e) => {
          if (e.items) {
              return loopNav(e.items, lang);
          }
          if (e.link.endsWith('/')) {
              return {
                  path: path.resolve(__dirname, '..', e.link.slice(1), 'README.md'),
                  type: file.NAV_TYPE,
                  lang,
              };
          } else {
              return {
                  path: path.resolve(__dirname, '..', `${e.link.replace(/^\//, '')}.md`),
                  type: file.NAV_TYPE,
                  lang,
              };
          }
      });
  const loopType = (sidebar, lang, prefix) => loopSideBar(sidebar[0].children, file.GUIDE_TYPE, lang, prefix).concat(loopSideBar(sidebar[1].children, file.ROUTE_TYPE, lang, prefix));
  
  /**
   * Iterate config and build document object:
   * E.g.
   * {
          path: 'docs/en/other.md', <-- full path here
          type: 'route', <--- Defined in file.js
          lang: 'en' <-- Defined in file.js
      }
   */
  const buildFileList = async () => {
      const config = require(`../.vuepress/config`);
      let fileList = [];
      Object.keys(config.themeConfig.locales).forEach((key) => {
          const locale = config.themeConfig.locales[key];
          const key_path = key.slice(1);
          if (locale.hasOwnProperty('sidebar')) {
              fileList = fileList.concat(loopType(locale.sidebar[key], locale.lang, key_path));
          }
          if (locale.hasOwnProperty('nav')) {
              fileList = fileList.concat(loopNav(locale.nav, locale.lang));
          }
      });
  
      return fileList;
  };
  
  /**
   * Select files that only being modified
   * Same format as `buildFileList()`
   */
  const buildStagedList = async () => {
      const stagedFiles = await sgf();
      const stagedFileList = [];
      stagedFiles.forEach((e) => {
          if (e.filename.endsWith('.md')) {
              stagedFileList.push(e.filename);
          }
      });
      const fullFileList = await buildFileList();
      const result = [];
      stagedFileList.forEach((e) => {
          const f = fullFileList.find((x) => x.path.indexOf(e) !== -1);
          if (f) {
              result.push(f);
          }
      });
  
      return result;
  };
  
  /** Entry
   * Usage: node format.js --full/--staged
   */
  (async () => {
      // Mode
      const flag = process.argv[2] || '--full';
      let fileList = [];
      switch (flag) {
          case '--staged':
              fileList = await buildStagedList();
              break;
          case '--full':
          default:
              fileList = await buildFileList();
      }
      // console.log(fileList);
      // return
  
      const stagedFiles = await sgf();
      for (const processor of processors) {
          for (const e of processor.rules(fileList)) {
              let formatted = await file.readFile(e.path);
              formatted = await processor.handler(formatted);
              await file.writeFile(e.path, formatted);
              if (stagedFiles.find((x) => e.path.indexOf(x.filename) !== -1)) {
                  await exec(`git add ${e.path}`);
              }
          }
      }
  })();
  