@selfage/generator_cli
Version:
Code generation for message, service, and database.
144 lines (143 loc) • 22.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateDatastoreModel = generateDatastoreModel;
const path = require("path");
const util_1 = require("./util");
let OPERATOR_NAME_MAP = new Map([
["=", "equalTo"],
[">", "greaterThan"],
["<", "lessThan"],
[">=", "greaterThanOrEqualTo"],
["<=", "lessThanOrEqualTo"],
]);
let PRIMITIVE_TYPES = new Set(["string", "number", "boolean"]);
function generateDatastoreModel(modulePath, messageName, messageDefinition, definitionFinder, indexBuilder, contentMap) {
let outputPath = (0, util_1.normalizeRelativePathForNode)(path.posix.join(path.posix.dirname(modulePath), messageDefinition.datastore.output));
let outputContentBuilder = output_content_builder_1.OutputContentBuilder.get(contentMap, outputPath);
let importMessagePath = (0, util_1.reverseImport)(modulePath, outputPath);
let messageDescriptorName = (0, util_1.toUppercaseSnaked)(messageName);
let fieldToDefinitions = new Map();
let excludedIndexes = new Set();
for (let field of messageDefinition.fields) {
fieldToDefinitions.set(field.name, field);
excludedIndexes.add(field.name);
}
let indexContentList = new Array();
if (messageDefinition.datastore.queries) {
for (let query of messageDefinition.datastore.queries) {
if (!query.filters) {
query.filters = new Array();
}
if (!query.orderings) {
query.orderings = new Array();
}
let inequalityFilteredFieldName;
for (let filter of query.filters) {
if (!OPERATOR_NAME_MAP.has(filter.operator)) {
throw new Error(`Unknown operator ${filter.operator} on query ${query.name}.`);
}
if (filter.operator !== "=") {
if (!inequalityFilteredFieldName) {
inequalityFilteredFieldName = filter.fieldName;
}
else if (inequalityFilteredFieldName !== filter.fieldName) {
throw new Error(`More than 1 fields are used in inequality filters in query ` +
`${query.name} which is not allowed by Datastore.`);
}
}
}
indexBuilder.addIndex(messageName, query);
outputContentBuilder.importFromDatastoreModelDescriptor("DatastoreQuery", "DatastoreFilter");
indexContentList.push(`${(0, util_1.generateComment)(query.comment)}
export class ${query.name}QueryBuilder {
private datastoreQuery: DatastoreQuery<${messageName}> = {
modelDescriptor: ${messageDescriptorName}_MODEL,
filters: new Array<DatastoreFilter>(),
orderings: [`);
for (let ordering of query.orderings) {
validateFieldAndNeedsToBeIndexed(ordering.fieldName, fieldToDefinitions, definitionFinder, excludedIndexes);
indexContentList.push(`
{
fieldName: "${ordering.fieldName}",
descending: ${ordering.descending}
},`);
excludedIndexes.delete(ordering.fieldName);
}
indexContentList.push(`
]
};
public start(cursor: string): this {
this.datastoreQuery.startCursor = cursor;
return this;
}
public limit(num: number): this {
this.datastoreQuery.limit = num;
return this;
}`);
for (let filter of query.filters) {
let { fieldDefinition, isEnum } = validateFieldAndNeedsToBeIndexed(filter.fieldName, fieldToDefinitions, definitionFinder, excludedIndexes);
if (isEnum) {
outputContentBuilder.importFromPath((0, util_1.transitImport)(importMessagePath, fieldDefinition.import), fieldDefinition.type);
}
indexContentList.push(`
public ${OPERATOR_NAME_MAP.get(filter.operator)}${(0, util_1.toInitialUppercased)(filter.fieldName)}(value: ${fieldDefinition.type}): this {
this.datastoreQuery.filters.push({
fieldName: "${filter.fieldName}",
fieldValue: value,
operator: "${filter.operator}",
});
return this;
}`);
}
indexContentList.push(`
public build(): DatastoreQuery<${messageName}> {
return this.datastoreQuery;
}
}
`);
}
}
let keyDefinition = fieldToDefinitions.get(messageDefinition.datastore.key);
if (!keyDefinition) {
throw new Error(`Datastore key ${messageDefinition.datastore.key} is not found from ` +
`${messageName}.`);
}
if (keyDefinition.type !== "string") {
throw new Error(`Datastore key can only be a string, but it is ` +
`${keyDefinition.type}.`);
}
if (keyDefinition.isArray) {
throw new Error(`Datastore key cannot be an array.`);
}
outputContentBuilder.importFromPath(importMessagePath, messageName, messageDescriptorName);
outputContentBuilder.importFromDatastoreModelDescriptor("DatastoreModelDescriptor");
outputContentBuilder.push(`${(0, util_1.generateComment)(messageDefinition.datastore.comment)}
export let ${messageDescriptorName}_MODEL: DatastoreModelDescriptor<${messageName}> = {
name: "${messageName}",
key: "${messageDefinition.datastore.key}",
excludedIndexes: ["${Array.from(excludedIndexes).join(`", "`)}"],
valueDescriptor: ${messageDescriptorName},
}
`);
outputContentBuilder.push(...indexContentList);
}
function validateFieldAndNeedsToBeIndexed(fieldName, fieldToDefinitions, definitionFinder, excludedIndexes) {
if (!fieldToDefinitions.has(fieldName)) {
throw new Error(`Field ${fieldName} is not defined and cannot be used to be ordered by ` +
`or filtered by.`);
}
let fieldDefinition = fieldToDefinitions.get(fieldName);
if (PRIMITIVE_TYPES.has(fieldDefinition.type)) {
excludedIndexes.delete(fieldName);
return { fieldDefinition, isEnum: false };
}
else {
let typeDefinition = definitionFinder.getDefinition(fieldDefinition.type, fieldDefinition.import);
if (!typeDefinition || !typeDefinition.enum) {
throw new Error(`${fieldName} is of ${fieldDefinition.type} which cannot be used to be ordered by or filtered by in Datastore.`);
}
excludedIndexes.delete(fieldName);
return { fieldDefinition, isEnum: true };
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YXN0b3JlX21vZGVsX2dlbmVyYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImRhdGFzdG9yZV9tb2RlbF9nZW5lcmF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUE2QkEsd0RBK0pDO0FBNUxELDZCQUE4QjtBQVU5QixpQ0FPZ0I7QUFFaEIsSUFBSSxpQkFBaUIsR0FBRyxJQUFJLEdBQUcsQ0FBaUI7SUFDOUMsQ0FBQyxHQUFHLEVBQUUsU0FBUyxDQUFDO0lBQ2hCLENBQUMsR0FBRyxFQUFFLGFBQWEsQ0FBQztJQUNwQixDQUFDLEdBQUcsRUFBRSxVQUFVLENBQUM7SUFDakIsQ0FBQyxJQUFJLEVBQUUsc0JBQXNCLENBQUM7SUFDOUIsQ0FBQyxJQUFJLEVBQUUsbUJBQW1CLENBQUM7Q0FDNUIsQ0FBQyxDQUFDO0FBRUgsSUFBSSxlQUFlLEdBQUcsSUFBSSxHQUFHLENBQVMsQ0FBQyxRQUFRLEVBQUUsUUFBUSxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUM7QUFFdkUsU0FBZ0Isc0JBQXNCLENBQ3BDLFVBQWtCLEVBQ2xCLFdBQW1CLEVBQ25CLGlCQUFvQyxFQUNwQyxnQkFBa0MsRUFDbEMsWUFBbUMsRUFDbkMsVUFBNkM7SUFFN0MsSUFBSSxVQUFVLEdBQUcsSUFBQSxtQ0FBNEIsRUFDM0MsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQ2IsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLEVBQzlCLGlCQUFpQixDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQ25DLENBQ0YsQ0FBQztJQUNGLElBQUksb0JBQW9CLEdBQUcsNkNBQW9CLENBQUMsR0FBRyxDQUFDLFVBQVUsRUFBRSxVQUFVLENBQUMsQ0FBQztJQUM1RSxJQUFJLGlCQUFpQixHQUFHLElBQUEsb0JBQWEsRUFBQyxVQUFVLEVBQUUsVUFBVSxDQUFDLENBQUM7SUFDOUQsSUFBSSxxQkFBcUIsR0FBRyxJQUFBLHdCQUFpQixFQUFDLFdBQVcsQ0FB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QUFDO0lBQzVDLENBQUM7U0FBTSxDQUFDO1FBQ04sSUFBSSxjQUFjLEdBQUcsZ0JBQWdCLENBQUMsYUFBYSxDQUNqRCxlQUFlLENBQUMsSUFBSSxFQUNwQixlQUFlLENBQUMsTUFBTSxDQUN2QixDQUFDO1FBQ0YsSUFBSSxDQUFDLGNBQWMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUM1QyxNQUFNLElBQUksS0FBSyxDQUNiLEdBQUcsU0FBUyxVQUFVLGVBQWUsQ0FBQyxJQUFJLHFFQUFxRSxDQUNoSCxDQUFDO1FBQ0osQ0FBQztRQUVELGVBQWUsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDbEMsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLENBQUM7SUFDM0MsQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgcGF0aCA9IHJlcXVpcmUoXCJwYXRoXCIpO1xuaW1wb3J0IHsgRGF0YXN0b3JlSW5kZXhCdWlsZGVyIH0gZnJvbSBcIi4vZGF0YXN0b3JlX2luZGV4X2J1aWxkZXJcIjtcbmltcG9ydCB7XG4gIERhdGFzdG9yZUZpbHRlclRlbXBsYXRlLFxuICBEYXRhc3RvcmVPcmRlcmluZyxcbiAgTWVzc2FnZURlZmluaXRpb24sXG4gIE1lc3NhZ2VGaWVsZERlZmluaXRpb24sXG59IGZyb20gXCIuL2RlZmluaXRpb25cIjtcbmltcG9ydCB7IERlZmluaXRpb25GaW5kZXIgfSBmcm9tIFwiLi9kZWZpbml0aW9uX2ZpbmRlclwiO1xuaW1wb3J0IHsgT3V0cHV0Q29udGVudEJ1aWxkZXIgfSBmcm9tIFwiLi9vdXRwdXRfY29udGVudF9idWlsZGVyXCI7XG5pbXBvcnQge1xuICBnZW5lcmF0ZUNvbW1lbnQsXG4gIG5vcm1hbGl6ZVJlbGF0aXZlUGF0aEZvck5vZGUsXG4gIHJldmVyc2VJbXBvcnQsXG4gIHRvSW5pdGlhbFVwcGVyY2FzZWQsXG4gIHRvVXBwZXJjYXNlU25ha2VkLFxuICB0cmFuc2l0SW1wb3J0LFxufSBmcm9tIFwiLi91dGlsXCI7XG5cbmxldCBPUEVSQVRPUl9OQU1FX01BUCA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmc+KFtcbiAgW1wiPVwiLCBcImVxdWFsVG9cIl0sXG4gIFtcIj5cIiwgXCJncmVhdGVyVGhhblwiXSxcbiAgW1wiPFwiLCBcImxlc3NUaGFuXCJdLFxuICBbXCI+PVwiLCBcImdyZWF0ZXJUaGFuT3JFcXVhbFRvXCJdLFxuICBbXCI8PVwiLCBcImxlc3NUaGFuT3JFcXVhbFRvXCJdLFxuXSk7XG5cbmxldCBQUklNSVRJVkVfVFlQRVMgPSBuZXcgU2V0PHN0cmluZz4oW1wic3RyaW5nXCIsIFwibnVtYmVyXCIsIFwiYm9vbGVhblwiXSk7XG5cbmV4cG9ydCBmdW5jdGlvbiBnZW5lcmF0ZURhdGFzdG9yZU1vZGVsKFxuICBtb2R1bGVQYXRoOiBzdHJpbmcsXG4gIG1lc3NhZ2VOYW1lOiBzdHJpbmcsXG4gIG1lc3NhZ2VEZWZpbml0aW9uOiBNZXNzYWdlRGVmaW5pdGlvbixcbiAgZGVmaW5pdGlvbkZpbmRlcjogRGVmaW5pdGlvbkZpbmRlcixcbiAgaW5kZXhCdWlsZGVyOiBEYXRhc3RvcmVJbmRleEJ1aWxkZXIsXG4gIGNvbnRlbnRNYXA6IE1hcDxzdHJpbmcsIE91dHB1dENvbnRlbnRCdWlsZGVyPixcbik6IHZvaWQge1xuICBsZXQgb3V0cHV0UGF0aCA9IG5vcm1hbGl6ZVJlbGF0aXZlUGF0aEZvck5vZGUoXG4gICAgcGF0aC5wb3NpeC5qb2luKFxuICAgICAgcGF0aC5wb3NpeC5kaXJuYW1lKG1vZHVsZVBhdGgpLFxuICAgICAgbWVzc2FnZURlZmluaXRpb24uZGF0YXN0b3JlLm91dHB1dCxcbiAgICApLFxuICApO1xuICBsZXQgb3V0cHV0Q29udGVudEJ1aWxkZXIgPSBPdXRwdXRDb250ZW50QnVpbGRlci5nZXQoY29udGVudE1hcCwgb3V0cHV0UGF0aCk7XG4gIGxldCBpbXBvcnRNZXNzYWdlUGF0aCA9IHJldmVyc2VJbXBvcnQobW9kdWxlUGF0aCwgb3V0cHV0UGF0aCk7XG4gIGxldCBtZXNzYWdlRGVzY3JpcHRvck5hbWUgPSB0b1VwcGVyY2FzZVNuYWtlZChtZXNzYWdlTmFtZSk7XG5cbiAgbGV0IGZpZWxkVG9EZWZpbml0aW9ucyA9IG5ldyBNYXA8c3RyaW5nLCBNZXNzYWdlRmllbGREZWZpbml0aW9uPigpO1xuICBsZXQgZXhjbHVkZWRJbmRleGVzID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gIGZvciAobGV0IGZpZWxkIG9mIG1lc3NhZ2VEZWZpbml0aW9uLmZpZWxkcykge1xuICAgIGZpZWxkVG9EZWZpbml0aW9ucy5zZXQoZmllbGQubmFtZSwgZmllbGQpO1xuICAgIGV4Y2x1ZGVkSW5kZXhlcy5hZGQoZmllbGQubmFtZSk7XG4gIH1cblxuICBsZXQgaW5kZXhDb250ZW50TGlzdCA9IG5ldyBBcnJheTxzdHJpbmc+KCk7XG4gIGlmIChtZXNzYWdlRGVmaW5pdGlvbi5kYXRhc3RvcmUucXVlcmllcykge1xuICAgIGZvciAobGV0IHF1ZXJ5IG9mIG1lc3NhZ2VEZWZpbml0aW9uLmRhdGFzdG9yZS5xdWVyaWVzKSB7XG4gICAgICBpZiAoIXF1ZXJ5LmZpbHRlcnMpIHtcbiAgICAgICAgcXVlcnkuZmlsdGVycyA9IG5ldyBBcnJheTxEYXRhc3RvcmVGaWx0ZXJUZW1wbGF0ZT4oKTtcbiAgICAgIH1cbiAgICAgIGlmICghcXVlcnkub3JkZXJpbmdzKSB7XG4gICAgICAgIHF1ZXJ5Lm9yZGVyaW5ncyA9IG5ldyBBcnJheTxEYXRhc3RvcmVPcmRlcmluZz4oKTtcbiAgICAgIH1cbiAgICAgIGxldCBpbmVxdWFsaXR5RmlsdGVyZWRGaWVsZE5hbWU6IHN0cmluZztcbiAgICAgIGZvciAobGV0IGZpbHRlciBvZiBxdWVyeS5maWx0ZXJzKSB7XG4gICAgICAgIGlmICghT1BFUkFUT1JfTkFNRV9NQVAuaGFzKGZpbHRlci5vcGVyYXRvcikpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICBgVW5rbm93biBvcGVyYXRvciAke2ZpbHRlci5vcGVyYXRvcn0gb24gcXVlcnkgJHtxdWVyeS5uYW1lfS5gLFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGZpbHRlci5vcGVyYXRvciAhPT0gXCI9XCIpIHtcbiAgICAgICAgICBpZiAoIWluZXF1YWxpdHlGaWx0ZXJlZEZpZWxkTmFtZSkge1xuICAgICAgICAgICAgaW5lcXVhbGl0eUZpbHRlcmVkRmllbGROYW1lID0gZmlsdGVyLmZpZWxkTmFtZTtcbiAgICAgICAgICB9IGVsc2UgaWYgKGluZXF1YWxpdHlGaWx0ZXJlZEZpZWxkTmFtZSAhPT0gZmlsdGVyLmZpZWxkTmFtZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgICBgTW9yZSB0aGFuIDEgZmllbGRzIGFyZSB1c2VkIGluIGluZXF1YWxpdHkgZmlsdGVycyBpbiBxdWVyeSBgICtcbiAgICAgICAgICAgICAgICBgJHtxdWVyeS5uYW1lfSB3aGljaCBpcyBub3QgYWxsb3dlZCBieSBEYXRhc3RvcmUuYCxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGluZGV4QnVpbGRlci5hZGRJbmRleChtZXNzYWdlTmFtZSwgcXVlcnkpO1xuICAgICAgb3V0cHV0Q29udGVudEJ1aWxkZXIuaW1wb3J0RnJvbURhdGFzdG9yZU1vZGVsRGVzY3JpcHRvcihcbiAgICAgICAgXCJEYXRhc3RvcmVRdWVyeVwiLFxuICAgICAgICBcIkRhdGFzdG9yZUZpbHRlclwiLFxuICAgICAgKTtcbiAgICAgIGluZGV4Q29udGVudExpc3QucHVzaChgJHtnZW5lcmF0ZUNvbW1lbnQocXVlcnkuY29tbWVudCl9XG5leHBvcnQgY2xhc3MgJHtxdWVyeS5uYW1lfVF1ZXJ5QnVpbGRlciB7XG4gIHByaXZhdGUgZGF0YXN0b3JlUXVlcnk6IERhdGFzdG9yZVF1ZXJ5PCR7bWVzc2FnZU5hbWV9PiA9IHtcbiAgICBtb2RlbERlc2NyaXB0b3I6ICR7bWVzc2FnZURlc2NyaXB0b3JOYW1lfV9NT0RFTCxcbiAgICBmaWx0ZXJzOiBuZXcgQXJyYXk8RGF0YXN0b3JlRmlsdGVyPigpLFxuICAgIG9yZGVyaW5nczogW2ApO1xuICAgICAgZm9yIChsZXQgb3JkZXJpbmcgb2YgcXVlcnkub3JkZXJpbmdzKSB7XG4gICAgICAgIHZhbGlkYXRlRmllbGRBbmROZWVkc1RvQmVJbmRleGVkKFxuICAgICAgICAgIG9yZGVyaW5nLmZpZWxkTmFtZSxcbiAgICAgICAgICBmaWVsZFRvRGVmaW5pdGlvbnMsXG4gICAgICAgICAgZGVmaW5pdGlvbkZpbmRlcixcbiAgICAgICAgICBleGNsdWRlZEluZGV4ZXMsXG4gICAgICAgICk7XG4gICAgICAgIGluZGV4Q29udGVudExpc3QucHVzaChgXG4gICAgICB7XG4gICAgICAgIGZpZWxkTmFtZTogXCIke29yZGVyaW5nLmZpZWxkTmFtZX1cIixcbiAgICAgICAgZGVzY2VuZGluZzogJHtvcmRlcmluZy5kZXNjZW5kaW5nfVxuICAgICAgfSxgKTtcbiAgICAgICAgZXhjbHVkZWRJbmRleGVzLmRlbGV0ZShvcmRlcmluZy5maWVsZE5hbWUpO1xuICAgICAgfVxuICAgICAgaW5kZXhDb250ZW50TGlzdC5wdXNoKGBcbiAgICBdXG4gIH07XG5cbiAgcHVibGljIHN0YXJ0KGN1cnNvcjogc3RyaW5nKTogdGhpcyB7XG4gICAgdGhpcy5kYXRhc3RvcmVRdWVyeS5zdGFydEN1cnNvciA9IGN1cnNvcjtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuICBwdWJsaWMgbGltaXQobnVtOiBudW1iZXIpOiB0aGlzIHtcbiAgICB0aGlzLmRhdGFzdG9yZVF1ZXJ5LmxpbWl0ID0gbnVtO1xuICAgIHJldHVybiB0aGlzO1xuICB9YCk7XG4gICAgICBmb3IgKGxldCBmaWx0ZXIgb2YgcXVlcnkuZmlsdGVycykge1xuICAgICAgICBsZXQgeyBmaWVsZERlZmluaXRpb24sIGlzRW51bSB9ID0gdmFsaWRhdGVGaWVsZEFuZE5lZWRzVG9CZUluZGV4ZWQoXG4gICAgICAgICAgZmlsdGVyLmZpZWxkTmFtZSxcbiAgICAgICAgICBmaWVsZFRvRGVmaW5pdGlvbnMsXG4gICAgICAgICAgZGVmaW5pdGlvbkZpbmRlcixcbiAgICAgICAgICBleGNsdWRlZEluZGV4ZXMsXG4gICAgICAgICk7XG4gICAgICAgIGlmIChpc0VudW0pIHtcbiAgICAgICAgICBvdXRwdXRDb250ZW50QnVpbGRlci5pbXBvcnRGcm9tUGF0aChcbiAgICAgICAgICAgIHRyYW5zaXRJbXBvcnQoaW1wb3J0TWVzc2FnZVBhdGgsIGZpZWxkRGVmaW5pdGlvbi5pbXBvcnQpLFxuICAgICAgICAgICAgZmllbGREZWZpbml0aW9uLnR5cGUsXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBpbmRleENvbnRlbnRMaXN0LnB1c2goYFxuICBwdWJsaWMgJHtPUEVSQVRPUl9OQU1FX01BUC5nZXQoZmlsdGVyLm9wZXJhdG9yKX0ke3RvSW5pdGlhbFVwcGVyY2FzZWQoXG4gICAgZmlsdGVyLmZpZWxkTmFtZSxcbiAgKX0odmFsdWU6ICR7ZmllbGREZWZpbml0aW9uLnR5cGV9KTogdGhpcyB7XG4gICAgdGhpcy5kYXRhc3RvcmVRdWVyeS5maWx0ZXJzLnB1c2goe1xuICAgICAgZmllbGROYW1lOiBcIiR7ZmlsdGVyLmZpZWxkTmFtZX1cIixcbiAgICAgIGZpZWxkVmFsdWU6IHZhbHVlLFxuICAgICAgb3BlcmF0b3I6IFwiJHtmaWx0ZXIub3BlcmF0b3J9XCIsXG4gICAgfSk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1gKTtcbiAgICAgIH1cbiAgICAgIGluZGV4Q29udGVudExpc3QucHVzaChgXG4gIHB1YmxpYyBidWlsZCgpOiBEYXRhc3RvcmVRdWVyeTwke21lc3NhZ2VOYW1lfT4ge1xuICAgIHJldHVybiB0aGlzLmRhdGFzdG9yZVF1ZXJ5O1xuICB9XG59XG5gKTtcbiAgICB9XG4gIH1cblxuICBsZXQga2V5RGVmaW5pdGlvbiA9IGZpZWxkVG9EZWZpbml0aW9ucy5nZXQobWVzc2FnZURlZmluaXRpb24uZGF0YXN0b3JlLmtleSk7XG4gIGlmICgha2V5RGVmaW5pdGlvbikge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBEYXRhc3RvcmUga2V5ICR7bWVzc2FnZURlZmluaXRpb24uZGF0YXN0b3JlLmtleX0gaXMgbm90IGZvdW5kIGZyb20gYCArXG4gICAgICAgIGAke21lc3NhZ2VOYW1lfS5gLFxuICAgICk7XG4gIH1cbiAgaWYgKGtleURlZmluaXRpb24udHlwZSAhPT0gXCJzdHJpbmdcIikge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBEYXRhc3RvcmUga2V5IGNhbiBvbmx5IGJlIGEgc3RyaW5nLCBidXQgaXQgaXMgYCArXG4gICAgICAgIGAke2tleURlZmluaXRpb24udHlwZX0uYCxcbiAgICApO1xuICB9XG4gIGlmIChrZXlEZWZpbml0aW9uLmlzQXJyYXkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYERhdGFzdG9yZSBrZXkgY2Fubm90IGJlIGFuIGFycmF5LmApO1xuICB9XG4gIG91dHB1dENvbnRlbnRCdWlsZGVyLmltcG9ydEZyb21QYXRoKFxuICAgIGltcG9ydE1lc3NhZ2VQYXRoLFxuICAgIG1lc3NhZ2VOYW1lLFxuICAgIG1lc3NhZ2VEZXNjcmlwdG9yTmFtZSxcbiAgKTtcbiAgb3V0cHV0Q29udGVudEJ1aWxkZXIuaW1wb3J0RnJvbURhdGFzdG9yZU1vZGVsRGVzY3JpcHRvcihcbiAgICBcIkRhdGFzdG9yZU1vZGVsRGVzY3JpcHRvclwiLFxuICApO1xuICBvdXRwdXRDb250ZW50QnVpbGRlci5wdXNoKGAke2dlbmVyYXRlQ29tbWVudChcbiAgICBtZXNzYWdlRGVmaW5pdGlvbi5kYXRhc3RvcmUuY29tbWVudCxcbiAgKX1cbmV4cG9ydCBsZXQgJHttZXNzYWdlRGVzY3JpcHRvck5hbWV9X01PREVMOiBEYXRhc3RvcmVNb2RlbERlc2NyaXB0b3I8JHttZXNzYWdlTmFtZX0+ID0ge1xuICBuYW1lOiBcIiR7bWVzc2FnZU5hbWV9XCIsXG4gIGtleTogXCIke21lc3NhZ2VEZWZpbml0aW9uLmRhdGFzdG9yZS5rZXl9XCIsXG4gIGV4Y2x1ZGVkSW5kZXhlczogW1wiJHtBcnJheS5mcm9tKGV4Y2x1ZGVkSW5kZXhlcykuam9pbihgXCIsIFwiYCl9XCJdLFxuICB2YWx1ZURlc2NyaXB0b3I6ICR7bWVzc2FnZURlc2NyaXB0b3JOYW1lfSxcbn1cbmApO1xuICBvdXRwdXRDb250ZW50QnVpbGRlci5wdXNoKC4uLmluZGV4Q29udGVudExpc3QpO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZUZpZWxkQW5kTmVlZHNUb0JlSW5kZXhlZChcbiAgZmllbGROYW1lOiBzdHJpbmcsXG4gIGZpZWxkVG9EZWZpbml0aW9uczogTWFwPHN0cmluZywgTWVzc2FnZUZpZWxkRGVmaW5pdGlvbj4sXG4gIGRlZmluaXRpb25GaW5kZXI6IERlZmluaXRpb25GaW5kZXIsXG4gIGV4Y2x1ZGVkSW5kZXhlczogU2V0PHN0cmluZz4sXG4pOiB7IGZpZWxkRGVmaW5pdGlvbjogTWVzc2FnZUZpZWxkRGVmaW5pdGlvbjsgaXNFbnVtOiBib29sZWFuIH0ge1xuICBpZiAoIWZpZWxkVG9EZWZpbml0aW9ucy5oYXMoZmllbGROYW1lKSkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgIGBGaWVsZCAke2ZpZWxkTmFtZX0gaXMgbm90IGRlZmluZWQgYW5kIGNhbm5vdCBiZSB1c2VkIHRvIGJlIG9yZGVyZWQgYnkgYCArXG4gICAgICAgIGBvciBmaWx0ZXJlZCBieS5gLFxuICAgICk7XG4gIH1cblxuICBsZXQgZmllbGREZWZpbml0aW9uID0gZmllbGRUb0RlZmluaXRpb25zLmdldChmaWVsZE5hbWUpO1xuICBpZiAoUFJJTUlUSVZFX1RZUEVTLmhhcyhmaWVsZERlZmluaXRpb24udHlwZSkpIHtcbiAgICBleGNsdWRlZEluZGV4ZXMuZGVsZXRlKGZpZWxkTmFtZSk7XG4gICAgcmV0dXJuIHsgZmllbGREZWZpbml0aW9uLCBpc0VudW06IGZhbHNlIH07XG4gIH0gZWxzZSB7XG4gICAgbGV0IHR5cGVEZWZpbml0aW9uID0gZGVmaW5pdGlvbkZpbmRlci5nZXREZWZpbml0aW9uKFxuICAgICAgZmllbGREZWZpbml0aW9uLnR5cGUsXG4gICAgICBmaWVsZERlZmluaXRpb24uaW1wb3J0LFxuICAgICk7XG4gICAgaWYgKCF0eXBlRGVmaW5pdGlvbiB8fCAhdHlwZURlZmluaXRpb24uZW51bSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgJHtmaWVsZE5hbWV9IGlzIG9mICR7ZmllbGREZWZpbml0aW9uLnR5cGV9IHdoaWNoIGNhbm5vdCBiZSB1c2VkIHRvIGJlIG9yZGVyZWQgYnkgb3IgZmlsdGVyZWQgYnkgaW4gRGF0YXN0b3JlLmAsXG4gICAgICApO1xuICAgIH1cblxuICAgIGV4Y2x1ZGVkSW5kZXhlcy5kZWxldGUoZmllbGROYW1lKTtcbiAgICByZXR1cm4geyBmaWVsZERlZmluaXRpb24sIGlzRW51bTogdHJ1ZSB9O1xuICB9XG59XG4iXX0=