@stackbit/utils
Version:
Stackbit utilities
199 lines • 8.31 kB
JavaScript
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
;