@codegena/oapi3ts
Version:
Codegeneration from OAS3 to TypeScript
486 lines • 76 kB
JavaScript
import _ from 'lodash';
import * as jsonPointer from 'json-pointer';
import { Generic as SchemaGeneric } from '@codegena/definitions/json-schema';
import { Oas3ParameterTarget, } from '@codegena/definitions/oas3';
import { defaultConfig } from './config';
import { ParsingError, ParsingProblems } from './parsing-problems';
const jsonPathRegex = /([\w:\/\\\.]+)?#(\/?[\w+\/?]+)/;
/**
* @param pieces
* @return
* JSON-Path according to [RFC-6901](https://tools.ietf.org/html/rfc6901)
* TODO refactor: move to common helper
*/
function makeJsonPath(...pieces) {
return jsonPointer.compile(pieces);
}
/**
* Rethrow {@link ParsingError} if original error already handled at inner level
* @param {ParsingError | any} error
*/
function rethrowParsingError(error) {
if (error instanceof ParsingError) {
throw error;
}
}
/**
* Базовый класс загрузчика.
*/
export class BaseConvertor {
constructor(config = defaultConfig) {
this.config = config;
}
loadOAPI3Structure(structure) {
if (!structure || !_.isObjectLike(structure)) {
throw new ParsingError([
`Expected structure to be object but got:`,
JSON.stringify(structure, null, ' ')
].join('\n'));
}
this._operationsMeta = [];
this._structure = structure;
}
setForeignSchemeFn(fn) {
if (!_.isFunction(fn)) {
throw new ParsingError('Error in `setForeignSchemeFn`: argument has to be function!');
}
this._foreignSchemaFn = (jsonPath) => {
try {
return fn(jsonPath);
}
catch (e) {
throw new ParsingError('Error when trying to resolve schema!', { jsonPath });
}
};
}
getApiMeta() {
return this._operationsMeta;
}
/**
* Getting of "entry-points" from structure in {@link _structure} early
* loaded by {@link loadOAPI3Structure}.
*
* Entrypoints are:
*
* - Parameters
* - Requests
* - Responses
*
* ### Why it needed?
*
* Entrypoints is needed to use [Convertor.renderRecursive]{@link Convertor.renderRecursive}.
* It's like a pulling on thread where entrypoints are outstanding trheads.
*
* @param ApiMetaInfo metaInfo
* Mutable object where meta-information accumulates during
* API-info extracting.
*/
getOAPI3EntryPoints(context = {}, metaInfo = []) {
const alreadyConverted = [];
// parameters
const methodsSchemes = this.getMethodsSchemes(metaInfo);
const dataTypeContainers = _.map(methodsSchemes, (schema, modelName) => {
const container = this.convert(schema, context, modelName);
// TODO Crutch. This class should never know about assignedTypes
// in GenericDescriptor
if (schema instanceof SchemaGeneric) {
_.each(container, (description) => {
if (description['assignedTypes']) {
description['assignedTypes'] = ['TCode', 'TContentType', 'T1', 'T2'];
}
});
}
// Исключение дубликатов.
// Дубликаты появляются, когда типы данные, которые
// ссылаются ($ref) без изменения на другие, подменяются
// моделями из `schema`.
return _.map(container, (descr) => {
// Excluding of elements having common `originalSchemaPath`
// and simultaneously already related with.
if (descr.originalSchemaPath) {
if (_.findIndex(alreadyConverted, v => v === descr.originalSchemaPath) !== -1) {
return null;
}
alreadyConverted.push(descr.originalSchemaPath);
}
return descr;
});
});
const dataTypeContainer = _.flattenDepth(dataTypeContainers);
return _.compact(dataTypeContainer);
}
/**
* Получить дескриптор типа по JSON Path:
* возвращает уже созданный ранее, или создает
* новый при первом упоминании.
*
* @param path
* @param context
*/
findTypeByPath(path, context) {
const alreadyFound = _.find(_.values(context), (v) => v.originalSchemaPath === path);
return alreadyFound
? [alreadyFound]
: this._processSchema(path, context);
}
/**
* @deprecated will be renamed to `getSchemaByRef`
* @param ref
* @param pathWhereReferred
* @return
*/
getSchemaByPath(ref, pathWhereReferred) {
const pathMatches = ref.match(jsonPathRegex);
if (pathMatches) {
const filePath = pathMatches[1];
const schemaPath = pathMatches[2];
const src = filePath
? this._getForeignSchema(filePath)
: this._structure;
const result = _.get(src, _.trim(schemaPath, '#/\\').replace(/[\\\/]/g, '.'), undefined);
if (result === undefined) {
ParsingProblems.parsingWarning(`Cant resolve ${ref}!`, {
oasStructure: this._structure,
relatedRef: ref,
jsonPath: pathWhereReferred
? makeJsonPath(...pathWhereReferred)
: undefined
});
}
return result;
}
else {
throw new ParsingError(`JSON Path error: ${ref} is not valid JSON path!`, {
oasStructure: this._structure,
relatedRef: ref,
jsonPath: pathWhereReferred
? makeJsonPath(...pathWhereReferred)
: undefined
});
}
}
/**
* Извлечени схем из параметров, ответов и тел запросов для API.
* @param metaInfo
* Place for storing meta-info of API-method.
*/
getMethodsSchemes(metaInfo) {
const struct = this._structure;
if (!struct) {
throw new ParsingError([
'There is no structure loaded!',
'Please, call method `loadOAPI3Structure` before!'
].join(' '));
}
const result = {};
const paths = struct.paths;
if (!paths) {
throw new ParsingError('No paths presented in OAS structure!', { oasStructure: struct });
}
for (const path in paths) {
// skip proto's properties
if (!paths.hasOwnProperty(path)) {
continue;
}
const jsonPathToPath = ['paths', path];
if (!path) {
ParsingProblems.parsingWarning('Path key cant be empty. Skipped.', {
oasStructure: struct,
jsonPath: makeJsonPath(...jsonPathToPath)
});
continue;
}
const pathItem = struct.paths[path];
if (!_.isObjectLike(pathItem)) {
ParsingProblems.parsingWarning('Item of "paths" should be object like. Skipped.', {
oasStructure: struct,
jsonPath: makeJsonPath(...jsonPathToPath)
});
continue;
}
const methods = [
'delete',
'get',
'head',
'options',
'patch',
'post',
'put',
'trace',
];
for (const methodName of methods) {
// skip proto's properties
if (!pathItem.hasOwnProperty(methodName)) {
continue;
}
const apiOperation = pathItem[methodName];
const jsonPathToOperation = [...jsonPathToPath, methodName];
if (!_.isObjectLike(apiOperation)) {
ParsingProblems.parsingWarning('Operation should be object like. Skipped.', {
oasStructure: struct,
jsonPath: makeJsonPath(...jsonPathToOperation)
});
continue;
}
const baseTypeName = this._getOperationBaseName(apiOperation, methodName, path, jsonPathToOperation);
const servers = this._getOperationServers(apiOperation, jsonPathToOperation);
const metaInfoItem = {
apiSchemaFile: 'domain-api-schema',
baseTypeName,
headersSchema: null,
headersModelName: null,
method: methodName.toUpperCase(),
mockData: {},
paramsModelName: null,
paramsSchema: null,
path,
queryParams: [],
requestIsRequired: false,
requestModelName: null,
requestSchema: null,
responseModelName: null,
responseSchema: null,
servers,
// default noname
typingsDependencies: [],
typingsDirectory: 'typings',
};
let jsonSubPathToOperation;
try {
jsonSubPathToOperation = [...jsonPathToOperation, 'parameters'];
// pick Parameters schema
_.assign(result, this._pickApiMethodParameters(metaInfoItem, apiOperation.parameters, jsonSubPathToOperation));
}
catch (error) {
rethrowParsingError(error);
throw new ParsingError('An error occurred at method parameters fetching', {
oasStructure: struct,
jsonPath: makeJsonPath(...jsonSubPathToOperation),
originalError: error
});
}
try {
jsonSubPathToOperation = [...jsonPathToOperation, 'responses'];
// pick Responses schema
_.assign(result, this._pickApiMethodResponses(metaInfoItem, apiOperation.responses || {}, jsonSubPathToOperation));
}
catch (error) {
rethrowParsingError(error);
throw new ParsingError('An error occurred at method responses fetching', {
oasStructure: struct,
jsonPath: makeJsonPath(...jsonSubPathToOperation),
originalError: error
});
}
try {
jsonSubPathToOperation = [...jsonPathToOperation, 'requestBody'];
// pick Request Body schema
_.assign(result, this._pickApiMethodRequest(apiOperation, metaInfoItem, [...jsonSubPathToOperation]));
}
catch (error) {
rethrowParsingError(error);
throw new ParsingError('An error occurred at method request body fetching', {
oasStructure: struct,
jsonPath: makeJsonPath(...jsonSubPathToOperation),
originalError: error
});
}
metaInfo.push(metaInfoItem);
this._operationsMeta.push({
operationJsonPath: jsonPathToOperation,
apiMeta: metaInfoItem,
});
}
}
return result;
}
/**
* Get parameters from the `parameters` section
* in method into {@link ApiMetaInfo}-object
*/
_pickApiMethodParameters(metaInfoItem, parameters, jsonPathToOperation) {
const result = {};
const paramsModelName = this.config.parametersModelName(metaInfoItem.baseTypeName);
const paramsSchema = {
properties: {},
required: [],
type: 'object'
};
// process parameters
_.each(parameters || [], (parameter, index) => {
if (parameter.$ref) {
parameter = _.merge(_.omit(parameter, ['$ref']), this.getSchemaByPath(parameter.$ref, [...jsonPathToOperation, String(index)]));
}
if (parameter.schema) {
paramsSchema.properties[parameter.name] = parameter.schema;
if (parameter.description) {
parameter.schema.description = parameter.description;
}
if (parameter.readOnly) {
paramsSchema.properties[parameter.name].readOnly = true;
}
if (parameter.required) {
paramsSchema.required.push(parameter.name);
}
if (Number(index) === 0) {
// metaInfoItem.typingsDependencies.push(paramsModelName);
metaInfoItem.paramsModelName = paramsModelName;
metaInfoItem.paramsSchema = paramsSchema;
}
if (parameter.in === Oas3ParameterTarget.Query) {
metaInfoItem.queryParams.push(parameter.name);
}
if (!paramsSchema.description) {
paramsSchema.description =
`Model of parameters for API \`${metaInfoItem.path}\``;
}
result[paramsModelName] = paramsSchema;
}
});
if (result[paramsModelName]) {
metaInfoItem.typingsDependencies.push(paramsModelName);
}
return result;
}
_pickApiMethodResponses(metaInfoItem, responses, jsonPathToOperation) {
const result = {};
_.each(responses, (response, code) => {
// todo do tests when $ref to schema.responses
if (response.$ref) {
response = _.merge(_.omit(response, ['$ref']), this.getSchemaByPath(response.$ref, [...jsonPathToOperation, String(code)]));
}
const mediaTypes = response.content
|| response.schema // Case for OAS2
|| {}; // Fallback
// if content set, but empty
if (_.keys(mediaTypes).length === 0) {
mediaTypes['application/json'] = null;
}
// todo пока обрабатываются только контент и заголовки
_.each(mediaTypes || {}, (mediaContent, contentTypeKey) => {
// todo do fallback if no `schema property`
const schema = _.get(mediaContent, 'schema')
|| {
description: 'Empty response',
type: 'null',
}; // by default
if (!metaInfoItem.responseSchema) {
metaInfoItem.responseSchema = {};
}
// add description if it's set
if (response.description) {
schema.description = response.description;
}
_.set(metaInfoItem.responseSchema, [code, contentTypeKey], schema);
});
if (response.headers) {
// TODO has to be tested
const modelName = this.config.headersModelName(metaInfoItem.baseTypeName, code);
result[modelName] = {
properties: response.headers,
type: 'object'
};
}
});
if (metaInfoItem.responseSchema) {
const modelName = this.config.responseModelName(metaInfoItem.baseTypeName, '', '');
metaInfoItem.responseModelName = modelName;
metaInfoItem.typingsDependencies.push(modelName);
result[modelName] = new SchemaGeneric(_.mapValues(metaInfoItem.responseSchema, subSchema => new SchemaGeneric(subSchema)));
}
return result;
}
_pickApiMethodRequest(apiOperation, metaInfoItem, jsonPathToOperation) {
const { requestBody } = apiOperation;
let responses;
if (!requestBody) {
return null;
}
else {
metaInfoItem.requestIsRequired = !!requestBody.required;
if (!requestBody.content) {
return null;
}
const modelName = this.config.requestModelName(metaInfoItem.baseTypeName);
responses = _(requestBody.content)
.mapValues((mediaContent, mediaTypeName) => {
const mapResult = mediaContent.schema ? Object.assign({}, mediaContent.schema) : null;
if (apiOperation.requestBody.description && !mapResult.description) {
mapResult.description = apiOperation.requestBody.description;
}
return mapResult;
})
.value();
metaInfoItem.requestModelName = modelName;
metaInfoItem.requestSchema = responses;
metaInfoItem.typingsDependencies.push(modelName);
return _.zipObject([modelName], [new SchemaGeneric(responses)]);
}
}
/**
* Получение нового дескриптора на основе JSON Path
* из текущей структуры.
*
* @param path
* @param context
*/
_processSchema(path, context) {
const schema = this.getSchemaByPath(path);
const modelName = (_.trim(path, '/\\').match(/(\w+)$/) || [])[1];
if (!schema) {
throw new Error(`Error: can't find schema with path: ${path}!`);
}
const results = this.convert(schema, context, modelName, null, path);
_.each(results, (result) => {
context[result.originalSchemaPath || result.modelName] = result;
});
return results;
}
_getForeignSchema(ref) {
if (this._foreignSchemaFn) {
return this._foreignSchemaFn(ref);
}
else {
throw new ParsingError([
'Function for getting foreign scheme not set.',
`Use setForeignSchemeFn(). Path: ${ref}.`
].join('\n'), {
oasStructure: this._structure,
relatedRef: ref
});
}
}
_getOperationBaseName(apiOperation, methodName, path, jsonPathToOperation) {
if (!apiOperation.operationId || !_.isString(apiOperation.operationId)) {
const baseNameFallback = _.upperFirst(_.camelCase(jsonPathToOperation.join('-').replace(/[^\-\w]/g, '')));
ParsingProblems.parsingWarning([
`Wrong operation id "${apiOperation.operationId}".`,
`Fallback basename is: "${baseNameFallback}".`
].join('\n'), {
oasStructure: this._structure,
jsonPath: makeJsonPath(...jsonPathToOperation, 'operationId')
});
return baseNameFallback;
}
const operationId = _.camelCase(apiOperation.operationId.trim().replace(/[^\w+]/g, '_'));
return _.upperFirst(operationId) || [
_.capitalize(methodName),
_.upperFirst(_.camelCase(path))
].join('');
}
_getOperationServers(apiOperation, jsonPathToOperation) {
let servers = apiOperation.servers || this._structure.servers;
if (servers !== undefined && !_.isArray(servers)) {
ParsingProblems.parsingWarning('Servers should be array. Skipped.', {
oasStructure: this._structure,
jsonPath: makeJsonPath(...jsonPathToOperation, 'servers')
});
servers = [];
}
if (!servers || servers.length < 1) {
servers = defaultConfig.defaultServerInfo;
}
return servers;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udmVydG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vbGlicy9vYXBpM3RzL3NyYy9sZWdhY3kvY29yZS9jb252ZXJ0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxDQUFDLE1BQU0sUUFBUSxDQUFDO0FBQ3ZCLE9BQU8sS0FBSyxXQUFXLE1BQU0sY0FBYyxDQUFDO0FBRzVDLE9BQU8sRUFDSCxPQUFPLElBQUksYUFBYSxFQUczQixNQUFNLG1DQUFtQyxDQUFDO0FBQzNDLE9BQU8sRUFJSCxtQkFBbUIsR0FNdEIsTUFBTSw0QkFBNEIsQ0FBQztBQUVwQyxPQUFPLEVBQW1CLGFBQWEsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUMxRCxPQUFPLEVBQUUsWUFBWSxFQUFFLGVBQWUsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBUW5FLE1BQU0sYUFBYSxHQUFHLGdDQUFnQyxDQUFDO0FBRXZEOzs7OztHQUtHO0FBQ0gsU0FBUyxZQUFZLENBQUMsR0FBRyxNQUE4QjtJQUNuRCxPQUFPLFdBQVcsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDdkMsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQVMsbUJBQW1CLENBQUMsS0FBeUI7SUFDbEQsSUFBSSxLQUFLLFlBQVksWUFBWSxFQUFFO1FBQy9CLE1BQU0sS0FBSyxDQUFDO0tBQ2Y7QUFDTCxDQUFDO0FBT0Q7O0dBRUc7QUFDSCxNQUFNLE9BQWdCLGFBQWE7SUFNL0IsWUFDYyxTQUEwQixhQUFhO1FBQXZDLFdBQU0sR0FBTixNQUFNLENBQWlDO0lBQ2xELENBQUM7SUFFRyxrQkFBa0IsQ0FBQyxTQUE0QjtRQUNsRCxJQUFJLENBQUMsU0FBUyxJQUFJLENBQUMsQ0FBQyxDQUFDLFlBQVksQ0FBQyxTQUFTLENBQUMsRUFBRTtZQUMxQyxNQUFNLElBQUksWUFBWSxDQUFDO2dCQUNuQiwwQ0FBMEM7Z0JBQzFDLElBQUksQ0FBQyxTQUFTLENBQUMsU0FB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QUFDO0lBQ2YsQ0FBQztJQUVPLG9CQUFvQixDQUN4QixZQUEyQixFQUMzQixtQkFBNkI7UUFFN0IsSUFBSSxPQUFPLEdBQUcsWUFBWSxDQUFDLE9BQU8sSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQztRQUU5RCxJQUFJLE9BQU8sS0FBSyxTQUFTLElBQUksQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFO1lBQzlDLGVBQWUsQ0FBQyxjQUFjLENBQUMsbUNBQW1DLEVBQUU7Z0JBQ2hFLFlBQVksRUFBRSxJQUFJLENBQUMsVUFBVTtnQkFDN0IsUUFBUSxFQUFFLFlBQVksQ0FBQyxHQUFHLG1CQUFtQixFQUFFLFNBQVMsQ0FBQzthQUM1RCxDQUFDLENBQUM7WUFFSCxPQUFPLEdBQUcsRUFBRSxDQUFDO1NBQ2hCO1FBRUQsSUFBSSxDQUFDLE9BQU8sSUFBSSxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRTtZQUNoQyxPQUFPLEdBQUcsYUFBYSxDQUFDLGlCQUFpQixDQUFDO1NBQzdDO1FBRUQsT0FBTyxPQUFPLENBQUM7SUFDbkIsQ0FBQztDQUNKIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCAqIGFzIGpzb25Qb2ludGVyIGZyb20gJ2pzb24tcG9pbnRlcic7XG5cbmltcG9ydCB7IEhhc1Jlc3BvbnNlcywgSGFzQ29udGVudFR5cGUgfSBmcm9tICdAY29kZWdlbmEvZGVmaW5pdGlvbnMvYXNwZWN0cyc7XG5pbXBvcnQge1xuICAgIEdlbmVyaWMgYXMgU2NoZW1hR2VuZXJpYyxcbiAgICBTY2hlbWEsXG4gICAgU2NoZW1hT2JqZWN0XG59IGZyb20gJ0Bjb2RlZ2VuYS9kZWZpbml0aW9ucy9qc29uLXNjaGVtYSc7XG5pbXBvcnQge1xuICAgIE9hczNNZWRpYUNvbnRlbnQsXG4gICAgT2FzM09wZXJhdGlvbixcbiAgICBPYXMzUGFyYW1ldGVyLFxuICAgIE9hczNQYXJhbWV0ZXJUYXJnZXQsXG4gICAgT2FzM1BhdGhJdGVtLFxuICAgIE9hczNQYXRocyxcbiAgICBPYXMzUmVzcG9uc2UsXG4gICAgT2FzM1NwZWNpZmljYXRpb24sXG4gICAgT2FzM1NlcnZlcixcbn0gZnJvbSAnQGNvZGVnZW5hL2RlZmluaXRpb25zL29hczMnO1xuXG5pbXBvcnQgeyBDb252ZXJ0b3JDb25maWcsIGRlZmF1bHRDb25maWcgfSBmcm9tICcuL2NvbmZpZyc7XG5pbXBvcnQgeyBQYXJzaW5nRXJyb3IsIFBhcnNpbmdQcm9ibGVtcyB9IGZyb20gJy4vcGFyc2luZy1wcm9ibGVtcyc7XG5pbXBvcnQge1xuICAgIEFwaU1ldGFJbmZvLFxuICAgIERhdGFUeXBlQ29udGFpbmVyLFxuICAgIERhdGFUeXBlRGVzY3JpcHRvcixcbiAgICBEZXNjcmlwdG9yQ29udGV4dFxufSBmcm9tICcuL2luZGV4JztcblxuY29uc3QganNvblBhdGhSZWdleCA9IC8oW1xcdzpcXC9cXFxcXFwuXSspPyMoXFwvP1tcXHcrXFwvP10rKS87XG5cbi8qKlxuICogQHBhcmFtIHBpZWNlc1xuICogQHJldHVyblxuICogSlNPTi1QYXRoIGFjY29yZGluZyB0byBbUkZDLTY5MDFdKGh0dHBzOi8vdG9vbHMuaWV0Zi5vcmcvaHRtbC9yZmM2OTAxKVxuICogVE9ETyByZWZhY3RvcjogbW92ZSB0byBjb21tb24gaGVscGVyXG4gKi9cbmZ1bmN0aW9uIG1ha2VKc29uUGF0aCguLi5waWVjZXM6IEFycmF5PHN0cmluZyB8IG51bWJlcj4pOiBzdHJpbmcge1xuICAgIHJldHVybiBqc29uUG9pbnRlci5jb21waWxlKHBpZWNlcyk7XG59XG5cbi8qKlxuICogUmV0aHJvdyB7QGxpbmsgUGFyc2luZ0Vycm9yfSBpZiBvcmlnaW5hbCBlcnJvciBhbHJlYWR5IGhhbmRsZWQgYXQgaW5uZXIgbGV2ZWxcbiAqIEBwYXJhbSB7UGFyc2luZ0Vycm9yIHwgYW55fSBlcnJvclxuICovXG5mdW5jdGlvbiByZXRocm93UGFyc2luZ0Vycm9yKGVycm9yOiBQYXJzaW5nRXJyb3IgfCBhbnkpOiB2b2lkIHtcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBQYXJzaW5nRXJyb3IpIHtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxufVxuXG5pbnRlcmZhY2UgT3BlcmF0aW9uTWV0YSB7XG4gICAgb3BlcmF0aW9uSnNvblBhdGg6IHN0cmluZ1tdO1xuICAgIGFwaU1ldGE6IEFwaU1ldGFJbmZvO1xufVxuXG4vKipcbiAqINCR0LDQt9C+0LLRi9C5INC60LvQsNGB0YEg0LfQsNCz0YDRg9C30YfQuNC60LAuXG4gKi9cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBCYXNlQ29udmVydG9yIHtcblxuICAgIHByb3RlY3RlZCBfc3RydWN0dXJlOiBPYXMzU3BlY2lmaWNhdGlvbjtcbiAgICBwcm90ZWN0ZWQgX2ZvcmVpZ25TY2hlbWFGbjogKHJlc291cmNlUGF0aDogc3RyaW5nKSA9PiBTY2hlbWE7XG4gICAgcHJvdGVjdGVkIF9vcGVyYXRpb25zTWV0YTogT3BlcmF0aW9uTWV0YVtdO1xuXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIHByb3RlY3RlZCBjb25maWc6IENvbnZlcnRvckNvbmZpZyA9IGRlZmF1bHRDb25maWdcbiAgICApIHt9XG5cbiAgICBwdWJsaWMgbG9hZE9BUEkzU3RydWN0dXJlKHN0cnVjdHVyZTogT2FzM1NwZWNpZmljYXRpb24pIHtcbiAgICAgICAgaWYgKCFzdHJ1Y3R1cmUgfHwgIV8uaXNPYmplY3RMaWtlKHN0cnVjdHVyZSkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBQYXJzaW5nRXJyb3IoW1xuICAgICAgICAgICAgICAgIGBFeHBlY3RlZCBzdHJ1Y3R1cmUgdG8gYmUgb2JqZWN0IGJ1dCBnb3Q6YCxcbiAgICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeShzdHJ1Y3R1cmUsIG51bGwsICcgJylcbiAgICAgICAgICAgIF0uam9pbignXFxuJykpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fb3BlcmF0aW9uc01ldGEgPSBbXTtcbiAgICAgICAgdGhpcy5fc3RydWN0dXJlID0gc3RydWN0dXJlO1xuICAgIH1cblxuICAgIHB1YmxpYyBzZXRGb3JlaWduU2NoZW1lRm4oZm46IChqc29uUGF0aDogc3RyaW5nKSA9PiBTY2hlbWEpOiB2b2lkIHtcbiAgICAgICAgaWYgKCFfLmlzRnVuY3Rpb24oZm4pKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgUGFyc2luZ0Vycm9yKCdFcnJvciBpbiBgc2V0Rm9yZWlnblNjaGVtZUZuYDogYXJndW1lbnQgaGFzIHRvIGJlIGZ1bmN0aW9uIScpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fZm9yZWlnblNjaGVtYUZuID0gKGpzb25QYXRoKSA9PiB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmbihqc29uUGF0aCk7XG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IFBhcnNpbmdFcnJvcihcbiAgICAgICAgICAgICAgICAgICAgJ0Vycm9yIHdoZW4gdHJ5aW5nIHRvIHJlc29sdmUgc2NoZW1hIScsXG4gICAgICAgICAgICAgICAgICAgIHsganNvblBhdGggfVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgcHVibGljIGdldEFwaU1ldGEoKTogT3BlcmF0aW9uTWV0YVtdIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX29wZXJhdGlvbnNNZXRhO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldHRpbmcgb2YgXCJlbnRyeS1wb2ludHNcIiBmcm9tIHN0cnVjdHVyZSBpbiB7QGxpbmsgX3N0cnVjdHVyZX0gZWFybHlcbiAgICAgKiBsb2FkZWQgYnkge0BsaW5rIGxvYWRPQVBJM1N0cnVjdHVyZX0uXG4gICAgICpcbiAgICAgKiBFbnRyeXBvaW50cyBhcmU6XG4gICAgICpcbiAgICAgKiAtIFBhcmFtZXRlcnNcbiAgICAgKiAtIFJlcXVlc3RzXG4gICAgICogLSBSZXNwb25zZXNcbiAgICAgKlxuICAgICAqICMjIyBXaHkgaXQgbmVlZGVkP1xuICAgICAqXG4gICAgICogRW50cnlwb2ludHMgaXMgbmVlZGVkIHRvIHVzZSBbQ29udmVydG9yLnJlbmRlclJlY3Vyc2l2ZV17QGxpbmsgQ29udmVydG9yLnJlbmRlclJlY3Vyc2l2ZX0uXG4gICAgICogSXQncyBsaWtlIGEgcHVsbGluZyBvbiB0aHJlYWQgd2hlcmUgZW50cnlwb2ludHMgYXJlIG91dHN0YW5kaW5nIHRyaGVhZHMuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gQXBpTWV0YUluZm8gbWV0YUluZm9cbiAgICAgKiBNdXRhYmxlIG9iamVjdCB3aGVyZSBtZXRhLWluZm9ybWF0aW9uIGFjY3VtdWxhdGVzIGR1cmluZ1xuICAgICAqIEFQSS1pbmZvIGV4dHJhY3RpbmcuXG4gICAgICovXG4gICAgcHVibGljIGdldE9BUEkzRW50cnlQb2ludHMoXG4gICAgICAgIGNvbnRleHQgPSB7fSxcbiAgICAgICAgbWV0YUluZm86IEFwaU1ldGFJbmZvW10gPSBbXVxuICAgICk6IERhdGFUeXBlQ29udGFpbmVyIHtcbiAgICAgICAgY29uc3QgYWxyZWFkeUNvbnZlcnRlZCA9IFtdO1xuICAgICAgICAvLyBwYXJhbWV0ZXJzXG4gICAgICAgIGNvbnN0IG1ldGhvZHNTY2hlbWVzID0gdGhpcy5nZXRNZXRob2RzU2NoZW1lcyhtZXRhSW5mbyk7XG4gICAgICAgIGNvbnN0IGRhdGFUeXBlQ29udGFpbmVyczogRGF0YVR5cGVDb250YWluZXJbXSA9IF8ubWFwKFxuICAgICAgICAgICAgbWV0aG9kc1NjaGVtZXMsXG4gICAgICAgICAgICAoc2NoZW1hLCBtb2RlbE5hbWUpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBjb250YWluZXIgPSB0aGlzLmNvbnZlcnQoXG4gICAgICAgICAgICAgICAgICAgIHNjaGVtYSxcbiAgICAgICAgICAgICAgICAgICAgY29udGV4dCxcbiAgICAgICAgICAgICAgICAgICAgbW9kZWxOYW1lXG4gICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgIC8vIFRPRE8gQ3J1dGNoLiBUaGlzIGNsYXNzIHNob3VsZCBuZXZlciBrbm93IGFib3V0IGFzc2lnbmVkVHlwZXNcbiAgICAgICAgICAgICAgICAvLyBpbiBHZW5lcmljRGVzY3JpcHRvclxuICAgICAgICAgICAgICAgIGlmIChzY2hlbWEgaW5zdGFuY2VvZiBTY2hlbWFHZW5lcmljKSB7XG4gICAgICAgICAgICAgICAgICAgIF8uZWFjaChjb250YWluZXIsIChkZXNjcmlwdGlvbjogRGF0YVR5cGVEZXNjcmlwdG9yKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoZGVzY3JpcHRpb25bJ2Fzc2lnbmVkVHlwZXMnXSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uWydhc3NpZ25lZFR5cGVzJ10gPSBbJ1RDb2RlJywgJ1RDb250ZW50VHlwZScsICdUMScsICdUMiddO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyDQmNGB0LrQu9GO0YfQtdC90LjQtSDQtNGD0LHQu9C40LrQsNGC0L7Qsi5cbiAgICAgICAgICAgICAgICAvLyDQlNGD0LHQu9C40LrQsNGC0Ysg0L/QvtGP0LLQu9GP0Y7RgtGB0Y8sINC60L7Qs9C00LAg0YLQuNC/0Ysg0LTQsNC90L3Ri9C1LCDQutC+0YLQvtGA0YvQtVxuICAgICAgICAgICAgICAgIC8vINGB0YHRi9C70LDRjtGC0YHRjyAoJHJlZikg0LHQtdC3INC40LfQvNC10L3QtdC90LjRjyDQvdCwINC00YDRg9Cz0LjQtSwg0L/QvtC00LzQtdC90Y/RjtGC0YHRj1xuICAgICAgICAgICAgICAgIC8vINC80L7QtNC10LvRj9C80Lgg0LjQtyBgc2NoZW1hYC5cbiAgICAgICAgICAgICAgICByZXR1cm4gXy5tYXAoY29udGFpbmVyLCAoZGVzY3I6IERhdGFUeXBlRGVzY3JpcHRvcikgPT4ge1xuICAgICAgICAgICAgICAgICAgICAvLyBFeGNsdWRpbmcgb2YgZWxlbWVudHMgaGF2aW5nIGNvbW1vbiBgb3JpZ2luYWxTY2hlbWFQYXRoYFxuICAgICAgICAgICAgICAgICAgICAvLyBhbmQgc2ltdWx0YW5lb3VzbHkgYWxyZWFkeSByZWxhdGVkIHdpdGguXG4gICAgICAgICAgICAgICAgICAgIGlmIChkZXNjci5vcmlnaW5hbFNjaGVtYVBhdGgpIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKF8uZmluZEluZGV4KFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscmVhZHlDb252ZXJ0ZWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdiA9PiB2ID09PSBkZXNjci5vcmlnaW5hbFNjaGVtYVBhdGhcbiAgICAgICAgICAgICAgICAgICAgICAgICkgIT09IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIGFscmVhZHlDb252ZXJ0ZWQucHVzaChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXNjci5vcmlnaW5hbFNjaGVtYVBhdGhcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZGVzY3I7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG5cbiAgICAgICAgY29uc3QgZGF0YVR5cGVDb250YWluZXIgPSBfLmZsYXR0ZW5EZXB0aDxEYXRhVHlwZURlc2NyaXB0b3I+KFxuICAgICAgICAgICAgZGF0YVR5cGVDb250YWluZXJzXG4gICAgICAgICk7XG5cbiAgICAgICAgcmV0dXJuIF8uY29tcGFjdChkYXRhVHlwZUNvbnRhaW5lcik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICog0J/QvtC70YPRh9C40YLRjCDQtNC10YHQutGA0LjQv9GC0L7RgCDRgtC40L/QsCDQv9C+IEpTT04gUGF0aDpcbiAgICAgKiDQstC+0LfQstGA0LDRidCw0LXRgiDRg9C20LUg0YHQvtC30LTQsNC90L3Ri9C5INGA0LDQvdC10LUsINC40LvQuCDRgdC+0LfQtNCw0LXRglxuICAgICAqINC90L7QstGL0Lkg0L/RgNC4INC/0LXRgNCy0L7QvCDRg9C/0L7QvNC40L3QsNC90LjQuC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBwYXRoXG4gICAgICogQHBhcmFtIGNvbnRleHRcbiAgICAgKi9cbiAgICBwdWJsaWMgZmluZFR5cGVCeVBhdGgoXG4gICAgICAgIHBhdGg6IHN0cmluZyxcbiAgICAgICAgY29udGV4dDogRGVzY3JpcHRvckNvbnRleHRcbiAgICApOiBEYXRhVHlwZUNvbnRhaW5lciB7XG5cbiAgICAgICAgY29uc3QgYWxyZWFkeUZvdW5kID0gXy5maW5kKFxuICAgICAgICAgICAgXy52YWx1ZXMoY29udGV4dCksXG4gICAgICAgICAgICAodjogRGF0YVR5cGVEZXNjcmlwdG9yKSA9PlxuICAgICAgICAgICAgICAgIHYub3JpZ2luYWxTY2hlbWFQYXRoID09PSBwYXRoXG4gICAgICAgICk7XG5cbiAgICAgICAgcmV0dXJuIGFscmVhZHlGb3VuZFxuICAgICAgICAgICAgPyBbYWxyZWFkeUZvdW5kXVxuICAgICAgICAgICAgOiB0aGlzLl9wcm9jZXNzU2NoZW1hKHBhdGgsIGNvbnRleHQpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBkZXByZWNhdGVkIHdpbGwgYmUgcmVuYW1lZCB0byBgZ2V0U2NoZW1hQnlSZWZgXG4gICAgICogQHBhcmFtIHJlZlxuICAgICAqIEBwYXJhbSBwYXRoV2hlcmVSZWZlcnJlZFxuICAgICAqIEByZXR1cm5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0U2NoZW1hQnlQYXRoKHJlZjogc3RyaW5nLCBwYXRoV2hlcmVSZWZlcnJlZD86IHN0cmluZ1tdKTogU2NoZW1hIHtcbiAgICAgICAgY29uc3QgcGF0aE1hdGNoZXMgPSByZWYubWF0Y2goanNvblBhdGhSZWdleCk7XG5cbiAgICAgICAgaWYgKHBhdGhNYXRjaGVzKSB7XG4gICAgICAgICAgICBjb25zdCBmaWxlUGF0aCA9IHBhdGhNYXRjaGVzWzFdO1xuICAgICAgICAgICAgY29uc3Qgc2NoZW1hUGF0aCA9IHBhdGhNYXRjaGVzWzJdO1xuICAgICAgICAgICAgY29uc3Qgc3JjID0gZmlsZVBhdGhcbiAgICAgICAgICAgICAgICA/IHRoaXMuX2dldEZvcmVpZ25TY2hlbWEoZmlsZVBhdGgpXG4gICAgICAgICAgICAgICAgOiB0aGlzLl9zdHJ1Y3R1cmU7XG5cbiAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IF8uZ2V0KFxuICAgICAgICAgICAgICAgIHNyYyxcbiAgICAgICAgICAgICAgICBfLnRyaW0oc2NoZW1hUGF0aCwgJyMvXFxcXCcpLnJlcGxhY2UoL1tcXFxcXFwvXS9nLCAnLicpLFxuICAgICAgICAgICAgICAgIHVuZGVmaW5lZFxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgaWYgKHJlc3VsdCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgUGFyc2luZ1Byb2JsZW1zLnBhcnNpbmdXYXJuaW5nKFxuICAgICAgICAgICAgICAgICAgICBgQ2FudCByZXNvbHZlICR7cmVmfSFgLFxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICBvYXNTdHJ1Y3R1cmU6IHRoaXMuX3N0cnVjdHVyZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlbGF0ZWRSZWY6IHJlZixcbiAgICAgICAgICAgICAgICAgICAgICAgIGpzb25QYXRoOiBwYXRoV2hlcmVSZWZlcnJlZFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gbWFrZUpzb25QYXRoKC4uLnBhdGhXaGVyZVJlZmVycmVkKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDogdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgUGFyc2luZ0Vycm9yKFxuICAgICAgICAgICAgICAgIGBKU09OIFBhdGggZXJyb3I6ICR7cmVmfSBpcyBub3QgdmFsaWQgSlNPTiBwYXRoIWAsXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBvYXNTdHJ1Y3R1cmU6IHRoaXMuX3N0cnVjdHVyZSxcbiAgICAgICAgICAgICAgICAgICAgcmVsYXRlZFJlZjogcmVmLFxuICAgICAgICAgICAgICAgICAgICBqc29uUGF0aDogcGF0aFdoZXJlUmVmZXJyZWRcbiAgICAgICAgICAgICAgICAgICAgICAgID8gbWFrZUpzb25QYXRoKC4uLnBhdGhXaGVyZVJlZmVycmVkKVxuICAgICAgICAgICAgICAgICAgICAgICAgOiB1bmRlZmluZWRcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICog0J/RgNC10LLRgNCw0YnQtdC90LjQtSBKU09OLdGB0YXQtdC80Ysg0LIg0L7Qv9C40YHQsNC90LjQtSDRgtC40L/QsCDQtNCw0L3QvdGL0YUuXG4gICAgICog0JLQvtC30LLRgNCw0YnQsNC10YIg0LrQvtC90YLQtdC50L3QtdGAIFvQtNC10YHQutGA0LjQv9GC0L7RgNC+0LIg0YLQuNC/0L7Qsl17QGxpbmsgRGF0YVR5cGVEZXNjcmlwdG9yfSxcbiAgICAgKiDQsiDQutC+0YLQvtGA0L7QvCDQv9C10YDQtdGH0LjRgdC70Y/RjtGC0YHRjyDRgtC40L/RiyDQtNCw0L3QvdGL0YUgKNCy0L7Qt9C80L7QttC90LAg0L/RgNC40L3QsNC00LvQtdC20L3QvtGB0YLRjFxuICAgICAqINC6INCx0L7Qu9C10LUg0YfQtdC8INC+0LTQvdC+0LzRgyDRgtC40L/RgyDQtNCw0L3QvdGL0YU6IGBudW1iZXJbXSB8IEludGVyZmFjZU5hbWVgKS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBzY2hlbWFcbiAgICAgKiDQodGF0LXQvNC