UNPKG

@stackbit/utils

Version:
199 lines 8.31 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.stringifyDataByFilePath = exports.outputData = exports.parseMarkdownWithFrontMatter = exports.parseDataByFilePath = exports.parseFile = exports.getFirstExistingFile = exports.parseFirstExistingFile = exports.readDirRecursivelyWithExtensions = exports.readDirRecursively = void 0; const path_1 = __importDefault(require("path")); const fs_extra_1 = __importDefault(require("fs-extra")); const js_yaml_1 = __importDefault(require("js-yaml")); const toml_1 = __importDefault(require("@iarna/toml")); const lodash_1 = __importDefault(require("lodash")); const promise_utils_1 = require("./promise-utils"); async function readDirRecursively(dir, options) { const rootDir = lodash_1.default.get(options, 'rootDir', dir); const includeDirs = options?.includeDirs; const includeStats = options?.includeStats; const files = await fs_extra_1.default.readdir(dir); return (0, promise_utils_1.reducePromise)(files, async (result, file) => { const absFilePath = path_1.default.join(dir, file); const relFilePath = options?.absoluteFilePaths ? absFilePath : path_1.default.relative(rootDir, absFilePath); const stats = await fs_extra_1.default.stat(absFilePath); if (options?.filter && !options.filter(relFilePath, stats)) { return result; } const resultItem = includeStats ? { filePath: relFilePath, stats: stats } : relFilePath; if (stats.isDirectory()) { const childOptions = { ...options, rootDir: rootDir }; const childFiles = await readDirRecursively(absFilePath, childOptions); return includeDirs ? result.concat(resultItem, childFiles) : result.concat(childFiles); } else if (stats.isFile()) { return result.concat(resultItem); } else { return result; } }, []); } exports.readDirRecursively = readDirRecursively; async function readDirRecursivelyWithExtensions(dirPath, allowedExtensions) { return readDirRecursively(dirPath, { filter: (filePath, stats) => { // return true for all directories to read them recursively if (!stats.isFile()) { return true; } const extension = path_1.default.extname(filePath).substring(1).toLowerCase(); return allowedExtensions.includes(extension); } }); } exports.readDirRecursivelyWithExtensions = readDirRecursivelyWithExtensions; async function parseFirstExistingFile(fileNames, inputDir) { const filePath = await getFirstExistingFile(fileNames, inputDir); if (filePath) { return parseFile(filePath); } else { return null; } } exports.parseFirstExistingFile = parseFirstExistingFile; function getFirstExistingFile(fileNames, inputDir) { const filePaths = lodash_1.default.map(fileNames, (fileName) => path_1.default.resolve(inputDir, fileName)); return (0, promise_utils_1.findPromise)(filePaths, (filePath) => fs_extra_1.default.pathExists(filePath)); } exports.getFirstExistingFile = getFirstExistingFile; async function parseFile(filePath) { const data = await fs_extra_1.default.readFile(filePath, 'utf8'); return parseDataByFilePath(data, filePath); } exports.parseFile = parseFile; function parseDataByFilePath(string, filePath) { const extension = path_1.default.extname(filePath).substring(1); let data; switch (extension) { case 'yml': case 'yaml': string = string.replace(/\n---\s*$/, ''); data = js_yaml_1.default.load(string, { schema: js_yaml_1.default.JSON_SCHEMA }); break; case 'json': data = JSON.parse(string); break; case 'toml': data = toml_1.default.parse(string); break; case 'md': case 'mdx': case 'markdown': data = parseMarkdownWithFrontMatter(string); break; case 'js': case 'jsx': data = string; break; default: throw new Error(`parseDataByFilePath error, extension '${extension}' of file ${filePath} is not supported`); } return data; } exports.parseDataByFilePath = parseDataByFilePath; function parseMarkdownWithFrontMatter(string) { string = string.replace('\r\n', '\n'); let frontmatter = null; let markdown = string; const frontMatterTypes = [ { type: 'yaml', startDelimiter: '---\n', endDelimiter: '\n---', parse: (string) => js_yaml_1.default.load(string, { schema: js_yaml_1.default.JSON_SCHEMA }) }, { type: 'toml', startDelimiter: '+++\n', endDelimiter: '\n+++', parse: (string) => toml_1.default.parse(string) }, { type: 'jsonmd', startDelimiter: '---json\n', endDelimiter: '\n---', parse: (string) => JSON.parse(string) }, { type: 'json', startDelimiter: '{\n', endDelimiter: '\n}', parse: (string) => JSON.parse(`{${string}}`) } ]; lodash_1.default.forEach(frontMatterTypes, (fmType) => { if (string.startsWith(fmType.startDelimiter)) { const index = string.indexOf(fmType.endDelimiter); if (index !== -1) { // The end delimiter must be followed by EOF or by a new line (possibly preceded with spaces) // For example ("." used for spaces): // |--- // |title: Title // |---... // | // |Markdown Content // | // "index" points to the beginning of the second "---" // "endDelimEndIndex" points to the end of the second "---" // "afterEndDelim" is everything after the second "---" // "afterEndDelimMatch" is the matched "...\n" after the second "---" // frontmatter will be: {title: "Title"} // markdown will be "\nMarkdown Content\n" (the first \n after end delimiter is discarded) const endDelimEndIndex = index + fmType.endDelimiter.length; const afterEndDelim = string.substring(endDelimEndIndex); const afterEndDelimMatch = afterEndDelim.match(/^\s*?(\n|$)/); if (afterEndDelimMatch) { const data = string.substring(fmType.startDelimiter.length, index); const afterEndDelimString = afterEndDelimMatch[0]; frontmatter = fmType.parse(data); markdown = afterEndDelim.substring(afterEndDelimString.length); } } } }); return { frontmatter: frontmatter, markdown: markdown }; } exports.parseMarkdownWithFrontMatter = parseMarkdownWithFrontMatter; function outputData(filePath, data) { const res = stringifyDataByFilePath(data, filePath); return fs_extra_1.default.outputFile(filePath, res); } exports.outputData = outputData; function stringifyDataByFilePath(data, filePath) { const extension = path_1.default.extname(filePath).substring(1); let result; switch (extension) { case 'yml': case 'yaml': result = js_yaml_1.default.dump(data, { noRefs: true }); break; case 'json': result = JSON.stringify(data, null, 4); break; case 'toml': result = toml_1.default.stringify(data); break; case 'md': case 'mdx': case 'markdown': result = '---\n' + js_yaml_1.default.dump(data.frontmatter, { noRefs: true }) + '---\n' + data.markdown; break; default: throw new Error(`stringifyDataByFilePath error, extension '${extension}' of file ${filePath} is not supported`); } return result; } exports.stringifyDataByFilePath = stringifyDataByFilePath; //# sourceMappingURL=file-utils.js.map