content / scripts /front-matter_utils.js
AbdulElahGwaith's picture
Upload folder using huggingface_hub
780c9fe verified
import fs from "node:fs/promises";
import path from "node:path";
import YAML from "yaml";
import * as prettier from "prettier";
import AJV from "ajv";
import grayMatter from "gray-matter";
import addFormats from "ajv-formats";
import { betterAjvErrors } from "@apideck/better-ajv-errors";
export function getRelativePath(filePath) {
return path.relative(process.cwd(), filePath);
}
export function getAjvValidator(schema) {
const ajv = new AJV({ allowUnionTypes: true, allErrors: true });
addFormats.default(ajv);
return ajv.compile(schema);
}
function areAttributesInOrder(frontMatter, order) {
const attrs = Object.keys(frontMatter).filter((item) => order.includes(item));
const orderedAttrs = order.filter((item) => frontMatter[item]);
return orderedAttrs.every((item, index) => item === attrs[index]);
}
export async function checkFrontMatter(filePath, options) {
let content = await fs.readFile(filePath, "utf-8");
const document = grayMatter(content);
const fmObject = document.data;
const order = options.config["attribute-order"];
// validate and collect errors
const validator = options.validator;
const valid = validator(fmObject);
const validationErrors = betterAjvErrors({
schema: validator.schema,
data: fmObject,
errors: validator.errors,
});
const errors = [];
if (!valid) {
for (const error of validationErrors) {
let message = error.message.replace("{base}", "Front matter");
if (error.context.allowedValues) {
message += `:\n\t${error.context.allowedValues.join(", ")}`;
}
errors.push(message);
}
}
const isInOrder = areAttributesInOrder(fmObject, order);
let fixableError = null;
if (!options.fix && !isInOrder) {
fixableError = `${getRelativePath(
filePath,
)}\n\t Front matter attributes are not in required order: ${order.join(
"->",
)}`;
}
// if --fix option is true, then fix the order and prettify
if (options.fix) {
const fmOrdered = {};
for (const attr of options.config["attribute-order"]) {
const value = fmObject[attr];
if (value) {
if (attr === "status" && Array.isArray(value) && value.length) {
fmOrdered[attr] = value.sort();
} else if (attr === "browser-compat" || attr === "spec-urls") {
if (Array.isArray(value) && value.length === 1) {
fmOrdered[attr] = value[0];
} else {
fmOrdered[attr] = value;
}
} else {
fmOrdered[attr] = value;
}
}
}
let yml = YAML.stringify(fmOrdered, null, {
lineWidth: options.config.lineWidth,
});
yml = yml.replace(/[\s\n]+$/g, "");
yml = await prettier.format(yml, { parser: "yaml" });
content = `---\n${yml}---\n${document.content}`;
} else {
content = null;
}
return [
errors.length
? `Error: ${getRelativePath(filePath)}\n${errors.join("\n")}`
: null,
fixableError,
content,
];
}