jsii-docgen
Version:
generates api docs for jsii modules
460 lines • 67.2 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.LANGUAGE_SPECIFIC = exports.Documentation = exports.SUPPORTED_ASSEMBLY_FEATURES = void 0;
exports.extractPackageName = extractPackageName;
const os = __importStar(require("os"));
const path = __importStar(require("path"));
const spec_1 = require("@jsii/spec");
const fs = __importStar(require("fs-extra"));
const reflect = __importStar(require("jsii-reflect"));
const jsii_rosetta_1 = require("jsii-rosetta");
const _npm_1 = require("./_npm");
const api_reference_1 = require("./api-reference");
const readme_1 = require("./readme");
const __1 = require("../..");
const json_1 = require("../render/json");
const markdown_doc_1 = require("../render/markdown-doc");
const markdown_render_1 = require("../render/markdown-render");
const schema_1 = require("../schema");
const assembly_1 = require("./assembly");
const csharp_1 = require("../transpile/csharp");
const go_1 = require("../transpile/go");
const java_1 = require("../transpile/java");
const python_1 = require("../transpile/python");
const transpile_1 = require("../transpile/transpile");
const typescript_1 = require("../transpile/typescript");
// https://github.com/aws/jsii/blob/v1.122.0/packages/jsii-reflect/lib/assembly.ts#L233
const NOT_FOUND_IN_ASSEMBLY_REGEX = /Type '(.*)\..*' not found in assembly (.*)$/;
// https://github.com/aws/jsii/blob/v1.122.0/packages/jsii-reflect/lib/type-system.ts#L252
const ASSEMBLY_NOT_FOUND_REGEX = /Assembly "(.*)" not found/;
exports.SUPPORTED_ASSEMBLY_FEATURES = ['intersection-types', 'class-covariant-overrides'];
/**
* Render documentation pages for a jsii library.
*/
class Documentation {
/**
* Create a `Documentation` object from a package installable by npm.
*
* Note that this method installs the target package to the local file-system. Make sure
* to call `Documentation.cleanup` once you are done rendering.
*
* @param target - The target to install. This can either be a local path or a registry identifier (e.g <name>@<version>)
* @param options - Additional options.
*
* @throws NoSpaceLeftOnDevice if the installation fails due to running out of disk space
* @throws NpmError if some `npm` command fails when preparing the working set
*/
static async forPackage(target, options = {}) {
var _a;
const workdir = await fs.mkdtemp(path.join(os.tmpdir(), path.sep));
const npm = new _npm_1.Npm(workdir);
if ((_a = options.verbose) !== null && _a !== void 0 ? _a : true) {
console.log(`Installing package ${target}`);
}
const name = await npm.install(target);
if (options._postInstall != null) {
await options._postInstall(workdir);
}
const docs = await Documentation.forProject(path.join(workdir, 'node_modules', name), { ...options, assembliesDir: workdir });
// we cannot delete this directory immediately since it is used during `render` calls.
// instead we register it so that callers can clean it up by calling the `cleanup` method.
docs.addCleanupDirectory(workdir);
return docs;
}
/**
* Create a `Documentation` object from a local directory containing a node project.
*
* @param root - The local directory path. Must contain a package.json file.
* @param options - Additional options.
*/
static async forProject(root, options = {}) {
var _a;
const manifestPath = path.join(root, 'package.json');
if (!(await fs.pathExists(manifestPath))) {
throw new Error(`Unable to locate ${manifestPath}`);
}
// normally the assemblies are located in subdirectories
// of the root package dir (i.e ./node_modules)
const assembliesDir = (_a = options === null || options === void 0 ? void 0 : options.assembliesDir) !== null && _a !== void 0 ? _a : root;
const { name } = JSON.parse(await fs.readFile(manifestPath, 'utf-8'));
return Documentation.forAssembly(name, assembliesDir);
}
/**
* Create a `Documentation` object for a specific assembly from a directory of assemblies.
*
* @param assemblyName - The assembly name.
* @param assembliesDir - The directory containing the assemblies that comprise the type-system.
*/
static async forAssembly(assemblyName, assembliesDir) {
return new Documentation(assemblyName, assembliesDir);
}
constructor(assemblyName, assembliesDir) {
this.assemblyName = assemblyName;
this.assembliesDir = assembliesDir;
this.cleanupDirectories = new Set();
this.assembliesCache = new Map();
}
/**
* List all submodules in the assembly.
*/
async listSubmodules() {
const tsAssembly = await this.createAssembly(undefined, { loose: true, validate: false });
return tsAssembly.allSubmodules;
}
async toIndexMarkdown(fileSuffix, options) {
const assembly = await this.createAssembly(undefined, { loose: true, validate: false });
const submodules = await this.listSubmodules();
const schema = (await this.toJson({
...options,
submodule: undefined,
allSubmodules: false,
})).content;
const ref = new markdown_doc_1.MarkdownDocument({ header: { title: 'API Reference' }, id: 'api-reference' });
if (schema.version !== schema_1.CURRENT_SCHEMA_VERSION) {
throw new Error(`Unexpected schema version: ${schema.version}`);
}
const renderer = new markdown_render_1.MarkdownRenderer({
language: options.language,
packageName: assembly.name,
packageVersion: assembly.version,
});
if (submodules.length) {
ref.section(renderer.visitSubmodules(submodules, fileSuffix));
}
if (schema.apiReference) {
ref.section(renderer.visitConstructs(schema.apiReference.constructs));
ref.section(renderer.visitStructs(schema.apiReference.structs));
ref.section(renderer.visitClasses(schema.apiReference.classes));
ref.section(renderer.visitInterfaces(schema.apiReference.interfaces));
ref.section(renderer.visitEnums(schema.apiReference.enums));
}
const documentation = new markdown_doc_1.MarkdownDocument();
documentation.section(ref);
return documentation;
}
/**
* Generate markdown.
*/
async toJson(options) {
var _a, _b, _c, _d, _e, _f, _g, _h;
const language = (_a = options.language) !== null && _a !== void 0 ? _a : transpile_1.Language.TYPESCRIPT;
const loose = (_b = options.loose) !== null && _b !== void 0 ? _b : true;
const validate = (_c = options.validate) !== null && _c !== void 0 ? _c : false;
const allSubmodules = (_d = options.allSubmodules) !== null && _d !== void 0 ? _d : false;
// Get the TS assembly first to check what languages are supported before calling rosetta
const tsAssembly = await this.createAssembly(undefined, { loose, validate });
const isSupported = language === transpile_1.Language.TYPESCRIPT || language.isValidConfiguration((_e = tsAssembly === null || tsAssembly === void 0 ? void 0 : tsAssembly.targets) === null || _e === void 0 ? void 0 : _e[language.targetName]);
this.assemblyFqn = `${tsAssembly.name}@${tsAssembly.version}`;
if (!isSupported) {
throw new __1.LanguageNotSupportedError(`Language ${language} is not supported for package ${this.assemblyFqn}`);
}
let submoduleStr = options.submodule;
if (allSubmodules && submoduleStr) {
throw new Error('Cannot call toJson with allSubmodules and a specific submodule both selected.');
}
const { assembly, transpile } = await this.languageSpecific(language, { loose, validate });
const targets = assembly.targets;
if (!targets) {
throw new Error(`Assembly ${this.assemblyFqn} does not have any targets defined`);
}
const submodule = submoduleStr ? this.findSubmodule(assembly, submoduleStr) : undefined;
let readme;
if ((_f = options === null || options === void 0 ? void 0 : options.readme) !== null && _f !== void 0 ? _f : false) {
readme = new readme_1.Readme(transpile, assembly, submodule).render();
}
let apiReference;
if ((_g = options === null || options === void 0 ? void 0 : options.apiReference) !== null && _g !== void 0 ? _g : true) {
try {
apiReference = new api_reference_1.ApiReference(transpile, assembly, submodule, allSubmodules);
}
catch (error) {
if (!(error instanceof Error)) {
throw error;
}
throw (_h = maybeCorruptedAssemblyError(error)) !== null && _h !== void 0 ? _h : error;
}
}
const contents = {
version: schema_1.CURRENT_SCHEMA_VERSION,
language: language.toString(),
metadata: {
packageName: assembly.name,
packageVersion: assembly.version,
submodule: (0, schema_1.submodulePath)(submodule),
},
readme: readme === null || readme === void 0 ? void 0 : readme.render(),
apiReference: apiReference === null || apiReference === void 0 ? void 0 : apiReference.toJson(),
};
return new json_1.Json(contents, {
spaces: options.spaces,
});
}
async toMarkdown(options) {
const json = (await this.toJson(options)).content;
return markdown_render_1.MarkdownRenderer.fromSchema(json, {
anchorFormatter: options.anchorFormatter,
linkFormatter: options.linkFormatter,
typeFormatter: options.typeFormatter,
header: options.header,
});
}
addCleanupDirectory(directory) {
this.cleanupDirectories.add(directory);
}
/**
* Removes any internal working directories.
*/
async cleanup() {
for (const dir of [...this.cleanupDirectories]) {
await fs.remove(dir);
this.cleanupDirectories.delete(dir);
}
}
async languageSpecific(lang, options) {
const { rosettaTarget, transpile } = exports.LANGUAGE_SPECIFIC[lang.toString()];
return { assembly: await this.createAssembly(rosettaTarget, options), transpile };
}
/**
* Lookup a submodule by a submodule name.
*
* The contract of this function is historically quite confused: the submodule
* name can be either an FQN (`asm.sub1.sub2`) or just a submodule name
* (`sub1` or `sub1.sub2`).
*
* This is sligthly complicated by ambiguity: `asm.asm.package` and
* `asm.package` can both exist, and which one do you mean when you say
* `asm.package`?
*
* We prefer an FQN match if possible (`asm.sub1.sub2`), but will accept a
* root-relative submodule name as well (`sub1.sub2`).
*/
findSubmodule(assembly, submodule) {
const fqnSubs = assembly.allSubmodules.filter((s) => s.fqn === submodule);
if (fqnSubs.length === 1) {
return fqnSubs[0];
}
// Fallback: assembly-relative name
const relSubs = assembly.allSubmodules.filter((s) => s.fqn === `${assembly.name}.${submodule}`);
if (relSubs.length === 1) {
console.error(`[WARNING] findSubmodule() is being called with a relative submodule name: '${submodule}'. Prefer the absolute name: '${assembly.name}.${submodule}'`);
return relSubs[0];
}
if (fqnSubs.length + relSubs.length === 0) {
throw new Error(`Submodule ${submodule} not found in assembly ${assembly.name}@${assembly.version} (neither as '${submodule}' nor as '${assembly.name}.${submodule})`);
}
// Almost impossible that this would be true
if (fqnSubs.length > 1) {
throw new Error(`Found multiple submodules with FQN: ${submodule} in assembly ${assembly.name}@${assembly.version}`);
}
throw new Error(`Found multiple submodules with relative name: ${submodule} in assembly ${assembly.name}@${assembly.version}`);
}
async createAssembly(language, options) {
const cacheKey = `lang:${language !== null && language !== void 0 ? language : 'ts'}.loose:${options.loose}.validate:${options.validate}`;
const cached = this.assembliesCache.get(cacheKey);
if (cached) {
return cached;
}
const created = await withTempDir(async (workdir) => {
// always better not to pollute an externally provided directory
await fs.copy(this.assembliesDir, workdir, {
// Ensure we don't try to copy socket files, as they can be found under .git when
// core.fsmonitor is enabled.
filter: async (src) => {
const stat = await fs.stat(src);
return stat.isFile() || stat.isDirectory();
},
});
const ts = new reflect.TypeSystem();
const assemblies = (0, assembly_1.discoverAssemblies)(this.assembliesDir);
for (let { name: discoveredName, path: dotJsii } of Object.values(assemblies)) {
// we only transliterate the top level assembly and not the entire type-system.
// note that the only reason to translate dependant assemblies is to show code examples
// for expanded python arguments - which we don't to right now anyway.
// we don't want to make any assumption of the directory structure, so this is the most
// robust way to detect the root assembly.
if (discoveredName === this.assemblyName) {
// only transliterate if we have received a target lang request
if (language) {
const packageDir = path.dirname(dotJsii);
try {
await (0, jsii_rosetta_1.transliterateAssembly)([packageDir], [language], { loose: options.loose, unknownSnippets: jsii_rosetta_1.UnknownSnippetMode.FAIL, outdir: workdir });
}
catch (e) {
throw new __1.TransliterationError(`Could not transliterate snippets in '${this.assemblyFqn}' to ${language}: ${e.message}`);
}
const langDotJsii = path.join(workdir, `${spec_1.SPEC_FILE_NAME}.${language}`);
await loadAssembly(langDotJsii, ts, assemblies, options);
}
else {
await loadAssembly(dotJsii, ts, assemblies, options);
}
}
}
return ts.findAssembly(this.assemblyName);
});
this.assembliesCache.set(cacheKey, created);
return created;
}
}
exports.Documentation = Documentation;
exports.LANGUAGE_SPECIFIC = {
[transpile_1.Language.PYTHON.toString()]: {
transpile: new python_1.PythonTranspile(),
rosettaTarget: jsii_rosetta_1.TargetLanguage.PYTHON,
},
[transpile_1.Language.TYPESCRIPT.toString()]: {
transpile: new typescript_1.TypeScriptTranspile(),
rosettaTarget: undefined, // no transpilation needed
},
[transpile_1.Language.JAVA.toString()]: {
transpile: new java_1.JavaTranspile(),
rosettaTarget: jsii_rosetta_1.TargetLanguage.JAVA,
},
[transpile_1.Language.CSHARP.toString()]: {
transpile: new csharp_1.CSharpTranspile(),
rosettaTarget: jsii_rosetta_1.TargetLanguage.CSHARP,
},
[transpile_1.Language.GO.toString()]: {
transpile: new go_1.GoTranspile(),
rosettaTarget: jsii_rosetta_1.TargetLanguage.GO,
},
};
/**
* Loads the specified assembly document into the provided type system, and
* recursively attempt to load the assembly's dependencies.
*
* @param dotJsii the assembly to be loaded.
* @param ts the type system in which the assembly is to be loaded.
* @param validate whether assemblies should be validated.
*/
async function loadAssembly(dotJsii, ts, availableAssemblies, { validate } = {}) {
var _a, _b, _c;
const loaded = await ts.load(dotJsii, { validate, supportedFeatures: exports.SUPPORTED_ASSEMBLY_FEATURES });
for (const [dep, version] of Object.entries((_a = loaded.spec.dependencies) !== null && _a !== void 0 ? _a : {})) {
if (ts.tryFindAssembly(dep) != null) {
// dependency already loaded... move on...
continue;
}
try {
// Use path from look up or try to resolve the dependencies relative to the dependent's package root.
const depPath = (_c = (_b = (0, assembly_1.bestAssemblyMatch)(availableAssemblies, `${dep}@${version}`)) === null || _b === void 0 ? void 0 : _b.path) !== null && _c !== void 0 ? _c : require.resolve(`${dep}/.jsii`, { paths: [path.dirname(dotJsii)] });
await loadAssembly(depPath, ts, availableAssemblies, { validate });
}
catch (error) {
// Silently ignore any resolution errors... We'll fail later if the dependency is
// ACTUALLY required, but it's okay to omit it if none of its types are actually exposed
// by the translated assembly's own API.
}
}
return loaded;
}
async function withTempDir(work) {
const workdir = await fs.mkdtemp(path.join(os.tmpdir(), path.sep));
const cwd = process.cwd();
try {
process.chdir(workdir);
// wait for the work to be completed before
// we cleanup the work environment.
return await work(workdir);
}
finally {
process.chdir(cwd);
await fs.remove(workdir);
}
}
function extractPackageName(spec) {
const firstAt = spec.indexOf('@');
if (firstAt === 0) {
const lastAt = spec.indexOf('@', firstAt + 1);
if (lastAt === -1) {
// @aws-cdk/aws-ecr
return spec;
}
else {
// @aws-cdk/aws-ecr@2.0.0
return spec.substring(0, lastAt);
}
}
if (firstAt > 0) {
// aws-cdk-lib@2.0.0
return spec.substring(0, firstAt);
}
// aws-cdk-lib
return spec;
}
/**
* Return a `CorruptedAssemblyError` if the error matches, undefined otherwise.
*
* Note that an 'not found in assembly` can be thrown in two cases:
*
* 1. Direct usage of `assembly.findType(fqn)`
*
* In this case the error could be caused by a wrong FQN being passed to the function. This is not considered
* a corrupted assembly since the caller might be passing an FQN from a different assembly.
*
* 2. Implicit usage of `assembly.findType(fqn)` by calling `.type` (e.g `parameter.type`)
*
* In this case the assembly we look in is always the same assembly the type itself comes from, and if it doesn't exist,
* then the assembly is considered corrupt.
*/
function maybeCorruptedAssemblyError(error) {
if (isAssemblyNotFound(error) || isNotFoundInAssmebly(error)) {
return new __1.CorruptedAssemblyError(error.message);
}
return;
}
function isNotFoundInAssmebly(error) {
const match = error.message.match(NOT_FOUND_IN_ASSEMBLY_REGEX);
if (!match) {
return false;
}
const searchedAssembly = match[2];
const typeAssembly = match[1];
if (searchedAssembly === typeAssembly
// take into account submodules (e.g aws-cdk-lib.aws_kms.IKeyRef)
|| typeAssembly.startsWith(searchedAssembly + '.')) {
return true;
}
return false;
}
function isAssemblyNotFound(error) {
const match = error.message.match(ASSEMBLY_NOT_FOUND_REGEX);
if (!match) {
return false;
}
return true;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZG9jdW1lbnRhdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9kb2NnZW4vdmlldy9kb2N1bWVudGF0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQTRnQkEsZ0RBcUJDO0FBamlCRCx1Q0FBeUI7QUFDekIsMkNBQTZCO0FBQzdCLHFDQUF5RDtBQUN6RCw2Q0FBK0I7QUFDL0Isc0RBQXdDO0FBQ3hDLCtDQUF5RjtBQUN6RixpQ0FBNkI7QUFDN0IsbURBQStDO0FBQy9DLHFDQUFrQztBQUNsQyw2QkFBZ0c7QUFDaEcseUNBQTZEO0FBQzdELHlEQUEwRDtBQUMxRCwrREFBd0Y7QUFDeEYsc0NBQTBFO0FBQzFFLHlDQUFtRjtBQUNuRixnREFBc0Q7QUFDdEQsd0NBQThDO0FBQzlDLDRDQUFrRDtBQUNsRCxnREFBc0Q7QUFDdEQsc0RBQTZEO0FBQzdELHdEQUE4RDtBQUU5RCx1RkFBdUY7QUFDdkYsTUFBTSwyQkFBMkIsR0FBRyw2Q0FBNkMsQ0FBQztBQUVsRiwwRkFBMEY7QUFDMUYsTUFBTSx3QkFBd0IsR0FBRywyQkFBMkIsQ0FBQztBQUVoRCxRQUFBLDJCQUEyQixHQUFrQixDQUFDLG9CQUFvQixFQUFFLDJCQUEyQixDQUFDLENBQUM7QUFpRzlHOztHQUVHO0FBQ0gsTUFBYSxhQUFhO0lBRXhCOzs7Ozs7Ozs7OztPQVdHO0lBQ0ksTUFBTSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsTUFBYyxFQUFFLFVBQTBDLEVBQUU7O1FBQ3pGLE1BQU0sT0FBTyxHQUFHLE1BQU0sRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUVuRSxNQUFNLEdBQUcsR0FBRyxJQUFJLFVBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUU3QixJQUFJ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TUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsMkJBQTJCLENBQUMsQ0FBQztJQUMvRCxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDWCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFDRCxNQUFNLGdCQUFnQixHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNsQyxNQUFNLFlBQVksR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFFOUIsSUFBSSxnQkFBZ0IsS0FBSyxZQUFZO1FBQ25DLGlFQUFpRTtXQUM5RCxZQUFZLENBQUMsVUFBVSxDQUFDLGdCQUFnQixHQUFHLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDckQsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBQ0QsT0FBTyxLQUFLLENBQUM7QUFFZixDQUFDO0FBRUQsU0FBUyxrQkFBa0IsQ0FBQyxLQUFZO0lBRXRDLE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLHdCQUF3QixDQUFDLENBQUM7SUFDNUQsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ1gsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBQ0QsT0FBTyxJQUFJLENBQUM7QUFFZCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgb3MgZnJvbSAnb3MnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7IEpzaWlGZWF0dXJlLCBTUEVDX0ZJTEVfTkFNRSB9IGZyb20gJ0Bqc2lpL3NwZWMnO1xuaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMtZXh0cmEnO1xuaW1wb3J0ICogYXMgcmVmbGVjdCBmcm9tICdqc2lpLXJlZmxlY3QnO1xuaW1wb3J0IHsgVGFyZ2V0TGFuZ3VhZ2UsIHRyYW5zbGl0ZXJhdGVBc3NlbWJseSwgVW5rbm93blNuaXBwZXRNb2RlIH0gZnJvbSAnanNpaS1yb3NldHRhJztcbmltcG9ydCB7IE5wbSB9IGZyb20gJy4vX25wbSc7XG5pbXBvcnQgeyBBcGlSZWZlcmVuY2UgfSBmcm9tICcuL2FwaS1yZWZlcmVuY2UnO1xuaW1wb3J0IHsgUmVhZG1lIH0gZnJvbSAnLi9yZWFkbWUnO1xuaW1wb3J0IHsgQ29ycnVwdGVkQXNzZW1ibHlFcnJvciwgTGFuZ3VhZ2VOb3RTdXBwb3J0ZWRFcnJvciwgVHJhbnNsaXRlcmF0aW9uRXJyb3IgfSBmcm9tICcuLi8uLic7XG5pbXBvcnQgeyBKc29uLCBKc29uRm9ybWF0dGluZ09wdGlvbnMgfSBmcm9tICcuLi9yZW5kZXIvanNvbic7XG5pbXBvcnQgeyBNYXJrZG93bkRvY3VtZW50IH0gZnJvbSAnLi4vcmVuZGVyL21hcmtkb3duLWRvYyc7XG5pbXBvcnQgeyBNYXJrZG93bkZvcm1hdHRpbmdPcHRpb25zLCBNYXJrZG93blJlbmRlcmVyIH0gZnJvbSAnLi4vcmVuZGVyL21hcmtkb3duLXJlbmRlcic7XG5pbXBvcnQgeyBTY2hlbWEsIENVUlJFTlRfU0NIRU1BX1ZFUlNJT04sIHN1Ym1vZHVsZVBhdGggfSBmcm9tICcuLi9zY2hlbWEnO1xuaW1wb3J0IHsgQXNzZW1ibHlMb29rdXAsIGJlc3RBc3NlbWJseU1hdGNoLCBkaXNjb3ZlckFzc2VtYmxpZXMgfSBmcm9tICcuL2Fzc2VtYmx5JztcbmltcG9ydCB7IENTaGFycFRyYW5zcGlsZSB9IGZyb20gJy4uL3RyYW5zcGlsZS9jc2hhcnAnO1xuaW1wb3J0IHsgR29UcmFuc3BpbGUgfSBmcm9tICcuLi90cmFuc3BpbGUvZ28nO1xuaW1wb3J0IHsgSmF2YVRyYW5zcGlsZSB9IGZyb20gJy4uL3RyYW5zcGlsZS9qYXZhJztcbmltcG9ydCB7IFB5dGhvblRyYW5zcGlsZSB9IGZyb20gJy4uL3RyYW5zcGlsZS9weXRob24nO1xuaW1wb3J0IHsgVHJhbnNwaWxlLCBMYW5ndWFnZSB9IGZyb20gJy4uL3RyYW5zcGlsZS90cmFuc3BpbGUnO1xuaW1wb3J0IHsgVHlwZVNjcmlwdFRyYW5zcGlsZSB9IGZyb20gJy4uL3RyYW5zcGlsZS90eXBlc2NyaXB0JztcblxuLy8gaHR0cHM6Ly9naXRodWIuY29tL2F3cy9qc2lpL2Jsb2IvdjEuMTIyLjAvcGFja2FnZXMvanNpaS1yZWZsZWN0L2xpYi9hc3NlbWJseS50cyNMMjMzXG5jb25zdCBOT1RfRk9VTkRfSU5fQVNTRU1CTFlfUkVHRVggPSAvVHlwZSAnKC4qKVxcLi4qJyBub3QgZm91bmQgaW4gYXNzZW1ibHkgKC4qKSQvO1xuXG4vLyBodHRwczovL2dpdGh1Yi5jb20vYXdzL2pzaWkvYmxvYi92MS4xMjIuMC9wYWNrYWdlcy9qc2lpLXJlZmxlY3QvbGliL3R5cGUtc3lzdGVtLnRzI0wyNTJcbmNvbnN0IEFTU0VNQkxZX05PVF9GT1VORF9SRUdFWCA9IC9Bc3NlbWJseSBcIiguKilcIiBub3QgZm91bmQvO1xuXG5leHBvcnQgY29uc3QgU1VQUE9SVEVEX0FTU0VNQkxZX0ZFQVRVUkVTOiBKc2lpRmVhdHVyZVtdID0gWydpbnRlcnNlY3Rpb24tdHlwZXMnLCAnY2xhc3MtY292YXJpYW50LW92ZXJyaWRlcyddO1xuXG4vKipcbiAqIE9wdGlvbnMgZm9yIHJlbmRlcmluZyBhIGBEb2N1bWVudGF0aW9uYCBvYmplY3QuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVuZGVyT3B0aW9ucyBleHRlbmRzIFRyYW5zbGl0ZXJhdGlvbk9wdGlvbnMge1xuICAvKipcbiAgICogV2hpY2ggbGFuZ3VhZ2UgdG8gZ2VuZXJhdGUgZG9jcyBmb3IuXG4gICAqL1xuICByZWFkb25seSBsYW5ndWFnZTogTGFuZ3VhZ2U7XG5cbiAgLyoqXG4gICAqIEluY2x1ZGUgYSBnZW5lcmF0ZWQgYXBpIHJlZmVyZW5jZSBpbiB0aGUgZG9jdW1lbnRhdGlvbi5cbiAgICpcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgYXBpUmVmZXJlbmNlPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogSW5jbHVkZSB0aGUgdXNlciBkZWZpbmVkIFJFQURNRS5tZCBpbiB0aGUgZG9jdW1lbnRhdGlvbi5cbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IHJlYWRtZT86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlIGRvY3VtZW50YXRpb24gb25seSBmb3IgYSBzcGVjaWZpYyBzdWJtb2R1bGUuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gRG9jdW1lbnRhdGlvbiBpcyBnZW5lcmF0ZWQgZm9yIHRoZSByb290IG1vZHVsZSBvbmx5LlxuICAgKi9cbiAgcmVhZG9ubHkgc3VibW9kdWxlPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZSBhIHNpbmdsZSBkb2N1bWVudCB3aXRoIEFQSXMgZnJvbSBhbGwgYXNzZW1ibHkgc3VibW9kdWxlc1xuICAgKiAoaW5jbHVkaW5nIHRoZSByb290KS5cbiAgICpcbiAgICogTm90ZTogb25seSB0aGUgcm9vdC1sZXZlbCBSRUFETUUgaXMgaW5jbHVkZWQuXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBhbGxTdWJtb2R1bGVzPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBUcmFuc2xpdGVyYXRpb25PcHRpb25zIHtcbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gaWdub3JlIG1pc3NpbmcgZml4dHVyZSBmaWxlcyB0aGF0IHdpbGwgcHJldmVudCB0cmFuc2xpdGVyYXRpbmdcbiAgICogc29tZSBjb2RlIHNuaXBwZXQgZXhhbXBsZXMuXG4gICAqXG4gICAqIEBkZWZhdWx0IHRydWVcbiAgICovXG4gIHJlYWRvbmx5IGxvb3NlPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogV2hldGhlciB0byB2YWxpZGF0ZSBqc2lpIGFzc2VtYmxpZXMgYWdhaW5zdCB0aGUganNpaSBzY2hlbWEgYmVmb3JlXG4gICAqIHVzaW5nIHRoZW0uXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSB2YWxpZGF0ZT86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTWFya2Rvd25SZW5kZXJPcHRpb25zIGV4dGVuZHMgUmVuZGVyT3B0aW9ucywgTWFya2Rvd25Gb3JtYXR0aW5nT3B0aW9ucyB7IH1cblxuZXhwb3J0IGludGVyZmFjZSBKc29uUmVuZGVyT3B0aW9ucyBleHRlbmRzIFJlbmRlck9wdGlvbnMsIEpzb25Gb3JtYXR0aW5nT3B0aW9ucyB7IH1cblxuLyoqXG4gKiBPcHRpb25zIGZvciBjcmVhdGluZyBhIGBEb2N1bWVudGF0aW9uYCBvYmplY3QgdXNpbmcgdGhlIGBmcm9tTG9jYWxQYWNrYWdlYCBmdW5jdGlvbi5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBGb3JMb2NhbFBhY2thZ2VEb2N1bWVudGF0aW9uT3B0aW9ucyB7XG5cbiAgLyoqXG4gICAqIEEgbG9jYWwgZGlyZWN0b3J5IGNvbnRhaW5pbmcganNpaSBhc3NlbWJseSBmaWxlcyB0aGF0IHdpbGxcbiAgICogY29tcHJpc2UgdGhlIHR5cGUtc3lzdGVtLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIHRoZSByb290IHBhY2thZ2UgZGlyZWN0b3J5IHdpbGwgYmUgdXNlZC5cbiAgICovXG4gIHJlYWRvbmx5IGFzc2VtYmxpZXNEaXI/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRm9yUGFja2FnZURvY3VtZW50YXRpb25PcHRpb25zIHtcbiAgLyoqXG4gICAqIFdoZXRoZXIgdmVyYm9zZSBsb2dnaW5nIGlzIHRvIGJlIHBlcmZvcm1lZC5cbiAgICpcbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgdmVyYm9zZT86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEEgZnVuY3Rpb24gdG8gcnVuIGFmdGVyIHJ1bm5pbmcgYG5wbSBpbnN0YWxsYCBmb3IgdGhlIHRhcmdldCBwYWNrYWdlLiBUaGlzXG4gICAqIGV4aXN0cyBvbmx5IGZvciB0ZXN0aW5nIHB1cnBvc2VzIGFuZCBzaG91bGQgbm90IGJlIHVzZWQgYnkgY29uc3VtZXJzIG9mXG4gICAqIHRoaXMgbW9kdWxlLlxuICAgKlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHJlYWRvbmx5IF9wb3N0SW5zdGFsbD86IChkaXI6IHN0cmluZykgPT4gUHJvbWlzZTx2b2lkPjtcbn1cblxuLyoqXG4gKiBSZW5kZXIgZG9jdW1lbnRhdGlvbiBwYWdlcyBmb3IgYSBqc2lpIGxpYnJhcnkuXG4gKi9cbmV4cG9ydCBjbGFzcyBEb2N1bWVudGF0aW9uIHtcblxuICAvKipcbiAgICogQ3JlYXRlIGEgYERvY3VtZW50YXRpb25gIG9iamVjdCBmcm9tIGEgcGFja2FnZSBpbnN0YWxsYWJsZSBieSBucG0uXG4gICAqXG4gICAqIE5vdGUgdGhhdCB0aGlzIG1ldGhvZCBpbnN0YWxscyB0aGUgdGFyZ2V0IHBhY2thZ2UgdG8gdGhlIGxvY2FsIGZpbGUtc3lzdGVtLiBNYWtlIHN1cmVcbiAgICogdG8gY2FsbCBgRG9jdW1lbnRhdGlvbi5jbGVhbnVwYCBvbmNlIHlvdSBhcmUgZG9uZSByZW5kZXJpbmcuXG4gICAqXG4gICAqIEBwYXJhbSB0YXJnZXQgLSBUaGUgdGFyZ2V0IHRvIGluc3RhbGwuIFRoaXMgY2FuIGVpdGhlciBiZSBhIGxvY2FsIHBhdGggb3IgYSByZWdpc3RyeSBpZGVudGlmaWVyIChlLmcgPG5hbWU+QDx2ZXJzaW9uPilcbiAgICogQHBhcmFtIG9wdGlvbnMgLSBBZGRpdGlvbmFsIG9wdGlvbnMuXG4gICAqXG4gICAqIEB0aHJvd3MgTm9TcGFjZUxlZnRPbkRldmljZSBpZiB0aGUgaW5zdGFsbGF0aW9uIGZhaWxzIGR1ZSB0byBydW5uaW5nIG91dCBvZiBkaXNrIHNwYWNlXG4gICAqIEB0aHJvd3MgTnBtRXJyb3IgaWYgc29tZSBgbnBtYCBjb21tYW5kIGZhaWxzIHdoZW4gcHJlcGFyaW5nIHRoZSB3b3JraW5nIHNldFxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBhc3luYyBmb3JQYWNrYWdlKHRhcmdldDogc3RyaW5nLCBvcHRpb25zOiBGb3JQYWNrYWdlRG9jdW1lbnRhdGlvbk9wdGlvbnMgPSB7fSk6IFByb21pc2U8RG9jdW1lbnRhdGlvbj4ge1xuICAgIGNvbnN0IHdvcmtkaXIgPSBhd2FpdCBmcy5ta2R0ZW1wKHBhdGguam9pbihvcy50bXBkaXIoKSwgcGF0aC5zZXApKTtcblxuICAgIGNvbnN0IG5wbSA9IG5ldyBOcG0od29ya2Rpcik7XG5cbiAgICBpZiAob3B0aW9ucy52ZXJib3NlID8/IHRydWUpIHtcbiAgICAgIGNvbnNvbGUubG9nKGBJbnN0YWxsaW5nIHBhY2thZ2UgJHt0YXJnZXR9YCk7XG4gICAgfVxuXG4gICAgY29uc3QgbmFtZSA9IGF3YWl0IG5wbS5pbnN0YWxsKHRhcmdldCk7XG5cbiAgICBpZiAob3B0aW9ucy5fcG9zdEluc3RhbGwgIT0gbnVsbCkge1xuICAgICAgYXdhaXQgb3B0aW9ucy5fcG9zdEluc3RhbGwod29ya2Rpcik7XG4gICAgfVxuXG4gICAgY29uc3QgZG9jcyA9IGF3YWl0IERvY3VtZW50YXRpb24uZm9yUHJvamVjdChwYXRoLmpvaW4od29ya2RpciwgJ25vZGVfbW9kdWxlcycsIG5hbWUpLCB7IC4uLm9wdGlvbnMsIGFzc2VtYmxpZXNEaXI6IHdvcmtkaXIgfSk7XG5cbiAgICAvLyB3ZSBjYW5ub3QgZGVsZXRlIHRoaXMgZGlyZWN0b3J5IGltbWVkaWF0ZWx5IHNpbmNlIGl0IGlzIHVzZWQgZHVyaW5nIGByZW5kZXJgIGNhbGxzLlxuICAgIC8vIGluc3RlYWQgd2UgcmVnaXN0ZXIgaXQgc28gdGhhdCBjYWxsZXJzIGNhbiBjbGVhbiBpdCB1cCBieSBjYWxsaW5nIHRoZSBgY2xlYW51cGAgbWV0aG9kLlxuICAgIGRvY3MuYWRkQ2xlYW51cERpcmVjdG9yeSh3b3JrZGlyKTtcblxuICAgIHJldHVybiBkb2NzO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhIGBEb2N1bWVudGF0aW9uYCBvYmplY3QgZnJvbSBhIGxvY2FsIGRpcmVjdG9yeSBjb250YWluaW5nIGEgbm9kZSBwcm9qZWN0LlxuICAgKlxuICAgKiBAcGFyYW0gcm9vdCAtIFRoZSBsb2NhbCBkaXJlY3RvcnkgcGF0aC4gTXVzdCBjb250YWluIGEgcGFja2FnZS5qc29uIGZpbGUuXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gQWRkaXRpb25hbCBvcHRpb25zLlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBhc3luYyBmb3JQcm9qZWN0KHJvb3Q6IHN0cmluZywgb3B0aW9uczogRm9yTG9jYWxQYWNrYWdlRG9jdW1lbnRhdGlvbk9wdGlvbnMgPSB7fSk6IFByb21pc2U8RG9jdW1lbnRhdGlvbj4ge1xuICAgIGNvbnN0IG1hbmlmZXN0UGF0aCA9IHBhdGguam9pbihyb290LCAncGFja2FnZS5qc29uJyk7XG4gICAgaWYgKCEoYXdhaXQgZnMucGF0aEV4aXN0cyhtYW5pZmVzdFBhdGgpKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmFibGUgdG8gbG9jYXRlICR7bWFuaWZlc3RQYXRofWApO1xuICAgIH1cblxuICAgIC8vIG5vcm1hbGx5IHRoZSBhc3NlbWJsaWVzIGFyZSBsb2NhdGVkIGluIHN1YmRpcmVjdG9yaWVzXG4gICAgLy8gb2YgdGhlIHJvb3QgcGFja2FnZSBkaXIgKGkuZSAuL25vZGVfbW9kdWxlcylcbiAgICBjb25zdCBhc3NlbWJsaWVzRGlyID0gb3B0aW9ucz8uYXNzZW1ibGllc0RpciA/PyByb290O1xuXG4gICAgY29uc3QgeyBuYW1lIH0gPSBKU09OLnBhcnNlKGF3YWl0IGZzLnJlYWRGaWxlKG1hbmlmZXN0UGF0aCwgJ3V0Zi04JykpO1xuICAgIHJldHVybiBEb2N1bWVudGF0aW9uLmZvckFzc2VtYmx5KG5hbWUsIGFzc2VtYmxpZXNEaXIpO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhIGBEb2N1bWVudGF0aW9uYCBvYmplY3QgZm9yIGEgc3BlY2lmaWMgYXNzZW1ibHkgZnJvbSBhIGRpcmVjdG9yeSBvZiBhc3NlbWJsaWVzLlxuICAgKlxuICAgKiBAcGFyYW0gYXNzZW1ibHlOYW1lIC0gVGhlIGFzc2VtYmx5IG5hbWUuXG4gICAqIEBwYXJhbSBhc3NlbWJsaWVzRGlyIC0gVGhlIGRpcmVjdG9yeSBjb250YWluaW5nIHRoZSBhc3NlbWJsaWVzIHRoYXQgY29tcHJpc2UgdGhlIHR5cGUtc3lzdGVtLlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBhc3luYyBmb3JBc3NlbWJseShhc3NlbWJseU5hbWU6IHN0cmluZywgYXNzZW1ibGllc0Rpcjogc3RyaW5nKTogUHJvbWlzZTxEb2N1bWVudGF0aW9uPiB7XG4gICAgcmV0dXJuIG5ldyBEb2N1bWVudGF0aW9uKGFzc2VtYmx5TmFtZSwgYXNzZW1ibGllc0Rpcik7XG4gIH1cblxuICBwcml2YXRlIHJlYWRvbmx5IGNsZWFudXBEaXJlY3RvcmllczogU2V0PHN0cmluZz4gPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSBhc3NlbWJsaWVzQ2FjaGU6IE1hcDxzdHJpbmcsIHJlZmxlY3QuQXNzZW1ibHk+ID0gbmV3IE1hcDxzdHJpbmcsIHJlZmxlY3QuQXNzZW1ibHk+KCk7XG4gIHByaXZhdGUgYXNzZW1ibHlGcW46IHN0cmluZyB8IHVuZGVmaW5lZDtcblxuICBwcml2YXRlIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgYXNzZW1ibHlOYW1lOiBzdHJpbmcsXG4gICAgcHJpdmF0ZSByZWFkb25seSBhc3NlbWJsaWVzRGlyOiBzdHJpbmcsXG4gICkgeyB9XG5cbiAgLyoqXG4gICAqIExpc3QgYWxsIHN1Ym1vZHVsZXMgaW4gdGhlIGFzc2VtYmx5LlxuICAgKi9cbiAgcHVibGljIGFzeW5jIGxpc3RTdWJtb2R1bGVzKCkge1xuICAgIGNvbnN0IHRzQXNzZW1ibHkgPSBhd2FpdCB0aGlzLmNyZWF0ZUFzc2VtYmx5KHVuZGVmaW5lZCwgeyBsb29zZTogdHJ1ZSwgdmFsaWRhdGU6IGZhbHNlIH0pO1xuICAgIHJldHVybiB0c0Fzc2VtYmx5LmFsbFN1Ym1vZHVsZXM7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgdG9JbmRleE1hcmtkb3duKGZpbGVTdWZmaXg6IHN0cmluZywgb3B0aW9uczogUmVuZGVyT3B0aW9ucykge1xuICAgIGNvbnN0IGFzc2VtYmx5ID0gYXdhaXQgdGhpcy5jcmVhdGVBc3NlbWJseSh1bmRlZmluZWQsIHsgbG9vc2U6IHRydWUsIHZhbGlkYXRlOiBmYWxzZSB9KTtcbiAgICBjb25zdCBzdWJtb2R1bGVzID0gYXdhaXQgdGhpcy5saXN0U3VibW9kdWxlcygpO1xuICAgIGNvbnN0IHNjaGVtYSA9IChhd2FpdCB0aGlzLnRvSnNvbih7XG4gICAgICAuLi5vcHRpb25zLFxuICAgICAgc3VibW9kdWxlOiB1bmRlZmluZWQsXG4gICAgICBhbGxTdWJtb2R1bGVzOiBmYWxzZSxcbiAgICB9KSkuY29udGVudDtcblxuICAgIGNvbnN0IHJlZiA9IG5ldyBNYXJrZG93bkRvY3VtZW50KHsgaGVhZGVyOiB7IHRpdGxlOiAnQVBJIFJlZmVyZW5jZScgfSwgaWQ6ICdhcGktcmVmZXJlbmNlJyB9KTtcblxuICAgIGlmIChzY2hlbWEudmVyc2lvbiAhPT0gQ1VSUkVOVF9TQ0hFTUFfVkVSU0lPTikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmV4cGVjdGVkIHNjaGVtYSB2ZXJzaW9uOiAke3NjaGVtYS52ZXJzaW9ufWApO1xuICAgIH1cblxuICAgIGNvbnN0IHJlbmRlcmVyID0gbmV3IE1hcmtkb3duUmVuZGVyZXIoe1xuICAgICAgbGFuZ3VhZ2U6IG9wdGlvbnMubGFuZ3VhZ2UsXG4gICAgICBwYWNrYWdlTmFtZTogYXNzZW1ibHkubmFtZSxcbiAgICAgIHBhY2thZ2VWZXJzaW9uOiBhc3NlbWJseS52ZXJzaW9uLFxuICAgIH0pO1xuXG4gICAgaWYgKHN1Ym1vZHVsZXMubGVuZ3RoKSB7XG4gICAgICByZWYuc2VjdGlvbihyZW5kZXJ