files: scanFolder()

in scripts/link-checker.js [27:137]


            files: scanFolder(p),
            path: p,
            project: project.name,
          });
        });
      });
    },
  },
  {
    title: 'Scan all links',
    task: (ctx) => {
      ctx.externalLinks = []; // links to other sites
      ctx.internalLinks = []; // links to other Markdown files or anchor

      ctx.allDocuments.forEach((documents) => {
        documents.files.forEach((file) => {
          const scanResult = scanLinkInMDFile(file, documents.project);
          ctx.externalLinks.push(...scanResult.links);
          ctx.internalLinks.push(...scanResult.filteredLinks);
        });
      });

      console.log(`[Link Scanner] Scan result: ${ctx.externalLinks.length} external links, ${ctx.internalLinks.length} internal links`);
    },
  },
  {
    title: 'Start external link check',
    task: async (ctx) => {
      ctx.externalBrokenList = [];
      const externalLinkCheckPromises = [];
      ctx.externalLinks.forEach((link) => {
        externalLinkCheckPromises.push(linkValidate(link));
      });

      const result = await Promise.all(externalLinkCheckPromises);
      ctx.externalBrokenList.push(...result.filter((item) => item.status !== 200));
    },
  },
  {
    title: 'Start internal link check',
    task: (ctx) => {
      ctx.internalBrokenList = [];
      ctx.internalLinks.forEach((link) => {
        if (!fs.existsSync(link.url)) {
          ctx.internalBrokenList.push(link);
        }
      });
    },
  },
  {
    title: 'Write broken list to file',
    task: (ctx) => {
      fs.writeFileSync('./brokenLinks.json', JSON.stringify({
        external: ctx.externalBrokenList,
        internal: ctx.internalBrokenList,
      }));
    },
  },
]);

tasks.run()
  .then(() => {
    console.log('[Finish] Link Checker finished');
  })
  .catch((err) => {
    console.error(err);
    process.exit(1);
  });

function scanFolder(tarDir) {
  const filePaths = [];
  const files = fs.readdirSync(tarDir);
  files.forEach((file) => {
    const tarPath = path.join(tarDir, file);
    const stats = fs.statSync(tarPath);
    if (stats.isDirectory()) {
      filePaths.push(...scanFolder(tarPath));
    } else {
      filePaths.push(tarPath);
    }
  });

  return filePaths;
}

function scanLinkInMDFile(filePath, project) {
  const fileContent = fs.readFileSync(filePath, 'utf-8');
  const regex = /\[[\s\S]*?\]\([\s\S]*?\)/g;
  if (fileContent.match(regex)) {
    const arrayOfLinks = fileContent.match(regex);
    const links = arrayOfLinks.map((item) => {
      const textHrefDivide = item.split('](');
      const text = textHrefDivide[0].replace('[', '');
      const url = textHrefDivide[1].replace(')', '');
      return ({ url, text, file: filePath });
    });

    // filter out links to other Markdown files
    const filteredList = []; // local files
    const unfilteredList = links.filter((link) => { // web links
      let url = link.url.trim();
      if (url.startsWith('http://') || url.startsWith('https://')) {
        // eslint-disable-next-line no-param-reassign
        link.url = url;
        return true;
      }

      // url preprocess
      if (url.startsWith('#') || url.indexOf('#') > 0) { // such as "#abcd"
        const split = url.split('#').filter((item) => item !== '');
        if (split.length > 1) {