UNPKG

rdme

Version:

ReadMe's official CLI and GitHub Action.

67 lines (66 loc) 3.44 kB
import crypto from 'node:crypto'; import fs from 'node:fs'; import fsPromises from 'node:fs/promises'; import path from 'node:path'; import grayMatter from 'gray-matter'; import ora from 'ora'; import { oraOptions } from './logger.js'; import readdirRecursive from './readdirRecursive.js'; export const allowedMarkdownExtensions = ['.markdown', '.md', '.mdx']; /** * Returns the content, matter and slug of the specified Markdown or HTML file */ export function readPage( /** * path to the HTML/Markdown file * (file extension must end in `.html`, `.md`., or `.markdown`) */ filePath) { this.debug(`reading file ${filePath}`); const rawFileContents = fs.readFileSync(filePath, 'utf8'); // by default, grayMatter maintains a buggy cache with the page data, // so we pass an empty object as second argument to avoid it entirely // (so far we've seen this issue crop up in tests) const matter = grayMatter(rawFileContents, {}); const { content, data } = matter; this.debug(`frontmatter for ${filePath}: ${JSON.stringify(matter)}`); // Stripping the subdirectories and markdown extension from the filename and lowercasing to get the default slug. const slug = matter.data.slug || path.basename(filePath).replace(path.extname(filePath), '').toLowerCase(); const hash = crypto.createHash('sha1').update(rawFileContents).digest('hex'); return { content, data, filePath, hash, slug }; } /** * Takes a path input and finds pages. If the path is a directory, it will recursively search for files with the specified extensions. * If the path is a file, it will check if the file has a valid extension. * * Once the files are found, it reads each file and returns an array of page metadata objects (e.g., the parsed frontmatter data). */ export async function findPages(pathInput, allowedFileExtensions = allowedMarkdownExtensions) { let files; const stat = await fsPromises.stat(pathInput).catch(err => { if (err.code === 'ENOENT') { throw new Error("Oops! We couldn't locate a file or directory at the path you provided."); } throw err; }); if (stat.isDirectory()) { const includeHtml = allowedFileExtensions.includes('.html') ? 'and/or HTML ' : ''; const fileScanningSpinner = ora({ ...oraOptions() }).start(`🔍 Looking for Markdown ${includeHtml}files in the \`${pathInput}\` directory...`); // Filter out any files that don't match allowedFileExtensions files = readdirRecursive(pathInput).filter(file => allowedFileExtensions.includes(path.extname(file).toLowerCase())); if (!files.length) { fileScanningSpinner.fail(`${fileScanningSpinner.text} no files found.`); throw new Error(`The directory you provided (${pathInput}) doesn't contain any of the following file extensions: ${allowedFileExtensions.join(', ')}.`); } fileScanningSpinner.succeed(`${fileScanningSpinner.text} ${files.length} file(s) found!`); } else { const fileExtension = path.extname(pathInput).toLowerCase(); if (!allowedFileExtensions.includes(fileExtension)) { throw new Error(`Invalid file extension (${fileExtension}). Must be one of the following: ${allowedFileExtensions.join(', ')}`); } files = [pathInput]; } this.debug(`number of files: ${files.length}`); return files.map(file => readPage.call(this, file)); }