UNPKG

@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
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