UNPKG

grind-http

Version:
264 lines (205 loc) 31.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ResourceRouteBuilder = void 0; var _grindSupport = require("grind-support"); function _isnil(val) { return val === null || typeof val === 'undefined'; } // // Adapted from Laravel: // https://github.com/laravel/framework/blob/b75aca6a203590068161835945213fd1a39c7080/src/Illuminate/Routing/ResourceRegistrar.php // class ResourceRouteBuilder { constructor(routes) { this.routes = null; this.resourceDefaults = ['index', 'create', 'store', 'show', 'edit', 'update', 'destroy']; this.parameters = null; this.routes = routes; } buildRoutes(name, controller, options = {}, callback = null) { if (typeof options === 'function') { callback = options; options = {}; } if (!_isnil(options.parameters) && !_isnil(this.parameters)) { this.parameters = options.parameters; } // If the resource name contains a slash, we will assume the developer wishes to // register these resource routes with a prefix so we will set that up out of // the box so they don't have to mess with it. Otherwise, we will continue. if (name.indexOf('/') >= 0) { return this._prefixedResource(name, controller, options, callback); } // We need to extract the base resource from the resource name. Nested resources // are supported in the framework, but we need to know what name to use for a // placeholder on the route parameters, which should be the base resources. const segments = name.split(/\./); const base = this.getResourceWildcard(segments[segments.length - 1]); return this.routes.group({ controller, prefix: this.getResourceUri(name), before: options.before, after: options.after }, routes => { if (typeof callback === 'function') { callback(routes, controller); } for (const m of this._getResourceMethods(this.resourceDefaults, options)) { const method = `_addResource${m.substring(0, 1).toUpperCase()}${m.substring(1)}`; this[method](name, base, controller, options); } }); } _prefixedResource(name, controller, options = {}, callback = null) { const { name: segment, prefix } = this._getResourcePrefix(name); // We need to extract the base resource from the resource name. Nested resources // are supported in the framework, but we need to know what name to use for a // placeholder on the route parameters, which should be the base resources. return this.routes.group({ prefix }, () => { this.buildRoutes(segment, controller, options, callback); }); } _getResourcePrefix(name) { const segments = name.split(/\//); // To get the prefix, we will take all of the name segments and implode them on // a slash. This will generate a proper URI prefix fors us. Then we take this // last segment, which will be considered the final resources name we use. const prefix = segments.slice(0, -1).join('/'); return { name: segments[segments.length - 1], prefix }; } _getResourceMethods(defaults, options) { if (!_isnil(options.only)) { return defaults.filter(method => options.only.indexOf(method) >= 0); } else if (!_isnil(options.except)) { return defaults.filter(method => options.except.indexOf(method) === -1); } return defaults; } _addResourceIndex(name, base, controller, options) { const action = this._getResourceAction(name, controller, 'index', options); if (typeof controller[action.method] !== 'function') { return null; } return this.routes.get('', action); } _addResourceCreate(name, base, controller, options) { const action = this._getResourceAction(name, controller, 'create', options); if (typeof controller[action.method] !== 'function') { return null; } return this.routes.get(this.constructor.verbs.create, action); } _addResourceStore(name, base, controller, options) { const action = this._getResourceAction(name, controller, 'store', options); if (typeof controller[action.method] !== 'function') { return null; } return this.routes.post('', action); } _addResourceShow(name, base, controller, options) { const action = this._getResourceAction(name, controller, 'show', options); if (typeof controller[action.method] !== 'function') { return null; } return this.routes.get(`:${base}`, action); } _addResourceEdit(name, base, controller, options) { const action = this._getResourceAction(name, controller, 'edit', options); if (typeof controller[action.method] !== 'function') { return null; } return this.routes.get(`:${base}/${this.constructor.verbs.edit}`, action); } _addResourceUpdate(name, base, controller, options) { const action = this._getResourceAction(name, controller, 'update', options); if (typeof controller[action.method] !== 'function') { return null; } return this.routes.match(['put', 'patch'], `:${base}`, action); } _addResourceDestroy(name, base, controller, options) { const action = this._getResourceAction(name, controller, 'destroy', options); if (typeof controller[action.method] !== 'function') { return null; } return this.routes.delete(`:${base}`, action); } getResourceUri(resource) { if (resource.indexOf('.') === -1) { return resource; } // Once we have built the base URI, we'll remove the parameter holder for this // base resource name so that the individual route adders can suffix these // paths however they need to, as some do not have any parameters at all. const segments = resource.split(/\./); const uri = this._getNestedResourceUri(segments); return uri.replace(`/:${this.getResourceWildcard(segments[segments.length - 1])}`, ''); } _getNestedResourceUri(segments) { // We will spin through the segments and create a placeholder for each of the // resource segments, as well as the resource itself. Then we should get an // entire string for the resource URI that contains all nested resources. return segments.map(s => `${s}/:${this.getResourceWildcard(s)}`).join('/'); } getResourceWildcard(value) { if (!_isnil(this.parameters) && !_isnil(this.parameters)[value]) { value = this.parameters[value]; } else if (!_isnil(this.constructor.parameterMap) && !_isnil(this.constructor.parameterMap[value])) { value = this.constructor.parameterMap[value]; } else if (this.parameters === 'singular' || this.constructor.singularParameters) { value = _grindSupport.Inflect.singularize(value); } return value.replace(/-/g, '_'); } _getResourceAction(resource, controller, method, options) { return { as: this._getResourceRouteName(resource, method, options), method: method }; } _getResourceRouteName(resource, method, options) { let name = resource; // If the names array has been provided to us we will check for an entry in the // array first. We will also check for the specific method within this array // so the names may be specified on a more "granular" level using methods. if (!_isnil(options.names)) { if (typeof options.names === 'string') { name = options.names; } else if (!_isnil(options.names[method])) { return options.names[method]; } } // If a global prefix has been assigned to all names for this resource, we will // grab that so we can prepend it onto the name when we create this name for // the resource action. Otherwise we'll just use an empty string for here. const prefix = !_isnil(options.as) ? `${options.as}.` : ''; return `${prefix}${name}.${method}`.replace(/(^\.|\.$)/g, ''); } static singularParameters(singular = true) { this.singularParameters = singular; } static getParameters() { return [...this.parameterMap]; } static setParameters(parameters = []) { this.parameterMap = [...parameters]; } static verbs(verbs = {}) { if (Object.keys(verbs).length === 0) { return { ...this.verbs }; } this.verbs = { ...this.verbs, ...verbs }; } } exports.ResourceRouteBuilder = ResourceRouteBuilder; ResourceRouteBuilder.parameterMap = []; ResourceRouteBuilder.singularParameters = true; ResourceRouteBuilder.verbs = { create: 'create', edit: 'edit' }; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9Sb3V0aW5nL1Jlc291cmNlUm91dGVCdWlsZGVyLmpzIl0sIm5hbWVzIjpbIlJlc291cmNlUm91dGVCdWlsZGVyIiwiY29uc3RydWN0b3IiLCJyb3V0ZXMiLCJyZXNvdXJjZURlZmF1bHRzIiwicGFyYW1ldGVycyIsImJ1aWxkUm91dGVzIiwibmFtZSIsImNvbnRyb2xsZXIiLCJvcHRpb25zIiwiY2FsbGJhY2siLCJpbmRleE9mIiwiX3ByZWZpeGVkUmVzb3VyY2UiLCJzZWdtZW50cyIsInNwbGl0IiwiYmFzZSIsImdldFJlc291cmNlV2lsZGNhcmQiLCJsZW5ndGgiLCJncm91cCIsInByZWZpeCIsImdldFJlc291cmNlVXJpIiwiYmVmb3JlIiwiYWZ0ZXIiLCJtIiwiX2dldFJlc291cmNlTWV0aG9kcyIsIm1ldGhvZCIsInN1YnN0cmluZyIsInRvVXBwZXJDYXNlIiwic2VnbWVudCIsIl9nZXRSZXNvdXJjZVByZWZpeCIsInNsaWNlIiwiam9pbiIsImRlZmF1bHRzIiwib25seSIsImZpbHRlciIsImV4Y2VwdCIsIl9hZGRSZXNvdXJjZUluZGV4IiwiYWN0aW9uIiwiX2dldFJlc291cmNlQWN0aW9uIiwiZ2V0IiwiX2FkZFJlc291cmNlQ3JlYXRlIiwidmVyYnMiLCJjcmVhdGUiLCJfYWRkUmVzb3VyY2VTdG9yZSIsInBvc3QiLCJfYWRkUmVzb3VyY2VTaG93IiwiX2FkZFJlc291cmNlRWRpdCIsImVkaXQiLCJfYWRkUmVzb3VyY2VVcGRhdGUiLCJtYXRjaCIsIl9hZGRSZXNvdXJjZURlc3Ryb3kiLCJkZWxldGUiLCJyZXNvdXJjZSIsInVyaSIsIl9nZXROZXN0ZWRSZXNvdXJjZVVyaSIsInJlcGxhY2UiLCJtYXAiLCJzIiwidmFsdWUiLCJwYXJhbWV0ZXJNYXAiLCJzaW5ndWxhclBhcmFtZXRlcnMiLCJJbmZsZWN0Iiwic2luZ3VsYXJpemUiLCJhcyIsIl9nZXRSZXNvdXJjZVJvdXRlTmFtZSIsIm5hbWVzIiwic2luZ3VsYXIiLCJnZXRQ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QUFFRCxTQUFPUyxhQUFQLENBQXFCL0QsVUFBVSxHQUFHLEVBQWxDLEVBQXNDO0FBQ3JDLFNBQUtzRCxZQUFMLEdBQW9CLENBQUMsR0FBR3RELFVBQUosQ0FBcEI7QUFDQTs7QUFFRCxTQUFPb0MsS0FBUCxDQUFhQSxLQUFLLEdBQUcsRUFBckIsRUFBeUI7QUFDeEIsUUFBSTRCLE1BQU0sQ0FBQ0MsSUFBUCxDQUFZN0IsS0FBWixFQUFtQnhCLE1BQW5CLEtBQThCLENBQWxDLEVBQXFDO0FBQ3BDLGFBQU8sRUFBRSxHQUFHLEtBQUt3QjtBQUFWLE9BQVA7QUFDQTs7QUFFRCxTQUFLQSxLQUFMLEdBQWEsRUFBRSxHQUFHLEtBQUtBLEtBQVY7QUFBaUIsU0FBR0E7QUFBcEIsS0FBYjtBQUNBOztBQXRQZ0M7OztBQUFyQnhDLG9CLENBS0wwRCxZLEdBQWUsRTtBQUxWMUQsb0IsQ0FNTDJELGtCLEdBQXFCLEk7QUFOaEIzRCxvQixDQU9Md0MsSyxHQUFRO0FBQ2RDLEVBQUFBLE1BQU0sRUFBRSxRQURNO0FBRWRLLEVBQUFBLElBQUksRUFBRTtBQUZRLEMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmZsZWN0IH0gZnJvbSAnZ3JpbmQtc3VwcG9ydCdcblxuLy9cbi8vIEFkYXB0ZWQgZnJvbSBMYXJhdmVsOlxuLy8gaHR0cHM6Ly9naXRodWIuY29tL2xhcmF2ZWwvZnJhbWV3b3JrL2Jsb2IvYjc1YWNhNmEyMDM1OTAwNjgxNjE4MzU5NDUyMTNmZDFhMzljNzA4MC9zcmMvSWxsdW1pbmF0ZS9Sb3V0aW5nL1Jlc291cmNlUmVnaXN0cmFyLnBocFxuLy9cblxuZXhwb3J0IGNsYXNzIFJlc291cmNlUm91dGVCdWlsZGVyIHtcblx0cm91dGVzID0gbnVsbFxuXHRyZXNvdXJjZURlZmF1bHRzID0gWydpbmRleCcsICdjcmVhdGUnLCAnc3RvcmUnLCAnc2hvdycsICdlZGl0JywgJ3VwZGF0ZScsICdkZXN0cm95J11cblx0cGFyYW1ldGVycyA9IG51bGxcblxuXHRzdGF0aWMgcGFyYW1ldGVyTWFwID0gW11cblx0c3RhdGljIHNpbmd1bGFyUGFyYW1ldGVycyA9IHRydWVcblx0c3RhdGljIHZlcmJzID0ge1xuXHRcdGNyZWF0ZTogJ2NyZWF0ZScsXG5cdFx0ZWRpdDogJ2VkaXQnLFxuXHR9XG5cblx0Y29uc3RydWN0b3Iocm91dGVzKSB7XG5cdFx0dGhpcy5yb3V0ZXMgPSByb3V0ZXNcblx0fVxuXG5cdGJ1aWxkUm91dGVzKG5hbWUsIGNvbnRyb2xsZXIsIG9wdGlvbnMgPSB7fSwgY2FsbGJhY2sgPSBudWxsKSB7XG5cdFx0aWYgKHR5cGVvZiBvcHRpb25zID09PSAnZnVuY3Rpb24nKSB7XG5cdFx0XHRjYWxsYmFjayA9IG9wdGlvbnNcblx0XHRcdG9wdGlvbnMgPSB7fVxuXHRcdH1cblxuXHRcdGlmICghb3B0aW9ucy5wYXJhbWV0ZXJzLmlzTmlsICYmICF0aGlzLnBhcmFtZXRlcnMuaXNOaWwpIHtcblx0XHRcdHRoaXMucGFyYW1ldGVycyA9IG9wdGlvbnMucGFyYW1ldGVyc1xuXHRcdH1cblxuXHRcdC8vIElmIHRoZSByZXNvdXJjZSBuYW1lIGNvbnRhaW5zIGEgc2xhc2gsIHdlIHdpbGwgYXNzdW1lIHRoZSBkZXZlbG9wZXIgd2lzaGVzIHRvXG5cdFx0Ly8gcmVnaXN0ZXIgdGhlc2UgcmVzb3VyY2Ugcm91dGVzIHdpdGggYSBwcmVmaXggc28gd2Ugd2lsbCBzZXQgdGhhdCB1cCBvdXQgb2Zcblx0XHQvLyB0aGUgYm94IHNvIHRoZXkgZG9uJ3QgaGF2ZSB0byBtZXNzIHdpdGggaXQuIE90aGVyd2lzZSwgd2Ugd2lsbCBjb250aW51ZS5cblx0XHRpZiAobmFtZS5pbmRleE9mKCcvJykgPj0gMCkge1xuXHRcdFx0cmV0dXJuIHRoaXMuX3ByZWZpeGVkUmVzb3VyY2UobmFtZSwgY29udHJvbGxlciwgb3B0aW9ucywgY2FsbGJhY2spXG5cdFx0fVxuXG5cdFx0Ly8gV2UgbmVlZCB0byBleHRyYWN0IHRoZSBiYXNlIHJlc291cmNlIGZyb20gdGhlIHJlc291cmNlIG5hbWUuIE5lc3RlZCByZXNvdXJjZXNcblx0XHQvLyBhcmUgc3VwcG9ydGVkIGluIHRoZSBmcmFtZXdvcmssIGJ1dCB3ZSBuZWVkIHRvIGtub3cgd2hhdCBuYW1lIHRvIHVzZSBmb3IgYVxuXHRcdC8vIHBsYWNlaG9sZGVyIG9uIHRoZSByb3V0ZSBwYXJhbWV0ZXJzLCB3aGljaCBzaG91bGQgYmUgdGhlIGJhc2UgcmVzb3VyY2VzLlxuXHRcdGNvbnN0IHNlZ21lbnRzID0gbmFtZS5zcGxpdCgvXFwuLylcblx0XHRjb25zdCBiYXNlID0gdGhpcy5nZXRSZXNvdXJjZVdpbGRjYXJkKHNlZ21lbnRzW3NlZ21lbnRzLmxlbmd0aCAtIDFdKVxuXG5cdFx0cmV0dXJuIHRoaXMucm91dGVzLmdyb3VwKFxuXHRcdFx0e1xuXHRcdFx0XHRjb250cm9sbGVyLFxuXHRcdFx0XHRwcmVmaXg6IHRoaXMuZ2V0UmVzb3VyY2VVcmkobmFtZSksXG5cdFx0XHRcdGJlZm9yZTogb3B0aW9ucy5iZWZvcmUsXG5cdFx0XHRcdGFmdGVyOiBvcHRpb25zLmFmdGVyLFxuXHRcdFx0fSxcblx0XHRcdHJvdXRlcyA9PiB7XG5cdFx0XHRcdGlmICh0eXBlb2YgY2FsbGJhY2sgPT09ICdmdW5jdGlvbicpIHtcblx0XHRcdFx0XHRjYWxsYmFjayhyb3V0ZXMsIGNvbnRyb2xsZXIpXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRmb3IgKGNvbnN0IG0gb2YgdGhpcy5fZ2V0UmVzb3VyY2VNZXRob2RzKHRoaXMucmVzb3VyY2VEZWZhdWx0cywgb3B0aW9ucykpIHtcblx0XHRcdFx0XHRjb25zdCBtZXRob2QgPSBgX2FkZFJlc291cmNlJHttLnN1YnN0cmluZygwLCAxKS50b1VwcGVyQ2FzZSgpfSR7bS5zdWJzdHJpbmcoMSl9YFxuXHRcdFx0XHRcdHRoaXNbbWV0aG9kXShuYW1lLCBiYXNlLCBjb250cm9sbGVyLCBvcHRpb25zKVxuXHRcdFx0XHR9XG5cdFx0XHR9LFxuXHRcdClcblx0fVxuXG5cdF9wcmVmaXhlZFJlc291cmNlKG5hbWUsIGNvbnRyb2xsZXIsIG9wdGlvbnMgPSB7fSwgY2FsbGJhY2sgPSBudWxsKSB7XG5cdFx0Y29uc3QgeyBuYW1lOiBzZWdtZW50LCBwcmVmaXggfSA9IHRoaXMuX2dldFJlc291cmNlUHJlZml4KG5hbWUpXG5cblx0XHQvLyBXZSBuZWVkIHRvIGV4dHJhY3QgdGhlIGJhc2UgcmVzb3VyY2UgZnJvbSB0aGUgcmVzb3VyY2UgbmFtZS4gTmVzdGVkIHJlc291cmNlc1xuXHRcdC8vIGFyZSBzdXBwb3J0ZWQgaW4gdGhlIGZyYW1ld29yaywgYnV0IHdlIG5lZWQgdG8ga25vdyB3aGF0IG5hbWUgdG8gdXNlIGZvciBhXG5cdFx0Ly8gcGxhY2Vob2xkZXIgb24gdGhlIHJvdXRlIHBhcmFtZXRlcnMsIHdoaWNoIHNob3VsZCBiZSB0aGUgYmFzZSByZXNvdXJjZXMuXG5cdFx0cmV0dXJuIHRoaXMucm91dGVzLmdyb3VwKHsgcHJlZml4IH0sICgpID0+IHtcblx0XHRcdHRoaXMuYnVpbGRSb3V0ZXMoc2VnbWVudCwgY29udHJvbGxlciwgb3B0aW9ucywgY2FsbGJhY2spXG5cdFx0fSlcblx0fVxuXG5cdF9nZXRSZXNvdXJjZVByZWZpeChuYW1lKSB7XG5cdFx0Y29uc3Qgc2VnbWVudHMgPSBuYW1lLnNwbGl0KC9cXC8vKVxuXG5cdFx0Ly8gVG8gZ2V0IHRoZSBwcmVmaXgsIHdlIHdpbGwgdGFrZSBhbGwgb2YgdGhlIG5hbWUgc2VnbWVudHMgYW5kIGltcGxvZGUgdGhlbSBvblxuXHRcdC8vIGEgc2xhc2guIFRoaXMgd2lsbCBnZW5lcmF0ZSBhIHByb3BlciBVUkkgcHJlZml4IGZvcnMgdXMuIFRoZW4gd2UgdGFrZSB0aGlzXG5cdFx0Ly8gbGFzdCBzZWdtZW50LCB3aGljaCB3aWxsIGJlIGNvbnNpZGVyZWQgdGhlIGZpbmFsIHJlc291cmNlcyBuYW1lIHdlIHVzZS5cblx0XHRjb25zdCBwcmVmaXggPSBzZWdtZW50cy5zbGljZSgwLCAtMSkuam9pbignLycpXG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0bmFtZTogc2VnbWVudHNbc2VnbWVudHMubGVuZ3RoIC0gMV0sXG5cdFx0XHRwcmVmaXgsXG5cdFx0fVxuXHR9XG5cblx0X2dldFJlc291cmNlTWV0aG9kcyhkZWZhdWx0cywgb3B0aW9ucykge1xuXHRcdGlmICghb3B0aW9ucy5vbmx5LmlzTmlsKSB7XG5cdFx0XHRyZXR1cm4gZGVmYXVsdHMuZmlsdGVyKG1ldGhvZCA9PiBvcHRpb25zLm9ubHkuaW5kZXhPZihtZXRob2QpID49IDApXG5cdFx0fSBlbHNlIGlmICghb3B0aW9ucy5leGNlcHQuaXNOaWwpIHtcblx0XHRcdHJldHVybiBkZWZhdWx0cy5maWx0ZXIobWV0aG9kID0+IG9wdGlvbnMuZXhjZXB0LmluZGV4T2YobWV0aG9kKSA9PT0gLTEpXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGRlZmF1bHRzXG5cdH1cblxuXHRfYWRkUmVzb3VyY2VJbmRleChuYW1lLCBiYXNlLCBjb250cm9sbGVyLCBvcHRpb25zKSB7XG5cdFx0Y29uc3QgYWN0aW9uID0gdGhpcy5fZ2V0UmVzb3VyY2VBY3Rpb24obmFtZSwgY29udHJvbGxlciwgJ2luZGV4Jywgb3B0aW9ucylcblxuXHRcdGlmICh0eXBlb2YgY29udHJvbGxlclthY3Rpb24ubWV0aG9kXSAhPT0gJ2Z1bmN0aW9uJykge1xuXHRcdFx0cmV0dXJuIG51bGxcblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcy5yb3V0ZXMuZ2V0KCcnLCBhY3Rpb24pXG5cdH1cblxuXHRfYWRkUmVzb3VyY2VDcmVhdGUobmFtZSwgYmFzZSwgY29udHJvbGxlciwgb3B0aW9ucykge1xuXHRcdGNvbnN0IGFjdGlvbiA9IHRoaXMuX2dldFJlc291cmNlQWN0aW9uKG5hbWUsIGNvbnRyb2xsZXIsICdjcmVhdGUnLCBvcHRpb25zKVxuXG5cdFx0aWYgKHR5cGVvZiBjb250cm9sbGVyW2FjdGlvbi5tZXRob2RdICE9PSAnZnVuY3Rpb24nKSB7XG5cdFx0XHRyZXR1cm4gbnVsbFxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLnJvdXRlcy5nZXQodGhpcy5jb25zdHJ1Y3Rvci52ZXJicy5jcmVhdGUsIGFjdGlvbilcblx0fVxuXG5cdF9hZGRSZXNvdXJjZVN0b3JlKG5hbWUsIGJhc2UsIGNvbnRyb2xsZXIsIG9wdGlvbnMpIHtcblx0XHRjb25zdCBhY3Rpb24gPSB0aGlzLl9nZXRSZXNvdXJjZUFjdGlvbihuYW1lLCBjb250cm9sbGVyLCAnc3RvcmUnLCBvcHRpb25zKVxuXG5cdFx0aWYgKHR5cGVvZiBjb250cm9sbGVyW2FjdGlvbi5tZXRob2RdICE9PSAnZnVuY3Rpb24nKSB7XG5cdFx0XHRyZXR1cm4gbnVsbFxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLnJvdXRlcy5wb3N0KCcnLCBhY3Rpb24pXG5cdH1cblxuXHRfYWRkUmVzb3VyY2VTaG93KG5hbWUsIGJhc2UsIGNvbnRyb2xsZXIsIG9wdGlvbnMpIHtcblx0XHRjb25zdCBhY3Rpb24gPSB0aGlzLl9nZXRSZXNvdXJjZUFjdGlvbihuYW1lLCBjb250cm9sbGVyLCAnc2hvdycsIG9wdGlvbnMpXG5cblx0XHRpZiAodHlwZW9mIGNvbnRyb2xsZXJbYWN0aW9uLm1ldGhvZF0gIT09ICdmdW5jdGlvbicpIHtcblx0XHRcdHJldHVybiBudWxsXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXMucm91dGVzLmdldChgOiR7YmFzZX1gLCBhY3Rpb24pXG5cdH1cblxuXHRfYWRkUmVzb3VyY2VFZGl0KG5hbWUsIGJhc2UsIGNvbnRyb2xsZXIsIG9wdGlvbnMpIHtcblx0XHRjb25zdCBhY3Rpb24gPSB0aGlzLl9nZXRSZXNvdXJjZUFjdGlvbihuYW1lLCBjb250cm9sbGVyLCAnZWRpdCcsIG9wdGlvbnMpXG5cblx0XHRpZiAodHlwZW9mIGNvbnRyb2xsZXJbYWN0aW9uLm1ldGhvZF0gIT09ICdmdW5jdGlvbicpIHtcblx0XHRcdHJldHVybiBudWxsXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXMucm91dGVzLmdldChgOiR7YmFzZX0vJHt0aGlzLmNvbnN0cnVjdG9yLnZlcmJzLmVkaXR9YCwgYWN0aW9uKVxuXHR9XG5cblx0X2FkZFJlc291cmNlVXBkYXRlKG5hbWUsIGJhc2UsIGNvbnRyb2xsZXIsIG9wdGlvbnMpIHtcblx0XHRjb25zdCBhY3Rpb24gPSB0aGlzLl9nZXRSZXNvdXJjZUFjdGlvbihuYW1lLCBjb250cm9sbGVyLCAndXBkYXRlJywgb3B0aW9ucylcblxuXHRcdGlmICh0eXBlb2YgY29udHJvbGxlclthY3Rpb24ubWV0aG9kXSAhPT0gJ2Z1bmN0aW9uJykge1xuXHRcdFx0cmV0dXJuIG51bGxcblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcy5yb3V0ZXMubWF0Y2goWydwdXQnLCAncGF0Y2gnXSwgYDoke2Jhc2V9YCwgYWN0aW9uKVxuXHR9XG5cblx0X2FkZFJlc291cmNlRGVzdHJveShuYW1lLCBiYXNlLCBjb250cm9sbGVyLCBvcHRpb25zKSB7XG5cdFx0Y29uc3QgYWN0aW9uID0gdGhpcy5fZ2V0UmVzb3VyY2VBY3Rpb24obmFtZSwgY29udHJvbGxlciwgJ2Rlc3Ryb3knLCBvcHRpb25zKVxuXG5cdFx0aWYgKHR5cGVvZiBjb250cm9sbGVyW2FjdGlvbi5tZXRob2RdICE9PSAnZnVuY3Rpb24nKSB7XG5cdFx0XHRyZXR1cm4gbnVsbFxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLnJvdXRlcy5kZWxldGUoYDoke2Jhc2V9YCwgYWN0aW9uKVxuXHR9XG5cblx0Z2V0UmVzb3VyY2VVcmkocmVzb3VyY2UpIHtcblx0XHRpZiAocmVzb3VyY2UuaW5kZXhPZignLicpID09PSAtMSkge1xuXHRcdFx0cmV0dXJuIHJlc291cmNlXG5cdFx0fVxuXG5cdFx0Ly8gT25jZSB3ZSBoYXZlIGJ1aWx0IHRoZSBiYXNlIFVSSSwgd2UnbGwgcmVtb3ZlIHRoZSBwYXJhbWV0ZXIgaG9sZGVyIGZvciB0aGlzXG5cdFx0Ly8gYmFzZSByZXNvdXJjZSBuYW1lIHNvIHRoYXQgdGhlIGluZGl2aWR1YWwgcm91dGUgYWRkZXJzIGNhbiBzdWZmaXggdGhlc2Vcblx0XHQvLyBwYXRocyBob3dldmVyIHRoZXkgbmVlZCB0bywgYXMgc29tZSBkbyBub3QgaGF2ZSBhbnkgcGFyYW1ldGVycyBhdCBhbGwuXG5cdFx0Y29uc3Qgc2VnbWVudHMgPSByZXNvdXJjZS5zcGxpdCgvXFwuLylcblx0XHRjb25zdCB1cmkgPSB0aGlzLl9nZXROZXN0ZWRSZXNvdXJjZVVyaShzZWdtZW50cylcblxuXHRcdHJldHVybiB1cmkucmVwbGFjZShgLzoke3RoaXMuZ2V0UmVzb3VyY2VXaWxkY2FyZChzZWdtZW50c1tzZWdtZW50cy5sZW5ndGggLSAxXSl9YCwgJycpXG5cdH1cblxuXHRfZ2V0TmVzdGVkUmVzb3VyY2VVcmkoc2VnbWVudHMpIHtcblx0XHQvLyBXZSB3aWxsIHNwaW4gdGhyb3VnaCB0aGUgc2VnbWVudHMgYW5kIGNyZWF0ZSBhIHBsYWNlaG9sZGVyIGZvciBlYWNoIG9mIHRoZVxuXHRcdC8vIHJlc291cmNlIHNlZ21lbnRzLCBhcyB3ZWxsIGFzIHRoZSByZXNvdXJjZSBpdHNlbGYuIFRoZW4gd2Ugc2hvdWxkIGdldCBhblxuXHRcdC8vIGVudGlyZSBzdHJpbmcgZm9yIHRoZSByZXNvdXJjZSBVUkkgdGhhdCBjb250YWlucyBhbGwgbmVzdGVkIHJlc291cmNlcy5cblx0XHRyZXR1cm4gc2VnbWVudHMubWFwKHMgPT4gYCR7c30vOiR7dGhpcy5nZXRSZXNvdXJjZVdpbGRjYXJkKHMpfWApLmpvaW4oJy8nKVxuXHR9XG5cblx0Z2V0UmVzb3VyY2VXaWxkY2FyZCh2YWx1ZSkge1xuXHRcdGlmICghdGhpcy5wYXJhbWV0ZXJzLmlzTmlsICYmICF0aGlzLnBhcmFtZXRlcnMuaXNOaWxbdmFsdWVdKSB7XG5cdFx0XHR2YWx1ZSA9IHRoaXMucGFyYW1ldGVyc1t2YWx1ZV1cblx0XHR9IGVsc2UgaWYgKFxuXHRcdFx0IXRoaXMuY29uc3RydWN0b3IucGFyYW1ldGVyTWFwLmlzTmlsICYmXG5cdFx0XHQhdGhpcy5jb25zdHJ1Y3Rvci5wYXJhbWV0ZXJNYXBbdmFsdWVdLmlzTmlsXG5cdFx0KSB7XG5cdFx0XHR2YWx1ZSA9IHRoaXMuY29uc3RydWN0b3IucGFyYW1ldGVyTWFwW3ZhbHVlXVxuXHRcdH0gZWxzZSBpZiAodGhpcy5wYXJhbWV0ZXJzID09PSAnc2luZ3VsYXInIHx8IHRoaXMuY29uc3RydWN0b3Iuc2luZ3VsYXJQYXJhbWV0ZXJzKSB7XG5cdFx0XHR2YWx1ZSA9IEluZmxlY3Quc2luZ3VsYXJpemUodmFsdWUpXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHZhbHVlLnJlcGxhY2UoLy0vZywgJ18nKVxuXHR9XG5cblx0X2dldFJlc291cmNlQWN0aW9uKHJlc291cmNlLCBjb250cm9sbGVyLCBtZXRob2QsIG9wdGlvbnMpIHtcblx0XHRyZXR1cm4ge1xuXHRcdFx0YXM6IHRoaXMuX2dldFJlc291cmNlUm91dGVOYW1lKHJlc291cmNlLCBtZXRob2QsIG9wdGlvbnMpLFxuXHRcdFx0bWV0aG9kOiBtZXRob2QsXG5cdFx0fVxuXHR9XG5cblx0X2dldFJlc291cmNlUm91dGVOYW1lKHJlc291cmNlLCBtZXRob2QsIG9wdGlvbnMpIHtcblx0XHRsZXQgbmFtZSA9IHJlc291cmNlXG5cblx0XHQvLyBJZiB0aGUgbmFtZXMgYXJyYXkgaGFzIGJlZW4gcHJvdmlkZWQgdG8gdXMgd2Ugd2lsbCBjaGVjayBmb3IgYW4gZW50cnkgaW4gdGhlXG5cdFx0Ly8gYXJyYXkgZmlyc3QuIFdlIHdpbGwgYWxzbyBjaGVjayBmb3IgdGhlIHNwZWNpZmljIG1ldGhvZCB3aXRoaW4gdGhpcyBhcnJheVxuXHRcdC8vIHNvIHRoZSBuYW1lcyBtYXkgYmUgc3BlY2lmaWVkIG9uIGEgbW9yZSBcImdyYW51bGFyXCIgbGV2ZWwgdXNpbmcgbWV0aG9kcy5cblx0XHRpZiAoIW9wdGlvbnMubmFtZXMuaXNOaWwpIHtcblx0XHRcdGlmICh0eXBlb2Ygb3B0aW9ucy5uYW1lcyA9PT0gJ3N0cmluZycpIHtcblx0XHRcdFx0bmFtZSA9IG9wdGlvbnMubmFtZXNcblx0XHRcdH0gZWxzZSBpZiAoIW9wdGlvbnMubmFtZXNbbWV0aG9kXS5pc05pbCkge1xuXHRcdFx0XHRyZXR1cm4gb3B0aW9ucy5uYW1lc1ttZXRob2RdXG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gSWYgYSBnbG9iYWwgcHJlZml4IGhhcyBiZWVuIGFzc2lnbmVkIHRvIGFsbCBuYW1lcyBmb3IgdGhpcyByZXNvdXJjZSwgd2Ugd2lsbFxuXHRcdC8vIGdyYWIgdGhhdCBzbyB3ZSBjYW4gcHJlcGVuZCBpdCBvbnRvIHRoZSBuYW1lIHdoZW4gd2UgY3JlYXRlIHRoaXMgbmFtZSBmb3Jcblx0XHQvLyB0aGUgcmVzb3VyY2UgYWN0aW9uLiBPdGhlcndpc2Ugd2UnbGwganVzdCB1c2UgYW4gZW1wdHkgc3RyaW5nIGZvciBoZXJlLlxuXHRcdGNvbnN0IHByZWZpeCA9ICFvcHRpb25zLmFzLmlzTmlsID8gYCR7b3B0aW9ucy5hc30uYCA6ICcnXG5cdFx0cmV0dXJuIGAke3ByZWZpeH0ke25hbWV9LiR7bWV0aG9kfWAucmVwbGFjZSgvKF5cXC58XFwuJCkvZywgJycpXG5cdH1cblxuXHRzdGF0aWMgc2luZ3VsYXJQYXJhbWV0ZXJzKHNpbmd1bGFyID0gdHJ1ZSkge1xuXHRcdHRoaXMuc2luZ3VsYXJQYXJhbWV0ZXJzID0gc2luZ3VsYXJcblx0fVxuXG5cdHN0YXRpYyBnZXRQYXJhbWV0ZXJzKCkge1xuXHRcdHJldHVybiBbLi4udGhpcy5wYXJhbWV0ZXJNYXBdXG5cdH1cblxuXHRzdGF0aWMgc2V0UGFyYW1ldGVycyhwYXJhbWV0ZXJzID0gW10pIHtcblx0XHR0aGlzLnBhcmFtZXRlck1hcCA9IFsuLi5wYXJhbWV0ZXJzXVxuXHR9XG5cblx0c3RhdGljIHZlcmJzKHZlcmJzID0ge30pIHtcblx0XHRpZiAoT2JqZWN0LmtleXModmVyYnMpLmxlbmd0aCA9PT0gMCkge1xuXHRcdFx0cmV0dXJuIHsgLi4udGhpcy52ZXJicyB9XG5cdFx0fVxuXG5cdFx0dGhpcy52ZXJicyA9IHsgLi4udGhpcy52ZXJicywgLi4udmVyYnMgfVxuXHR9XG59XG4iXX0=