search_awesome/validator.ts
2022-11-29 19:14:48 +09:00

136 lines
4.8 KiB
TypeScript

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<void> {
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);
}