@riddance/env
Version:
Too much code slows you down, creates risks, increases maintainability burdens, confuses AI. So let's commit less of it.
250 lines • 35.8 kB
JavaScript
import { spawn } from 'node:child_process';
import { readFile, rm, stat, writeFile } from 'node:fs/promises';
import { dirname, extname, join, resolve } from 'node:path';
import { formatted } from '../lib/formatter.js';
import { lint, makeCache } from '../lib/linter.js';
import { install } from '../lib/npm.js';
import { spelling } from '../lib/spelling.js';
import { isTest, isTestData, test, writeTestConfig } from '../lib/tester.js';
import { setupAgents } from './agents.js';
import { writeTSConfig } from './compiler.js';
import { dependantPackages } from './dependencies.js';
import { uninstall } from './env.js';
export function getSource(input) {
return input.filter(f => extname(f) === '.ts' && !f.endsWith('.d.ts') && !dirname(f).includes('node_modules'));
}
export async function load(path) {
return new Changes(path, await loadMyVersion(path), await loadTimestamps(path));
}
export class Changes {
#path;
#myVersion;
#timestamps;
#lintCache;
constructor(path, myVersion, timestamps) {
this.#path = path;
this.#myVersion = myVersion;
this.#timestamps = timestamps;
this.#lintCache = makeCache(path);
}
async preCompile(reporter, path) {
const dependencies = dependantPackages(path);
if (await this.shouldInstall()) {
if (!(await install(reporter, path))) {
await this.clearStages();
return false;
}
this.#timestamps.stages = {};
await this.stageComplete('install');
if (!(await this.#restartIfUpdated(reporter))) {
return undefined;
}
await Promise.all([
setupAgents(path, dependencies),
writeTestConfig(path, dependencies),
]);
}
await writeTSConfig(path, dependencies);
return ((await checkNodeVersion(reporter, path, 'package.json')) &&
(await checkNodeVersion(reporter, path, 'example/package.json')));
}
async postCompile(reporter, path, inputFiles, compileResult, abort) {
const testData = inputFiles.filter(isTestData);
const source = getSource(inputFiles);
const result = (await Promise.all([
compileResult,
this.#ifChanged('formatting', source, s => formatted(reporter, path, s, abort)),
this.#ifChanged('spelling', source, s => spelling(reporter, path, s, abort)),
this.#ifChanged('linting', source, s => lint(reporter, path, s, this.#lintCache)),
this.#ifChanged('tests', [...source, ...testData], async (s) => {
const outputFiles = await compileResult;
if (abort.aborted) {
return false;
}
if (!outputFiles) {
return false;
}
const tests = outputFiles.filter(f => isTest(f));
return await test(reporter, path, tests, s, abort);
}),
])).every(r => !!r);
await this.#setOutputs(await compileResult);
await this.#saveTimestamps();
return result;
}
async shouldInstall() {
const oldestStage = Object.values(this.#timestamps.stages)
.map(d => new Date(d).getTime())
.sort()
.at(0) ?? -1;
const latestPackage = (await Promise.all([
'package.json',
'package-lock.json',
'example/package.json',
'example/package-lock.json',
].map(async (f) => {
try {
return await stat(resolve(this.#path, f));
}
catch (e) {
if (isFileNotFound(e)) {
return { ctimeMs: 0 };
}
throw e;
}
})))
.map(s => s.ctimeMs)
.sort()
.at(-1) ?? 0;
return oldestStage < latestPackage;
}
async #restartIfUpdated(reporter) {
const myNewVersion = await loadMyVersion(this.#path);
if (!myNewVersion) {
await uninstall(reporter, this.#path);
return false;
}
if (this.#myVersion === myNewVersion) {
return true;
}
reporter.status('Restarting...');
const [cmd, ...argv] = process.argv;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const proc = spawn(cmd, argv, {
stdio: [process.stdin, process.stdout, process.stderr, 'pipe'],
});
// eslint-disable-next-line promise/param-names
await new Promise(exit => {
proc.addListener('exit', exit);
});
return false;
}
async stageComplete(stage) {
this.#timestamps.stages[stage] = new Date().toISOString();
await this.#saveTimestamps();
}
async clearStages() {
this.#timestamps.stages = {};
this.#lintCache = makeCache(this.#path);
await this.#saveTimestamps();
}
async #ifChanged(stage, source, fn) {
const { stages } = this.#timestamps;
if (stages[stage]) {
const lastSuccess = new Date(this.#timestamps.stages[stage] ?? 0).getTime();
const stats = await Promise.all(source.map(async (s) => {
try {
return await stat(s);
}
catch (e) {
if (isFileNotFound(e)) {
return { mtimeMs: 0 };
}
throw e;
}
}));
source = source
.map((s, ix) => ((stats[ix]?.mtimeMs ?? Number.MAX_VALUE) > lastSuccess ? s : ''))
.filter(s => !!s);
}
if (await fn(source)) {
stages[stage] = new Date().toISOString();
return true;
}
return false;
}
async #setOutputs(outputs) {
for (const old of this.#timestamps.outputs) {
if (!outputs?.includes(old)) {
try {
await rm(old);
}
catch (e) {
if (isFileNotFound(e)) {
continue;
}
throw e;
}
}
}
this.#timestamps.outputs = outputs ?? [];
}
async #saveTimestamps() {
await writeFile(join(this.#path, '.timestamps.json'), JSON.stringify(this.#timestamps, undefined, ' '));
}
}
async function loadTimestamps(path) {
try {
return JSON.parse(await readFile(join(path, '.timestamps.json'), 'utf-8'));
}
catch (e) {
if (isFileNotFound(e)) {
return {
outputs: [],
stages: {},
};
}
throw e;
}
}
async function loadMyVersion(path, reporter) {
try {
const { name, version, dependencies = {}, devDependencies = {}, } = JSON.parse(await readFile(join(path, 'package.json'), 'utf-8'));
if (name === '@riddance/env') {
return version;
}
const myVersion = devDependencies['@riddance/env'];
if (!myVersion) {
if (dependencies['@riddance/env']) {
reporter?.error('@riddance/env should be added to package.json as a devDependency, not a dependency.');
}
return;
}
return myVersion;
}
catch (e) {
if (isFileNotFound(e)) {
return;
}
throw e;
}
}
async function checkNodeVersion(reporter, path, packageJsonPath) {
try {
const { engines } = JSON.parse(await readFile(join(path, packageJsonPath), 'utf-8'));
if (!engines?.node) {
reporter?.error('Please specify node engine in package.json.');
return false;
}
const [exeMajor] = process.version.slice(1).split('.');
if (!exeMajor) {
throw new Error('Unexpected node version: ' + process.version);
}
if (!engineCompatible(engines.node, exeMajor)) {
reporter?.error(`Running different version of node than specified in package.json. Consider adding "node": ">=${exeMajor} to the engines property.`);
return false;
}
const myNodeVersion = '24';
if (!engineCompatible(engines.node, myNodeVersion)) {
reporter?.error(`Your version of @riddance/env expects to be running on node version ${myNodeVersion}. Consider adding "node": ">=${myNodeVersion} to the engines property.`);
return false;
}
return true;
}
catch (e) {
if (isFileNotFound(e)) {
return true;
}
throw e;
}
}
function engineCompatible(engineVersion, version) {
return (engineVersion === version ||
engineVersion === `>=${version}` ||
engineVersion.startsWith(`${version}.`) ||
engineVersion.startsWith(`>=${version}.`));
}
function isFileNotFound(e) {
return e.code === 'ENOENT';
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhbmdlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImNoYW5nZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLG9CQUFvQixDQUFBO0FBQzFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQTtBQUNoRSxPQUFPLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBQzNELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQTtBQUMvQyxPQUFPLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxNQUFNLGtCQUFrQixDQUFBO0FBQ2xELE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxlQUFlLENBQUE7QUFDdkMsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLG9CQUFvQixDQUFBO0FBQzdDLE9BQU8sRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxlQUFlLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQTtBQUM1RSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBQ3pDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxlQUFlLENBQUE7QUFDN0MsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDckQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLFVBQVUsQ0FBQTtBQUdwQyxNQUFNLFVBQVUsU0FBUyxDQUFDLEtBQWU7SUFDckMsT0FBTyxLQUFLLENBQUMsTUFBTSxDQUNmLENBQUMsQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxLQUFLLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFD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O0lBQzVELE9BQU8sQ0FDSCxhQUFhLEtBQUssT0FBTztRQUN6QixhQUFhLEtBQUssS0FBSyxPQUFPLEVBQUU7UUFDaEMsYUFBYSxDQUFDLFVBQVUsQ0FBQyxHQUFHLE9BQU8sR0FBRyxDQUFDO1FBQ3ZDLGFBQWEsQ0FBQyxVQUFVLENBQUMsS0FBSyxPQUFPLEdBQUcsQ0FBQyxDQUM1QyxDQUFBO0FBQ0wsQ0FBQztBQUVELFNBQVMsY0FBYyxDQUFDLENBQVU7SUFDOUIsT0FBUSxDQUF1QixDQUFDLElBQUksS0FBSyxRQUFRLENBQUE7QUFDckQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHNwYXduIH0gZnJvbSAnbm9kZTpjaGlsZF9wcm9jZXNzJ1xuaW1wb3J0IHsgcmVhZEZpbGUsIHJtLCBzdGF0LCB3cml0ZUZpbGUgfSBmcm9tICdub2RlOmZzL3Byb21pc2VzJ1xuaW1wb3J0IHsgZGlybmFtZSwgZXh0bmFtZSwgam9pbiwgcmVzb2x2ZSB9IGZyb20gJ25vZGU6cGF0aCdcbmltcG9ydCB7IGZvcm1hdHRlZCB9IGZyb20gJy4uL2xpYi9mb3JtYXR0ZXIuanMnXG5pbXBvcnQgeyBsaW50LCBtYWtlQ2FjaGUgfSBmcm9tICcuLi9saWIvbGludGVyLmpzJ1xuaW1wb3J0IHsgaW5zdGFsbCB9IGZyb20gJy4uL2xpYi9ucG0uanMnXG5pbXBvcnQgeyBzcGVsbGluZyB9IGZyb20gJy4uL2xpYi9zcGVsbGluZy5qcydcbmltcG9ydCB7IGlzVGVzdCwgaXNUZXN0RGF0YSwgdGVzdCwgd3JpdGVUZXN0Q29uZmlnIH0gZnJvbSAnLi4vbGliL3Rlc3Rlci5qcydcbmltcG9ydCB7IHNldHVwQWdlbnRzIH0gZnJvbSAnLi9hZ2VudHMuanMnXG5pbXBvcnQgeyB3cml0ZVRTQ29uZmlnIH0gZnJvbSAnLi9jb21waWxlci5qcydcbmltcG9ydCB7IGRlcGVuZGFudFBhY2thZ2VzIH0gZnJvbSAnLi9kZXBlbmRlbmNpZXMuanMnXG5pbXBvcnQgeyB1bmluc3RhbGwgfSBmcm9tICcuL2Vudi5qcydcbmltcG9ydCB7IFJlcG9ydGVyIH0gZnJvbSAnLi9yZXBvcnRlci5qcydcblxuZXhwb3J0IGZ1bmN0aW9uIGdldFNvdXJjZShpbnB1dDogc3RyaW5nW10pIHtcbiAgICByZXR1cm4gaW5wdXQuZmlsdGVyKFxuICAgICAgICBmID0+IGV4dG5hbWUoZikgPT09ICcudHMnICYmICFmLmVuZHNXaXRoKCcuZC50cycpICYmICFkaXJuYW1lKGYpLmluY2x1ZGVzKCdub2RlX21vZHVsZXMnKSxcbiAgICApXG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsb2FkKHBhdGg6IHN0cmluZykge1xuICAgIHJldHVybiBuZXcgQ2hhbmdlcyhwYXRoLCBhd2FpdCBsb2FkTXlWZXJzaW9uKHBhdGgpLCBhd2FpdCBsb2FkVGltZXN0YW1wcyhwYXRoKSlcbn1cblxuZXhwb3J0IGNsYXNzIENoYW5nZXMge1xuICAgIHJlYWRvbmx5ICNwYXRoXG4gICAgcmVhZG9ubHkgI215VmVyc2lvbjogc3RyaW5nIHwgdW5kZWZpbmVkXG4gICAgcmVhZG9ubHkgI3RpbWVzdGFtcHM6IFRpbWVzdGFtcHNcbiAgICAjbGludENhY2hlXG5cbiAgICBjb25zdHJ1Y3RvcihwYXRoOiBzdHJpbmcsIG15VmVyc2lvbjogc3RyaW5nIHwgdW5kZWZpbmVkLCB0aW1lc3RhbXBzOiBUaW1lc3RhbXBzKSB7XG4gICAgICAgIHRoaXMuI3BhdGggPSBwYXRoXG4gICAgICAgIHRoaXMuI215VmVyc2lvbiA9IG15VmVyc2lvblxuICAgICAgICB0aGlzLiN0aW1lc3RhbXBzID0gdGltZXN0YW1wc1xuICAgICAgICB0aGlzLiNsaW50Q2FjaGUgPSBtYWtlQ2FjaGUocGF0aClcbiAgICB9XG5cbiAgICBhc3luYyBwcmVDb21waWxlKHJlcG9ydGVyOiBSZXBvcnRlciwgcGF0aDogc3RyaW5nKSB7XG4gICAgICAgIGNvbnN0IGRlcGVuZGVuY2llcyA9IGRlcGVuZGFudFBhY2thZ2VzKHBhdGgpXG4gICAgICAgIGlmIChhd2FpdCB0aGlzLnNob3VsZEluc3RhbGwoKSkge1xuICAgICAgICAgICAgaWYgKCEoYXdhaXQgaW5zdGFsbChyZXBvcnRlciwgcGF0aCkpKSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5jbGVhclN0YWdlcygpXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLiN0aW1lc3RhbXBzLnN0YWdlcyA9IHt9XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnN0YWdlQ29tcGxldGUoJ2luc3RhbGwnKVxuICAgICAgICAgICAgaWYgKCEoYXdhaXQgdGhpcy4jcmVzdGFydElmVXBkYXRlZChyZXBvcnRlcikpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZFxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICAgICAgICAgIHNldHVwQWdlbnRzKHBhdGgsIGRlcGVuZGVuY2llcyksXG4gICAgICAgICAgICAgICAgd3JpdGVUZXN0Q29uZmlnKHBhdGgsIGRlcGVuZGVuY2llcyksXG4gICAgICAgICAgICBdKVxuICAgICAgICB9XG4gICAgICAgIGF3YWl0IHdyaXRlVFNDb25maWcocGF0aCwgZGVwZW5kZW5jaWVzKVxuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgKGF3YWl0IGNoZWNrTm9kZVZlcnNpb24ocmVwb3J0ZXIsIHBhdGgsICdwYWNrYWdlLmpzb24nKSkgJiZcbiAgICAgICAgICAgIChhd2FpdCBjaGVja05vZGVWZXJzaW9uKHJlcG9ydGVyLCBwYXRoLCAnZXhhbXBsZS9wYWNrYWdlLmpzb24nKSlcbiAgICAgICAgKVxuICAgIH1cblxuICAgIGFzeW5jIHBvc3RDb21waWxlKFxuICAgICAgICByZXBvcnRlcjogUmVwb3J0ZXIsXG4gICAgICAgIHBhdGg6IHN0cmluZyxcbiAgICAgICAgaW5wdXRGaWxlczogc3RyaW5nW10sXG4gICAgICAgIGNvbXBpbGVSZXN1bHQ6IFByb21pc2U8c3RyaW5nW10gfCB1bmRlZmluZWQ+LFxuICAgICAgICBhYm9ydDogQWJvcnRTaWduYWwsXG4gICAgKSB7XG4gICAgICAgIGNvbnN0IHRlc3REYXRhID0gaW5wdXRGaWxlcy5maWx0ZXIoaXNUZXN0RGF0YSlcbiAgICAgICAgY29uc3Qgc291cmNlID0gZ2V0U291cmNlKGlucHV0RmlsZXMpXG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IChcbiAgICAgICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgICAgICAgICBjb21waWxlUmVzdWx0LFxuICAgICAgICAgICAgICAgIHRoaXMuI2lmQ2hhbmdlZCgnZm9ybWF0dGluZycsIHNvdXJjZSwgcyA9PiBmb3JtYXR0ZWQocmVwb3J0ZXIsIHBhdGgsIHMsIGFib3J0KSksXG4gICAgICAgICAgICAgICAgdGhpcy4jaWZDaGFuZ2VkKCdzcGVsbGluZycsIHNvdXJjZSwgcyA9PiBzcGVsbGluZyhyZXBvcnRlciwgcGF0aCwgcywgYWJvcnQpKSxcbiAgICAgICAgICAgICAgICB0aGlzLiNpZkNoYW5nZWQoJ2xpbnRpbmcnLCBzb3VyY2UsIHMgPT4gbGludChyZXBvcnRlciwgcGF0aCwgcywgdGhpcy4jbGludENhY2hlKSksXG4gICAgICAgICAgICAgICAgdGhpcy4jaWZDaGFuZ2VkKCd0ZXN0cycsIFsuLi5zb3VyY2UsIC4uLnRlc3REYXRhXSwgYXN5bmMgcyA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG91dHB1dEZpbGVzID0gYXdhaXQgY29tcGlsZVJlc3VsdFxuICAgICAgICAgICAgICAgICAgICBpZiAoYWJvcnQuYWJvcnRlZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKCFvdXRwdXRGaWxlcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgY29uc3QgdGVzdHMgPSBvdXRwdXRGaWxlcy5maWx0ZXIoZiA9PiBpc1Rlc3QoZikpXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBhd2FpdCB0ZXN0KHJlcG9ydGVyLCBwYXRoLCB0ZXN0cywgcywgYWJvcnQpXG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICBdKVxuICAgICAgICApLmV2ZXJ5KHIgPT4gISFyKVxuICAgICAgICBhd2FpdCB0aGlzLiNzZXRPdXRwdXRzKGF3YWl0IGNvbXBpbGVSZXN1bHQpXG4gICAgICAgIGF3YWl0IHRoaXMuI3NhdmVUaW1lc3RhbXBzKClcbiAgICAgICAgcmV0dXJuIHJlc3VsdFxuICAgIH1cblxuICAgIGFzeW5jIHNob3VsZEluc3RhbGwoKSB7XG4gICAgICAgIGNvbnN0IG9sZGVzdFN0YWdlID1cbiAgICAgICAgICAgIE9iamVjdC52YWx1ZXModGhpcy4jdGltZXN0YW1wcy5zdGFnZXMpXG4gICAgICAgICAgICAgICAgLm1hcChkID0+IG5ldyBEYXRlKGQpLmdldFRpbWUoKSlcbiAgICAgICAgICAgICAgICAuc29ydCgpXG4gICAgICAgICAgICAgICAgLmF0KDApID8/IC0xXG4gICAgICAgIGNvbnN0IGxhdGVzdFBhY2thZ2UgPVxuICAgICAgICAgICAgKFxuICAgICAgICAgICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICAgICAgICAgICAgICBbXG4gICAgICAgICAgICAgICAgICAgICAgICAncGFja2FnZS5qc29uJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICdwYWNrYWdlLWxvY2suanNvbicsXG4gICAgICAgICAgICAgICAgICAgICAgICAnZXhhbXBsZS9wYWNrYWdlLmpzb24nLFxuICAgICAgICAgICAgICAgICAgICAgICAgJ2V4YW1wbGUvcGFja2FnZS1sb2NrLmpzb24nLFxuICAgICAgICAgICAgICAgICAgICBdLm1hcChhc3luYyBmID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGF3YWl0IHN0YXQocmVzb2x2ZSh0aGlzLiNwYXRoLCBmKSlcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoaXNGaWxlTm90Rm91bmQoZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHsgY3RpbWVNczogMCB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IGVcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgIC5tYXAocyA9PiBzLmN0aW1lTXMpXG4gICAgICAgICAgICAgICAgLnNvcnQoKVxuICAgICAgICAgICAgICAgIC5hdCgtMSkgPz8gMFxuICAgICAgICByZXR1cm4gb2xkZXN0U3RhZ2UgPCBsYXRlc3RQYWNrYWdlXG4gICAgfVxuXG4gICAgYXN5bmMgI3Jlc3RhcnRJZlVwZGF0ZWQocmVwb3J0ZXI6IFJlcG9ydGVyKSB7XG4gICAgICAgIGNvbnN0IG15TmV3VmVyc2lvbiA9IGF3YWl0IGxvYWRNeVZlcnNpb24odGhpcy4jcGF0aClcbiAgICAgICAgaWYgKCFteU5ld1ZlcnNpb24pIHtcbiAgICAgICAgICAgIGF3YWl0IHVuaW5zdGFsbChyZXBvcnRlciwgdGhpcy4jcGF0aClcbiAgICAgICAgICAgIHJldHVybiBmYWxzZVxuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLiNteVZlcnNpb24gPT09IG15TmV3VmVyc2lvbikge1xuICAgICAgICAgICAgcmV0dXJuIHRydWVcbiAgICAgICAgfVxuICAgICAgICByZXBvcnRlci5zdGF0dXMoJ1Jlc3RhcnRpbmcuLi4nKVxuICAgICAgICBjb25zdCBbY21kLCAuLi5hcmd2XSA9IHByb2Nlc3MuYXJndlxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLW5vbi1udWxsLWFzc2VydGlvblxuICAgICAgICBjb25zdCBwcm9jID0gc3Bhd24oY21kISwgYXJndiwge1xuICAgICAgICAgICAgc3RkaW86IFtwcm9jZXNzLnN0ZGluLCBwcm9jZXNzLnN0ZG91dCwgcHJvY2Vzcy5zdGRlcnIsICdwaXBlJ10sXG4gICAgICAgIH0pXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBwcm9taXNlL3BhcmFtLW5hbWVzXG4gICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKGV4aXQgPT4ge1xuICAgICAgICAgICAgcHJvYy5hZGRMaXN0ZW5lcignZXhpdCcsIGV4aXQpXG4gICAgICAgIH0pXG4gICAgICAgIHJldHVybiBmYWxzZVxuICAgIH1cblxuICAgIGFzeW5jIHN0YWdlQ29tcGxldGUoc3RhZ2U6IHN0cmluZykge1xuICAgICAgICB0aGlzLiN0aW1lc3RhbXBzLnN0YWdlc1tzdGFnZV0gPSBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKClcbiAgICAgICAgYXdhaXQgdGhpcy4jc2F2ZVRpbWVzdGFtcHMoKVxuICAgIH1cbiAgICBhc3luYyBjbGVhclN0YWdlcygpIHtcbiAgICAgICAgdGhpcy4jdGltZXN0YW1wcy5zdGFnZXMgPSB7fVxuICAgICAgICB0aGlzLiNsaW50Q2FjaGUgPSBtYWtlQ2FjaGUodGhpcy4jcGF0aClcbiAgICAgICAgYXdhaXQgdGhpcy4jc2F2ZVRpbWVzdGFtcHMoKVxuICAgIH1cblxuICAgIGFzeW5jICNpZkNoYW5nZWQoc3RhZ2U6IHN0cmluZywgc291cmNlOiBzdHJpbmdbXSwgZm46IChzcmM6IHN0cmluZ1tdKSA9PiBQcm9taXNlPGJvb2xlYW4+KSB7XG4gICAgICAgIGNvbnN0IHsgc3RhZ2VzIH0gPSB0aGlzLiN0aW1lc3RhbXBzXG4gICAgICAgIGlmIChzdGFnZXNbc3RhZ2VdKSB7XG4gICAgICAgICAgICBjb25zdCBsYXN0U3VjY2VzcyA9IG5ldyBEYXRlKHRoaXMuI3RpbWVzdGFtcHMuc3RhZ2VzW3N0YWdlXSA/PyAwKS5nZXRUaW1lKClcbiAgICAgICAgICAgIGNvbnN0IHN0YXRzID0gYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgICAgICAgICAgc291cmNlLm1hcChhc3luYyBzID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBhd2FpdCBzdGF0KHMpXG4gICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpc0ZpbGVOb3RGb3VuZChlKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB7IG10aW1lTXM6IDAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgZVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICApXG4gICAgICAgICAgICBzb3VyY2UgPSBzb3VyY2VcbiAgICAgICAgICAgICAgICAubWFwKChzLCBpeCkgPT4gKChzdGF0c1tpeF0/Lm10aW1lTXMgPz8gTnVtYmVyLk1BWF9WQUxVRSkgPiBsYXN0U3VjY2VzcyA/IHMgOiAnJykpXG4gICAgICAgICAgICAgICAgLmZpbHRlcihzID0+ICEhcylcbiAgICAgICAgfVxuICAgICAgICBpZiAoYXdhaXQgZm4oc291cmNlKSkge1xuICAgICAgICAgICAgc3RhZ2VzW3N0YWdlXSA9IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKVxuICAgICAgICAgICAgcmV0dXJuIHRydWVcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmFsc2VcbiAgICB9XG5cbiAgICBhc3luYyAjc2V0T3V0cHV0cyhvdXRwdXRzOiBzdHJpbmdbXSB8IHVuZGVmaW5lZCkge1xuICAgICAgICBmb3IgKGNvbnN0IG9sZCBvZiB0aGlzLiN0aW1lc3RhbXBzLm91dHB1dHMpIHtcbiAgICAgICAgICAgIGlmICghb3V0cHV0cz8uaW5jbHVkZXMob2xkKSkge1xuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IHJtKG9sZClcbiAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChpc0ZpbGVOb3RGb3VuZChlKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29udGludWVcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBlXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHRoaXMuI3RpbWVzdGFtcHMub3V0cHV0cyA9IG91dHB1dHMgPz8gW11cbiAgICB9XG5cbiAgICBhc3luYyAjc2F2ZVRpbWVzdGFtcHMoKSB7XG4gICAgICAgIGF3YWl0IHdyaXRlRmlsZShcbiAgICAgICAgICAgIGpvaW4odGhpcy4jcGF0aCwgJy50aW1lc3RhbXBzLmpzb24nKSxcbiAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KHRoaXMuI3RpbWVzdGFtcHMsIHVuZGVmaW5lZCwgJyAgJyksXG4gICAgICAgIClcbiAgICB9XG59XG5cbnR5cGUgVGltZXN0YW1wcyA9IHtcbiAgICBvdXRwdXRzOiBzdHJpbmdbXVxuICAgIHN0YWdlczogeyBbc3RhZ2U6IHN0cmluZ106IHN0cmluZyB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGxvYWRUaW1lc3RhbXBzKHBhdGg6IHN0cmluZykge1xuICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBKU09OLnBhcnNlKGF3YWl0IHJlYWRGaWxlKGpvaW4ocGF0aCwgJy50aW1lc3RhbXBzLmpzb24nKSwgJ3V0Zi04JykpIGFzIFRpbWVzdGFtcHNcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGlmIChpc0ZpbGVOb3RGb3VuZChlKSkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBvdXRwdXRzOiBbXSxcbiAgICAgICAgICAgICAgICBzdGFnZXM6IHt9LFxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHRocm93IGVcbiAgICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGxvYWRNeVZlcnNpb24ocGF0aDogc3RyaW5nLCByZXBvcnRlcj86IFJlcG9ydGVyKSB7XG4gICAgdHJ5IHtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgICAgbmFtZSxcbiAgICAgICAgICAgIHZlcnNpb24sXG4gICAgICAgICAgICBkZXBlbmRlbmNpZXMgPSB7fSxcbiAgICAgICAgICAgIGRldkRlcGVuZGVuY2llcyA9IHt9LFxuICAgICAgICB9ID0gSlNPTi5wYXJzZShhd2FpdCByZWFkRmlsZShqb2luKHBhdGgsICdwYWNrYWdlLmpzb24nKSwgJ3V0Zi04JykpIGFzIHtcbiAgICAgICAgICAgIG5hbWU6IHN0cmluZ1xuICAgICAgICAgICAgdmVyc2lvbjogc3RyaW5nXG4gICAgICAgICAgICBkZXBlbmRlbmNpZXM/OiB7IFtwOiBzdHJpbmddOiBzdHJpbmcgfVxuICAgICAgICAgICAgZGV2RGVwZW5kZW5jaWVzPzogeyBbcDogc3RyaW5nXTogc3RyaW5nIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAobmFtZSA9PT0gJ0ByaWRkYW5jZS9lbnYnKSB7XG4gICAgICAgICAgICByZXR1cm4gdmVyc2lvblxuICAgICAgICB9XG4gICAgICAgIGNvbnN0IG15VmVyc2lvbiA9IGRldkRlcGVuZGVuY2llc1snQHJpZGRhbmNlL2VudiddXG4gICAgICAgIGlmICghbXlWZXJzaW9uKSB7XG4gICAgICAgICAgICBpZiAoZGVwZW5kZW5jaWVzWydAcmlkZGFuY2UvZW52J10pIHtcbiAgICAgICAgICAgICAgICByZXBvcnRlcj8uZXJyb3IoXG4gICAgICAgICAgICAgICAgICAgICdAcmlkZGFuY2UvZW52IHNob3VsZCBiZSBhZGRlZCB0byBwYWNrYWdlLmpzb24gYXMgYSBkZXZEZXBlbmRlbmN5LCBub3QgYSBkZXBlbmRlbmN5LicsXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG15VmVyc2lvblxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgaWYgKGlzRmlsZU5vdEZvdW5kKGUpKSB7XG4gICAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuICAgICAgICB0aHJvdyBlXG4gICAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBjaGVja05vZGVWZXJzaW9uKFxuICAgIHJlcG9ydGVyOiBSZXBvcnRlciB8IHVuZGVmaW5lZCxcbiAgICBwYXRoOiBzdHJpbmcsXG4gICAgcGFja2FnZUpzb25QYXRoOiBzdHJpbmcsXG4pIHtcbiAgICB0cnkge1xuICAgICAgICBjb25zdCB7IGVuZ2luZXMgfSA9IEpTT04ucGFyc2UoYXdhaXQgcmVhZEZpbGUoam9pbihwYXRoLCBwYWNrYWdlSnNvblBhdGgpLCAndXRmLTgnKSkgYXMge1xuICAgICAgICAgICAgZW5naW5lcz86IHsgbm9kZT86IHN0cmluZyB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFlbmdpbmVzPy5ub2RlKSB7XG4gICAgICAgICAgICByZXBvcnRlcj8uZXJyb3IoJ1BsZWFzZSBzcGVjaWZ5IG5vZGUgZW5naW5lIGluIHBhY2thZ2UuanNvbi4nKVxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlXG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgW2V4ZU1ham9yXSA9IHByb2Nlc3MudmVyc2lvbi5zbGljZSgxKS5zcGxpdCgnLicpXG4gICAgICAgIGlmICghZXhlTWFqb3IpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignVW5leHBlY3RlZCBub2RlIHZlcnNpb246ICcgKyBwcm9jZXNzLnZlcnNpb24pXG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFlbmdpbmVDb21wYXRpYmxlKGVuZ2luZXMubm9kZSwgZXhlTWFqb3IpKSB7XG4gICAgICAgICAgICByZXBvcnRlcj8uZXJyb3IoXG4gICAgICAgICAgICAgICAgYFJ1bm5pbmcgZGlmZmVyZW50IHZlcnNpb24gb2Ygbm9kZSB0aGFuIHNwZWNpZmllZCBpbiBwYWNrYWdlLmpzb24uIENvbnNpZGVyIGFkZGluZyBcIm5vZGVcIjogXCI+PSR7ZXhlTWFqb3J9IHRvIHRoZSBlbmdpbmVzIHByb3BlcnR5LmAsXG4gICAgICAgICAgICApXG4gICAgICAgICAgICByZXR1cm4gZmFsc2VcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBteU5vZGVWZXJzaW9uID0gJzI0J1xuICAgICAgICBpZiAoIWVuZ2luZUNvbXBhdGlibGUoZW5naW5lcy5ub2RlLCBteU5vZGVWZXJzaW9uKSkge1xuICAgICAgICAgICAgcmVwb3J0ZXI/LmVycm9yKFxuICAgICAgICAgICAgICAgIGBZb3VyIHZlcnNpb24gb2YgQHJpZGRhbmNlL2VudiBleHBlY3RzIHRvIGJlIHJ1bm5pbmcgb24gbm9kZSB2ZXJzaW9uICR7bXlOb2RlVmVyc2lvbn0uIENvbnNpZGVyIGFkZGluZyBcIm5vZGVcIjogXCI+PSR7bXlOb2RlVmVyc2lvbn0gdG8gdGhlIGVuZ2luZXMgcHJvcGVydHkuYCxcbiAgICAgICAgICAgIClcbiAgICAgICAgICAgIHJldHVybiBmYWxzZVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0cnVlXG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBpZiAoaXNGaWxlTm90Rm91bmQoZSkpIHtcbiAgICAgICAgICAgIHJldHVybiB0cnVlXG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgZVxuICAgIH1cbn1cblxuZnVuY3Rpb24gZW5naW5lQ29tcGF0aWJsZShlbmdpbmVWZXJzaW9uOiBzdHJpbmcsIHZlcnNpb246IHN0cmluZykge1xuICAgIHJldHVybiAoXG4gICAgICAgIGVuZ2luZVZlcnNpb24gPT09IHZlcnNpb24gfHxcbiAgICAgICAgZW5naW5lVmVyc2lvbiA9PT0gYD49JHt2ZXJzaW9ufWAgfHxcbiAgICAgICAgZW5naW5lVmVyc2lvbi5zdGFydHNXaXRoKGAke3ZlcnNpb259LmApIHx8XG4gICAgICAgIGVuZ2luZVZlcnNpb24uc3RhcnRzV2l0aChgPj0ke3ZlcnNpb259LmApXG4gICAgKVxufVxuXG5mdW5jdGlvbiBpc0ZpbGVOb3RGb3VuZChlOiB1bmtub3duKSB7XG4gICAgcmV0dXJuIChlIGFzIHsgY29kZTogdW5rbm93biB9KS5jb2RlID09PSAnRU5PRU5UJ1xufVxuIl19