Files
formulation/scripts/lint-recipe-instructions.mjs
nicholasandnicholas 2a1e16ed30
Build & Deploy Formulation / Build & Push Image (push) Failing after 15s
Build & Deploy Formulation / deploy (push) Skipped
add core features (#14)
Reviewed-on: #14
Co-authored-by: Nicholas Ward <nicholaspward@outlook.com>
2026-08-18 18:22:34 -05:00

147 lines
4.1 KiB
JavaScript

#!/usr/bin/env node
import fs from "node:fs";
import path from "node:path";
import process from "node:process";
import YAML from "yaml";
const root = path.resolve(import.meta.dirname, "..");
const recipesDir = path.join(root, "culinary", "recipes");
const autofix = process.argv.includes("--fix") || process.argv.includes("--autofix");
const gerundMap = {
"mixing": "Mix",
"combining": "Combine",
"adding": "Add",
"whisking": "Whisk",
"stirring": "Stir",
"baking": "Bake",
"cooking": "Cook",
"heating": "Heat",
"pouring": "Pour",
"placing": "Place",
"cutting": "Cut",
"dicing": "Dice",
"chopping": "Chop",
"kneading": "Knead",
"rolling": "Roll",
"folding": "Fold",
"preheating": "Preheat",
"seasoning": "Season",
"simmering": "Simmer",
"boiling": "Boil",
"cooling": "Cool",
"refrigerating": "Refrigerate",
"freezing": "Freeze",
"storing": "Store",
"serving": "Serve",
"garnishing": "Garnish",
};
function standardizeInstruction(text) {
let clean = text.trim();
if (!clean) return clean;
// Check if it's an inline note: (Note: ...) or (...)
if (clean.startsWith("(") && clean.endsWith(")")) {
return clean;
}
// Check if it's a section heading: ends with colon
if (clean.endsWith(":")) {
// Capitalize first character
clean = clean.charAt(0).toUpperCase() + clean.slice(1);
return clean;
}
// Check for common gerund starts
const words = clean.split(/\s+/);
const firstWordLower = words[0].toLowerCase();
if (gerundMap[firstWordLower]) {
words[0] = gerundMap[firstWordLower];
clean = words.join(" ");
}
// Capitalize first letter
clean = clean.charAt(0).toUpperCase() + clean.slice(1);
// Replace trailing comma, semicolon, or dash with period
clean = clean.replace(/[,;\-\s]+$/, "");
// Ensure terminal punctuation if not ending with : or )
if (!clean.endsWith(".") && !clean.endsWith("!") && !clean.endsWith("?") && !clean.endsWith(":") && !clean.endsWith(")")) {
clean += ".";
}
return clean;
}
function lintRecipeFile(filePath) {
const content = fs.readFileSync(filePath, "utf8");
const data = YAML.parse(content);
if (!data || !Array.isArray(data.steps)) return { warnings: [], errors: [], changed: false };
const issues = [];
let changed = false;
const newSteps = data.steps.map((step, index) => {
const original = step.instruction ?? "";
const standardized = standardizeInstruction(original);
if (original !== standardized) {
issues.push({
stepOrder: step.order ?? index + 1,
original,
standardized,
});
if (autofix) {
changed = true;
return { ...step, instruction: standardized };
}
}
return step;
});
if (changed && autofix) {
data.steps = newSteps;
fs.writeFileSync(filePath, YAML.stringify(data, { indent: 2, lineWidth: 0 }), "utf8");
}
return { issues, changed };
}
function main() {
const files = fs.readdirSync(recipesDir).filter((f) => f.endsWith(".yaml")).sort();
let totalIssues = 0;
let filesModified = 0;
console.log(`Auditing ${files.length} recipe instruction files against Microsoft procedural guidelines...`);
for (const file of files) {
const filePath = path.join(recipesDir, file);
const { issues, changed } = lintRecipeFile(filePath);
if (issues.length > 0) {
totalIssues += issues.length;
if (changed) filesModified++;
console.log(`\n📄 ${file} (${issues.length} issue${issues.length > 1 ? "s" : ""}):`);
for (const issue of issues) {
console.log(` Step ${issue.stepOrder}:`);
console.log(` - Current: "${issue.original}"`);
console.log(` + Standard: "${issue.standardized}"`);
}
}
}
console.log("\n--------------------------------------------------");
if (autofix) {
console.log(`✅ Standardized ${totalIssues} instructions across ${filesModified} recipe files.`);
} else {
console.log(`Found ${totalIssues} non-standard instructions.`);
if (totalIssues > 0) {
console.log("Run with --fix to apply automated standardization.");
}
}
}
main();