import { Command } from "cliffy"; import { DocParser, readDoc, writeDoc, Doc } from "./doc_load/load.ts"; import { expandGlob } from "https://deno.land/std@0.166.0/fs/mod.ts"; import ProgressBar from "https://deno.land/x/progress@v1.3.4/mod.ts"; function checkAndPrint(doc: Doc, another: Doc): [boolean, string[]] { const diffs = []; if (doc.name !== another.name) { diffs.push(`name: ${doc.name} => ${another.name}`); } if (doc.author !== another.author) { diffs.push(`author: ${doc.author} => ${another.author}`); } if (doc.star !== another.star) { diffs.push(`star: ${doc.star} => ${another.star}`); } if (doc.fork !== another.fork) { diffs.push(`fork: ${doc.fork} => ${another.fork}`); } if (doc.desc !== another.desc) { diffs.push(`desc: "${doc.desc}" => ${another.desc}`); } if (doc.url !== another.url) { diffs.push(`url: ${doc.url} => ${another.url}`); } if (doc.tags.length !== another.tags.length) { diffs.push(`tags: ${doc.tags} => ${another.tags}`); } else { doc.tags = doc.tags.sort(); another.tags = another.tags.sort(); for (let i = 0; i < doc.tags.length; i++) { if (doc.tags[i] !== another.tags[i]) { diffs.push(`tags: ${doc.tags} => ${another.tags}`); break; } } } if (doc.readme !== another.readme) { diffs.push(`readme: ${doc.readme} => ${another.readme}`); } if (doc.from_url !== another.from_url) { diffs.push(`from_url: ${doc.from_url} => ${another.from_url}`); } return [diffs.length === 0, diffs]; } async function validateDoc(path: string, parser: DocParser, fix?: boolean, log = console.log): Promise { try { const content = await Deno.readTextFile(path); const doc = parser.parseAlternative(content); if (fix) { await writeDoc(path, doc); } else { try { parser.parse(content); const another = parser.parse(content); const [isSame, errors] = checkAndPrint(doc, another); if (!isSame) { log(`File ${path} is not valid.`); for (const error of errors) { log("\t",error); } } } catch (e) { if ( e instanceof Error) { log(`File ${path} is not valid. error: ${e.name}`); } else { throw e; } } } } catch (error) { log(`File ${path} is not valid. error: ${error.name}`); throw error; } } if(import.meta.main){ const app = new Command() .name("validator") .version("0.1.0") .description("Validate and fix the doc files in the sample directory. glob is supported.") .option("-v, --verbose", "Enable verbose mode.") .option("-f, --fix", "Fix the doc files.") .option("-p, --progress", "Show progress.") .arguments("[pathes...:string]") .action(async (options, ...pathes) => { const { verbose, fix, progress } = options; const parser = new DocParser(); if(pathes.length === 0){ console.log("No pathes specified. Use --help to see the usage."); Deno.exit(1); } if (verbose) { console.log("Verbose mode enabled."); } if (progress) { console.log("Progress mode enabled."); const targets = (await Promise.all(pathes.map(async (path) => { const paths = []; for await (const entry of expandGlob(path)) { paths.push(entry.path); } return paths; }))).flat(); const bar = new ProgressBar({ total: targets.length, title: "Validating", }); let count = 0; for (const path of targets) { await validateDoc(path, parser, fix, verbose ? (...args)=>{ bar.console(args.join(" ")); } : () => { }); bar.render(++count); } bar.end(); } else { for (const path of pathes) { for await (const dir of expandGlob(path)) { if (verbose) { console.log(`Processing ${dir.path}`); } validateDoc(dir.path, parser, fix); } } } }); await app.parse(Deno.args); }