import { decode, encode, colors } from "./deps.ts";import { Progress } from "./progress.ts";import { importUrls } from "./search.ts";import { versioned, Versioned } from "./versioned.ts";
export async function update( filename: string, test: () => Promise<boolean>, options: UpdateOptions): Promise<UpdateResult[]> { const u = new Update(filename, test, options); return await u.update();}
export interface UpdateOptions { dryRun: boolean;}
export interface UpdateResult { initUrl: string; initVersion: string; newVersion?: string; success?: boolean;}
export class Update { private filename: string; private test: () => Promise<boolean>; private options: UpdateOptions; private progress: Progress;
constructor( filename: string, test: () => Promise<boolean>, options: UpdateOptions ) { this.filename = filename; this.test = test; this.options = options; this.progress = new Progress(1); }
async update(): Promise<UpdateResult[]> { const content: string = await this.content();
const urls: string[] = importUrls(content); this.progress.n = urls.length;
const results: UpdateResult[] = []; for (const [i, u] of urls.entries()) { this.progress.step = i; const v = versioned(u); if (v !== undefined) { results.push(await this.updateOne(v!)); } } return results; }
async updateOne( url: Versioned ): Promise<UpdateResult> { const versions = await url.all();
if (url.current() === versions[0]) { await this.progress.log(`Using latest: ${url.url}`); return { initUrl: url.url, initVersion: url.current() }; }
const newVersion = versions[0];
await this.progress.log(`Updating: ${url.url} -> ${newVersion}`); const fails: boolean = await this.updateIfTestPasses(url, newVersion); return { initUrl: url.url, initVersion: url.current(), newVersion, success: !fails }; }
async updateIfTestPasses( url: Versioned, newVersion: string ): Promise<boolean> { const newUrl = url.at(newVersion); await this.replace(url, newUrl);
const fails = await this.test(); if (fails || this.options.dryRun) { await this.replace(newUrl, url); } return fails; }
async content(): Promise<string> { return decode(await Deno.readFile(this.filename)); }
async replace(url: Versioned, newUrl: Versioned) { const content = await this.content(); const newContent = content.split(url.url).join(newUrl.url); await Deno.writeFile(this.filename, encode(newContent)); }}