puppeteer/utils/internal/job.ts

97 lines
2.1 KiB
TypeScript

import {Stats} from 'fs';
import {stat} from 'fs/promises';
import {glob} from 'glob';
import path from 'path';
interface JobContext {
name: string;
inputs: string[];
outputs: string[];
}
class JobBuilder {
#inputs: string[] = [];
#outputs: string[] = [];
#callback: (ctx: JobContext) => Promise<void>;
#name: string;
constructor(name: string, callback: (ctx: JobContext) => Promise<void>) {
this.#name = name;
this.#callback = callback;
}
inputs(inputs: string[]): JobBuilder {
this.#inputs = inputs.flatMap(value => {
value = path.resolve(__dirname, '..', '..', value);
const paths = glob.sync(value);
return paths.length ? paths : [value];
});
return this;
}
outputs(outputs: string[]): JobBuilder {
if (!this.#name) {
this.#name = outputs[0]!;
}
this.#outputs = outputs.map(value => {
return path.resolve(__dirname, '..', '..', value);
});
return this;
}
async build(): Promise<void> {
console.log(`Running job ${this.#name}...`);
let shouldRun = true;
const inputStats = await Promise.all(
this.#inputs.map(input => {
return stat(input);
})
);
let outputStats: Stats[];
try {
outputStats = await Promise.all(
this.#outputs.map(output => {
return stat(output);
})
);
if (
outputStats.reduce(reduceMaxTime, 0) >=
inputStats.reduce(reduceMinTime, Infinity)
) {
shouldRun = false;
}
} catch {}
if (shouldRun) {
this.#run();
}
}
#run(): Promise<void> {
return this.#callback({
name: this.#name,
inputs: this.#inputs,
outputs: this.#outputs,
});
}
}
export const job = (
name: string,
callback: (ctx: JobContext) => Promise<void>
): JobBuilder => {
return new JobBuilder(name, callback);
};
const reduceMaxTime = (time: number, stat: Stats) => {
return time < stat.mtimeMs ? stat.mtimeMs : time;
};
const reduceMinTime = (time: number, stat: Stats) => {
return time > stat.mtimeMs ? stat.mtimeMs : time;
};