no-extraneous-dependencies.js 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. 'use strict';var _slicedToArray = function () {function sliceIterator(arr, i) {var _arr = [];var _n = true;var _d = false;var _e = undefined;try {for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {_arr.push(_s.value);if (i && _arr.length === i) break;}} catch (err) {_d = true;_e = err;} finally {try {if (!_n && _i["return"]) _i["return"]();} finally {if (_d) throw _e;}}return _arr;}return function (arr, i) {if (Array.isArray(arr)) {return arr;} else if (Symbol.iterator in Object(arr)) {return sliceIterator(arr, i);} else {throw new TypeError("Invalid attempt to destructure non-iterable instance");}};}();var _path = require('path');var _path2 = _interopRequireDefault(_path);
  2. var _fs = require('fs');var _fs2 = _interopRequireDefault(_fs);
  3. var _readPkgUp = require('read-pkg-up');var _readPkgUp2 = _interopRequireDefault(_readPkgUp);
  4. var _minimatch = require('minimatch');var _minimatch2 = _interopRequireDefault(_minimatch);
  5. var _resolve = require('eslint-module-utils/resolve');var _resolve2 = _interopRequireDefault(_resolve);
  6. var _moduleVisitor = require('eslint-module-utils/moduleVisitor');var _moduleVisitor2 = _interopRequireDefault(_moduleVisitor);
  7. var _importType = require('../core/importType');var _importType2 = _interopRequireDefault(_importType);
  8. var _packagePath = require('../core/packagePath');
  9. var _docsUrl = require('../docsUrl');var _docsUrl2 = _interopRequireDefault(_docsUrl);function _interopRequireDefault(obj) {return obj && obj.__esModule ? obj : { default: obj };}
  10. const depFieldCache = new Map();
  11. function hasKeys() {let obj = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  12. return Object.keys(obj).length > 0;
  13. }
  14. function arrayOrKeys(arrayOrObject) {
  15. return Array.isArray(arrayOrObject) ? arrayOrObject : Object.keys(arrayOrObject);
  16. }
  17. function extractDepFields(pkg) {
  18. return {
  19. dependencies: pkg.dependencies || {},
  20. devDependencies: pkg.devDependencies || {},
  21. optionalDependencies: pkg.optionalDependencies || {},
  22. peerDependencies: pkg.peerDependencies || {},
  23. // BundledDeps should be in the form of an array, but object notation is also supported by
  24. // `npm`, so we convert it to an array if it is an object
  25. bundledDependencies: arrayOrKeys(pkg.bundleDependencies || pkg.bundledDependencies || []) };
  26. }
  27. function getDependencies(context, packageDir) {
  28. let paths = [];
  29. try {
  30. const packageContent = {
  31. dependencies: {},
  32. devDependencies: {},
  33. optionalDependencies: {},
  34. peerDependencies: {},
  35. bundledDependencies: [] };
  36. if (packageDir && packageDir.length > 0) {
  37. if (!Array.isArray(packageDir)) {
  38. paths = [_path2.default.resolve(packageDir)];
  39. } else {
  40. paths = packageDir.map(dir => _path2.default.resolve(dir));
  41. }
  42. }
  43. if (paths.length > 0) {
  44. // use rule config to find package.json
  45. paths.forEach(dir => {
  46. const packageJsonPath = _path2.default.join(dir, 'package.json');
  47. if (!depFieldCache.has(packageJsonPath)) {
  48. const depFields = extractDepFields(
  49. JSON.parse(_fs2.default.readFileSync(packageJsonPath, 'utf8')));
  50. depFieldCache.set(packageJsonPath, depFields);
  51. }
  52. const _packageContent = depFieldCache.get(packageJsonPath);
  53. Object.keys(packageContent).forEach(depsKey =>
  54. Object.assign(packageContent[depsKey], _packageContent[depsKey]));
  55. });
  56. } else {
  57. // use closest package.json
  58. Object.assign(
  59. packageContent,
  60. extractDepFields(
  61. _readPkgUp2.default.sync({ cwd: context.getFilename(), normalize: false }).pkg));
  62. }
  63. if (![
  64. packageContent.dependencies,
  65. packageContent.devDependencies,
  66. packageContent.optionalDependencies,
  67. packageContent.peerDependencies,
  68. packageContent.bundledDependencies].
  69. some(hasKeys)) {
  70. return null;
  71. }
  72. return packageContent;
  73. } catch (e) {
  74. if (paths.length > 0 && e.code === 'ENOENT') {
  75. context.report({
  76. message: 'The package.json file could not be found.',
  77. loc: { line: 0, column: 0 } });
  78. }
  79. if (e.name === 'JSONError' || e instanceof SyntaxError) {
  80. context.report({
  81. message: 'The package.json file could not be parsed: ' + e.message,
  82. loc: { line: 0, column: 0 } });
  83. }
  84. return null;
  85. }
  86. }
  87. function missingErrorMessage(packageName) {
  88. return `'${packageName}' should be listed in the project's dependencies. ` +
  89. `Run 'npm i -S ${packageName}' to add it`;
  90. }
  91. function devDepErrorMessage(packageName) {
  92. return `'${packageName}' should be listed in the project's dependencies, not devDependencies.`;
  93. }
  94. function optDepErrorMessage(packageName) {
  95. return `'${packageName}' should be listed in the project's dependencies, ` +
  96. `not optionalDependencies.`;
  97. }
  98. function getModuleOriginalName(name) {var _name$split =
  99. name.split('/'),_name$split2 = _slicedToArray(_name$split, 2);const first = _name$split2[0],second = _name$split2[1];
  100. return first.startsWith('@') ? `${first}/${second}` : first;
  101. }
  102. function getModuleRealName(resolved) {
  103. return (0, _packagePath.getFilePackageName)(resolved);
  104. }
  105. function checkDependencyDeclaration(deps, packageName) {
  106. // in case of sub package.json inside a module
  107. // check the dependencies on all hierarchy
  108. const packageHierarchy = [];
  109. const packageNameParts = packageName.split('/');
  110. packageNameParts.forEach((namePart, index) => {
  111. if (!namePart.startsWith('@')) {
  112. const ancestor = packageNameParts.slice(0, index + 1).join('/');
  113. packageHierarchy.push(ancestor);
  114. }
  115. });
  116. return packageHierarchy.reduce((result, ancestorName) => {
  117. return {
  118. isInDeps: result.isInDeps || deps.dependencies[ancestorName] !== undefined,
  119. isInDevDeps: result.isInDevDeps || deps.devDependencies[ancestorName] !== undefined,
  120. isInOptDeps: result.isInOptDeps || deps.optionalDependencies[ancestorName] !== undefined,
  121. isInPeerDeps: result.isInPeerDeps || deps.peerDependencies[ancestorName] !== undefined,
  122. isInBundledDeps:
  123. result.isInBundledDeps || deps.bundledDependencies.indexOf(ancestorName) !== -1 };
  124. }, {
  125. isInDeps: false,
  126. isInDevDeps: false,
  127. isInOptDeps: false,
  128. isInPeerDeps: false,
  129. isInBundledDeps: false });
  130. }
  131. function reportIfMissing(context, deps, depsOptions, node, name) {
  132. // Do not report when importing types
  133. if (node.importKind === 'type' || node.parent && node.parent.importKind === 'type' || node.importKind === 'typeof') {
  134. return;
  135. }
  136. if ((0, _importType2.default)(name, context) !== 'external') {
  137. return;
  138. }
  139. const resolved = (0, _resolve2.default)(name, context);
  140. if (!resolved) {return;}
  141. const importPackageName = getModuleOriginalName(name);
  142. const importPackageNameDeclaration = checkDependencyDeclaration(deps, importPackageName);
  143. if (importPackageNameDeclaration.isInDeps ||
  144. depsOptions.allowDevDeps && importPackageNameDeclaration.isInDevDeps ||
  145. depsOptions.allowPeerDeps && importPackageNameDeclaration.isInPeerDeps ||
  146. depsOptions.allowOptDeps && importPackageNameDeclaration.isInOptDeps ||
  147. depsOptions.allowBundledDeps && importPackageNameDeclaration.isInBundledDeps)
  148. {
  149. return;
  150. }
  151. // test the real name from the resolved package.json
  152. // if not aliased imports (alias/react for example), importPackageName can be misinterpreted
  153. const realPackageName = getModuleRealName(resolved);
  154. const realPackageNameDeclaration = checkDependencyDeclaration(deps, realPackageName);
  155. if (realPackageNameDeclaration.isInDeps ||
  156. depsOptions.allowDevDeps && realPackageNameDeclaration.isInDevDeps ||
  157. depsOptions.allowPeerDeps && realPackageNameDeclaration.isInPeerDeps ||
  158. depsOptions.allowOptDeps && realPackageNameDeclaration.isInOptDeps ||
  159. depsOptions.allowBundledDeps && realPackageNameDeclaration.isInBundledDeps)
  160. {
  161. return;
  162. }
  163. if ((
  164. importPackageNameDeclaration.isInDevDeps ||
  165. realPackageNameDeclaration.isInDevDeps) &&
  166. !depsOptions.allowDevDeps) {
  167. context.report(node, devDepErrorMessage(realPackageName));
  168. return;
  169. }
  170. if ((
  171. importPackageNameDeclaration.isInOptDeps ||
  172. realPackageNameDeclaration.isInOptDeps) &&
  173. !depsOptions.allowOptDeps) {
  174. context.report(node, optDepErrorMessage(realPackageName));
  175. return;
  176. }
  177. context.report(node, missingErrorMessage(realPackageName));
  178. }
  179. function testConfig(config, filename) {
  180. // Simplest configuration first, either a boolean or nothing.
  181. if (typeof config === 'boolean' || typeof config === 'undefined') {
  182. return config;
  183. }
  184. // Array of globs.
  185. return config.some(c =>
  186. (0, _minimatch2.default)(filename, c) ||
  187. (0, _minimatch2.default)(filename, _path2.default.join(process.cwd(), c)));
  188. }
  189. module.exports = {
  190. meta: {
  191. type: 'problem',
  192. docs: {
  193. url: (0, _docsUrl2.default)('no-extraneous-dependencies') },
  194. schema: [
  195. {
  196. 'type': 'object',
  197. 'properties': {
  198. 'devDependencies': { 'type': ['boolean', 'array'] },
  199. 'optionalDependencies': { 'type': ['boolean', 'array'] },
  200. 'peerDependencies': { 'type': ['boolean', 'array'] },
  201. 'bundledDependencies': { 'type': ['boolean', 'array'] },
  202. 'packageDir': { 'type': ['string', 'array'] } },
  203. 'additionalProperties': false }] },
  204. create: function (context) {
  205. const options = context.options[0] || {};
  206. const filename = context.getFilename();
  207. const deps = getDependencies(context, options.packageDir) || extractDepFields({});
  208. const depsOptions = {
  209. allowDevDeps: testConfig(options.devDependencies, filename) !== false,
  210. allowOptDeps: testConfig(options.optionalDependencies, filename) !== false,
  211. allowPeerDeps: testConfig(options.peerDependencies, filename) !== false,
  212. allowBundledDeps: testConfig(options.bundledDependencies, filename) !== false };
  213. return (0, _moduleVisitor2.default)((source, node) => {
  214. reportIfMissing(context, deps, depsOptions, node, source.value);
  215. }, { commonjs: true });
  216. } };
  217. //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydWxlcy9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llcy5qcyJdLCJuYW1lcyI6WyJkZXBGaWVsZENhY2hlIiwiTWFwIiwiaGFzS2V5cyIsIm9iaiIsIk9iamVjdCIsImtleXMiLCJsZW5ndGgiLCJhcnJheU9yS2V5cyIsImFycmF5T3JPYmplY3QiLCJBcnJheSIsImlzQXJyYXkiLCJleHRyYWN0RGVwRmllbGRzIiwicGtnIiwiZGVwZW5kZW5jaWVzIiwiZGV2RGVwZW5kZW5jaWVzIiwib3B0aW9uYWxEZXBlbmRlbmNpZXMiLCJwZWVyRGVwZW5kZW5jaWVzIiwiYnVuZGxlZERlcGVuZGVuY2llcyIsImJ1bmRsZURlcGVuZGVuY2llcyIsImdldERlcGVuZGVuY2llcyIsImNvbnRleHQiLCJwYWNrYWdlRGlyIiwicGF0aHMiLCJwYWNrYWdlQ29udGVudCIsInBhdGgiLCJyZXNvbHZlIiwibWFwIiwiZGlyIiwiZm9yRWFjaCIsInBhY2thZ2VKc29uUGF0aCIsImpvaW4iLCJoYXMiLCJkZXBGaWVsZHMiLCJKU09OIiwicGFyc2UiLCJmcyIsInJlYWRGaWxlU3luYyIsInNldCIsIl9wYWNrYWdlQ29udGVudCIsImdldCIsImRlcHNLZXkiLCJhc3NpZ24iLCJyZWFkUGtnVXAiLCJzeW5jIiwiY3dkIiwiZ2V0RmlsZW5hbWUiLCJub3JtYWxpemUiLCJzb21lIiwiZSIsImNvZGUiLCJyZXBvcnQiLCJtZXNzYWdlIiwibG9jIiwibGluZSIsImNvbHVtbiIsIm5hbWUiLCJTeW50YXhFcnJvciIsIm1pc3NpbmdFcnJvck1lc3NhZ2UiLCJwYWNrYWdlTmFtZSIsImRldkRlcEVycm9yTWVzc2FnZSIsIm9wdERlcEVycm9yTWVzc2FnZSIsImdldE1vZHVsZU9yaWdpbmFsTmFtZSIsInNwbGl0IiwiZmlyc3QiLCJzZWNvbmQiLCJzdGFydHNXaXRoIiwiZ2V0TW9kdWxlUmVhbE5hbWUiLCJyZXNvbHZlZCIsImNoZWNrRGVwZW5kZW5jeURlY2xhcmF0aW9uIiwiZGVwcyIsInBhY2thZ2VIaWVyYXJjaHkiLCJwYWNrYWdlTmFtZVBhcnRzIiwibmFtZVBhcnQiLCJpbmRleCIsImFuY2VzdG9yIiwic2xpY2UiLCJwdXNoIiwicmVkdWNlIiwicmVzdWx0IiwiYW5jZXN0b3JOYW1lIiwiaXNJbkRlcHMiLCJ1bmRlZmluZWQiLCJpc0luRGV2RGVwcyIsImlzSW5PcHREZXBzIiwiaXNJblBlZXJEZXBzIiwiaXNJbkJ1bmRsZWREZXBzIiwiaW5kZXhPZiIsInJlcG9ydElmTWlzc2luZyIsImRlcHNPcHRpb25zIiwibm9kZSIsImltcG9ydEtpbmQiLCJwYXJlbnQiLCJpbXBvcnRQYWNrYWdlTmFtZSIsImltcG9ydFBhY2thZ2VOYW1lRGVjbGFyYXRpb24iLCJhbGxvd0RldkRlcHMiLCJhbGxvd1BlZXJEZXBzIiwiYWxsb3dPcHREZXBzIiwiYWxsb3dCdW5kbGVkRGVwcyIsInJlYWxQYWNrYWdlTmFtZSIsInJlYWxQYWNrYWdlTmFtZURlY2xhcmF0aW9uIiwidGVzdENvbmZpZyIsImNvbmZpZyIsImZpbGVuYW1lIiwiYyIsInByb2Nlc3MiLCJtb2R1bGUiLCJleHBvcnRzIiwibWV0YSIsInR5cGUiLCJkb2NzIiwidXJsIiwic2NoZW1hIiwiY3JlYXRlIiwib3B0aW9ucyIsInNvdXJjZSIsInZhbHVlIiwiY29tbW9uanMiXSwibWFwcGluZ3MiOiJxb0JBQUEsNEI7QUFDQSx3QjtBQUNBLHdDO0FBQ0Esc0M7QUFDQSxzRDtBQUNBLGtFO0FBQ0EsZ0Q7QUFDQTtBQUNBLHFDOztBQUVBLE1BQU1BLGdCQUFnQixJQUFJQyxHQUFKLEVBQXRCOztBQUVBLFNBQVNDLE9BQVQsR0FBMkIsS0FBVkMsR0FBVSx1RUFBSixFQUFJO0FBQ3pCLFNBQU9DLE9BQU9DLElBQVAsQ0FBWUYsR0FBWixFQUFpQkcsTUFBakIsR0FBMEIsQ0FBakM7QUFDRDs7QUFFRCxTQUFTQyxXQUFULENBQXFCQyxhQUFyQixFQUFvQztBQUNsQyxTQUFPQyxNQUFNQyxPQUFOLENBQWNGLGFBQWQsSUFBK0JBLGFBQS9C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c291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgZnMgZnJvbSAnZnMnO1xuaW1wb3J0IHJlYWRQa2dVcCBmcm9tICdyZWFkLXBrZy11cCc7XG5pbXBvcnQgbWluaW1hdGNoIGZyb20gJ21pbmltYXRjaCc7XG5pbXBvcnQgcmVzb2x2ZSBmcm9tICdlc2xpbnQtbW9kdWxlLXV0aWxzL3Jlc29sdmUnO1xuaW1wb3J0IG1vZHVsZVZpc2l0b3IgZnJvbSAnZXNsaW50LW1vZHVsZS11dGlscy9tb2R1bGVWaXNpdG9yJztcbmltcG9ydCBpbXBvcnRUeXBlIGZyb20gJy4uL2NvcmUvaW1wb3J0VHlwZSc7XG5pbXBvcnQgeyBnZXRGaWxlUGFja2FnZU5hbWUgfSBmcm9tICcuLi9jb3JlL3BhY2thZ2VQYXRoJztcbmltcG9ydCBkb2NzVXJsIGZyb20gJy4uL2RvY3NVcmwnO1xuXG5jb25zdCBkZXBGaWVsZENhY2hlID0gbmV3IE1hcCgpO1xuXG5mdW5jdGlvbiBoYXNLZXlzKG9iaiA9IHt9KSB7XG4gIHJldHVybiBPYmplY3Qua2V5cyhvYmopLmxlbmd0aCA+IDA7XG59XG5cbmZ1bmN0aW9uIGFycmF5T3JLZXlzKGFycmF5T3JPYmplY3QpIHtcbiAgcmV0dXJuIEFycmF5LmlzQXJyYXkoYXJyYXlPck9iamVjdCkgPyBhcnJheU9yT2JqZWN0IDogT2JqZWN0LmtleXMoYXJyYXlPck9iamVjdCk7XG59XG5cbmZ1bmN0aW9uIGV4dHJhY3REZXBGaWVsZHMocGtnKSB7XG4gIHJldHVybiB7XG4gICAgZGVwZW5kZW5jaWVzOiBwa2cuZGVwZW5kZW5jaWVzIHx8IHt9LFxuICAgIGRldkRlcGVuZGVuY2llczogcGtnLmRldkRlcGVuZGVuY2llcyB8fCB7fSxcbiAgICBvcHRpb25hbERlcGVuZGVuY2llczogcGtnLm9wdGlvbmFsRGVwZW5kZW5jaWVzIHx8IHt9LFxuICAgIHBlZXJEZXBlbmRlbmNpZXM6IHBrZy5wZWVyRGVwZW5kZW5jaWVzIHx8IHt9LFxuICAgIC8vIEJ1bmRsZWREZXBzIHNob3VsZCBiZSBpbiB0aGUgZm9ybSBvZiBhbiBhcnJheSwgYnV0IG9iamVjdCBub3RhdGlvbiBpcyBhbHNvIHN1cHBvcnRlZCBieVxuICAgIC8vIGBucG1gLCBzbyB3ZSBjb252ZXJ0IGl0IHRvIGFuIGFycmF5IGlmIGl0IGlzIGFuIG9iamVjdFxuICAgIGJ1bmRsZWREZXBlbmRlbmNpZXM6IGFycmF5T3JLZXlzKHBrZy5idW5kbGVEZXBlbmRlbmNpZXMgfHwgcGtnLmJ1bmRsZWREZXBlbmRlbmNpZXMgfHwgW10pLFxuICB9O1xufVxuXG5mdW5jdGlvbiBnZXREZXBlbmRlbmNpZXMoY29udGV4dCwgcGFja2FnZURpcikge1xuICBsZXQgcGF0aHMgPSBbXTtcbiAgdHJ5IHtcbiAgICBjb25zdCBwYWNrYWdlQ29udGVudCA9IHtcbiAgICAgIGRlcGVuZGVuY2llczoge30sXG4gICAgICBkZXZEZXBlbmRlbmNpZXM6IHt9LFxuICAgICAgb3B0aW9uYWxEZXBlbmRlbmNpZXM6IHt9LFxuICAgICAgcGVlckRlcGVuZGVuY2llczoge30sXG4gICAgICBidW5kbGVkRGVwZW5kZW5jaWVzOiBbXSxcbiAgICB9O1xuXG4gICAgaWYgKHBhY2thZ2VEaXIgJiYgcGFja2FnZURpci5sZW5ndGggPiAwKSB7XG4gICAgICBpZiAoIUFycmF5LmlzQXJyYXkocGFja2FnZURpcikpIHtcbiAgICAgICAgcGF0aHMgPSBbcGF0aC5yZXNvbHZlKHBhY2thZ2VEaXIpXTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHBhdGhzID0gcGFja2FnZURpci5tYXAoZGlyID0+IHBhdGgucmVzb2x2ZShkaXIpKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAocGF0aHMubGVuZ3RoID4gMCkge1xuICAgICAgLy8gdXNlIHJ1bGUgY29uZmlnIHRvIGZpbmQgcGFja2FnZS5qc29uXG4gICAgICBwYXRocy5mb3JFYWNoKGRpciA9PiB7XG4gICAgICAgIGNvbnN0IHBhY2thZ2VKc29uUGF0aCA9IHBhdGguam9pbihkaXIsICdwYWNrYWdlLmpzb24nKTtcbiAgICAgICAgaWYgKCFkZXBGaWVsZENhY2hlLmhhcyhwYWNrYWdlSnNvblBhdGgpKSB7XG4gICAgICAgICAgY29uc3QgZGVwRmllbGRzID0gZXh0cmFjdERlcEZpZWxkcyhcbiAgICAgICAgICAgIEpTT04ucGFyc2UoZnMucmVhZEZpbGVTeW5jKHBhY2thZ2VKc29uUGF0aCwgJ3V0ZjgnKSlcbiAgICAgICAgICApO1xuICAgICAgICAgIGRlcEZpZWxkQ2FjaGUuc2V0KHBhY2thZ2VKc29uUGF0aCwgZGVwRmllbGRzKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBfcGFja2FnZUNvbnRlbnQgPSBkZXBGaWVsZENhY2hlLmdldChwYWNrYWdlSnNvblBhdGgpO1xuICAgICAgICBPYmplY3Qua2V5cyhwYWNrYWdlQ29udGVudCkuZm9yRWFjaChkZXBzS2V5ID0+XG4gICAgICAgICAgT2JqZWN0LmFzc2lnbihwYWNrYWdlQ29udGVudFtkZXBzS2V5XSwgX3BhY2thZ2VDb250ZW50W2RlcHNLZXldKVxuICAgICAgICApO1xuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIHVzZSBjbG9zZXN0IHBhY2thZ2UuanNvblxuICAgICAgT2JqZWN0LmFzc2lnbihcbiAgICAgICAgcGFja2FnZUNvbnRlbnQsXG4gICAgICAgIGV4dHJhY3REZXBGaWVsZHMoXG4gICAgICAgICAgcmVhZFBrZ1VwLnN5bmMoeyBjd2Q6IGNvbnRleHQuZ2V0RmlsZW5hbWUoKSwgbm9ybWFsaXplOiBmYWxzZSB9KS5wa2dcbiAgICAgICAgKVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAoIVtcbiAgICAgIHBhY2thZ2VDb250ZW50LmRlcGVuZGVuY2llcyxcbiAgICAgIHBhY2thZ2VDb250ZW50LmRldkRlcGVuZGVuY2llcyxcbiAgICAgIHBhY2thZ2VDb250ZW50Lm9wdGlvbmFsRGVwZW5kZW5jaWVzLFxuICAgICAgcGFja2FnZUNvbnRlbnQucGVlckRlcGVuZGVuY2llcyxcbiAgICAgIHBhY2thZ2VDb250ZW50LmJ1bmRsZWREZXBlbmRlbmNpZXMsXG4gICAgXS5zb21lKGhhc0tleXMpKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICByZXR1cm4gcGFja2FnZUNvbnRlbnQ7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBpZiAocGF0aHMubGVuZ3RoID4gMCAmJiBlLmNvZGUgPT09ICdFTk9FTlQnKSB7XG4gICAgICBjb250ZXh0LnJlcG9ydCh7XG4gICAgICAgIG1lc3NhZ2U6ICdUaGUgcGFja2FnZS5qc29uIGZpbGUgY291bGQgbm90IGJlIGZvdW5kLicsXG4gICAgICAgIGxvYzogeyBsaW5lOiAwLCBjb2x1bW46IDAgfSxcbiAgICAgIH0pO1xuICAgIH1cbiAgICBpZiAoZS5uYW1lID09PSAnSlNPTkVycm9yJyB8fCBlIGluc3RhbmNlb2YgU3ludGF4RXJyb3IpIHtcbiAgICAgIGNvbnRleHQucmVwb3J0KHtcbiAgICAgICAgbWVzc2FnZTogJ1RoZSBwYWNrYWdlLmpzb24gZmlsZSBjb3VsZCBub3QgYmUgcGFyc2VkOiAnICsgZS5tZXNzYWdlLFxuICAgICAgICBsb2M6IHsgbGluZTogMCwgY29sdW1uOiAwIH0sXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxufVxuXG5mdW5jdGlvbiBtaXNzaW5nRXJyb3JNZXNzYWdlKHBhY2thZ2VOYW1lKSB7XG4gIHJldHVybiBgJyR7cGFja2FnZU5hbWV9JyBzaG91bGQgYmUgbGlzdGVkIGluIHRoZSBwcm9qZWN0J3MgZGVwZW5kZW5jaWVzLiBgICtcbiAgICBgUnVuICducG0gaSAtUyAke3BhY2thZ2VOYW1lfScgdG8gYWRkIGl0YDtcbn1cblxuZnVuY3Rpb24gZGV2RGVwRXJyb3JNZXNzYWdlKHBhY2thZ2VOYW1lKSB7XG4gIHJldHVybiBgJyR7cGFja2FnZU5hbWV9JyBzaG91bGQgYmUgbGlzdGVkIGluIHRoZSBwcm9qZWN0J3MgZGVwZW5kZW5jaWVzLCBub3QgZGV2RGVwZW5kZW5jaWVzLmA7XG59XG5cbmZ1bmN0aW9uIG9wdERlcEVycm9yTWVzc2FnZShwYWNrYWdlTmFtZSkge1xuICByZXR1cm4gYCcke3BhY2thZ2VOYW1lfScgc2hvdWxkIGJlIGxpc3RlZCBpbiB0aGUgcHJvamVjdCdzIGRlcGVuZGVuY2llcywgYCArXG4gICAgYG5vdCBvcHRpb25hbERlcGVuZGVuY2llcy5gO1xufVxuXG5mdW5jdGlvbiBnZXRNb2R1bGVPcmlnaW5hbE5hbWUobmFtZSkge1xuICBjb25zdCBbZmlyc3QsIHNlY29uZF0gPSBuYW1lLnNwbGl0KCcvJyk7XG4gIHJldHVybiBmaXJzdC5zdGFydHNXaXRoKCdAJykgPyBgJHtmaXJzdH0vJHtzZWNvbmR9YCA6IGZpcnN0O1xufVxuXG5mdW5jdGlvbiBnZXRNb2R1bGVSZWFsTmFtZShyZXNvbHZlZCkge1xuICByZXR1cm4gZ2V0RmlsZVBhY2thZ2VOYW1lKHJlc29sdmVkKTtcbn1cblxuZnVuY3Rpb24gY2hlY2tEZXBlbmRlbmN5RGVjbGFyYXRpb24oZGVwcywgcGFja2FnZU5hbWUpIHtcbiAgLy8gaW4gY2FzZSBvZiBzdWIgcGFja2FnZS5qc29uIGluc2lkZSBhIG1vZHVsZVxuICAvLyBjaGVjayB0aGUgZGVwZW5kZW5jaWVzIG9uIGFsbCBoaWVyYXJjaHlcbiAgY29uc3QgcGFja2FnZUhpZXJhcmNoeSA9IFtdO1xuICBjb25zdCBwYWNrYWdlTmFtZVBhcnRzID0gcGFja2FnZU5hbWUuc3BsaXQoJy8nKTtcbiAgcGFja2FnZU5hbWVQYXJ0cy5mb3JFYWNoKChuYW1lUGFydCwgaW5kZXgpID0+IHtcbiAgICBpZiAoIW5hbWVQYXJ0LnN0YXJ0c1dpdGgoJ0AnKSkge1xuICAgICAgY29uc3QgYW5jZXN0b3IgPSBwYWNrYWdlTmFtZVBhcnRzLnNsaWNlKDAsIGluZGV4ICsgMSkuam9pbignLycpO1xuICAgICAgcGFja2FnZUhpZXJhcmNoeS5wdXNoKGFuY2VzdG9yKTtcbiAgICB9XG4gIH0pO1xuXG4gIHJldHVybiBwYWNrYWdlSGllcmFyY2h5LnJlZHVjZSgocmVzdWx0LCBhbmNlc3Rvck5hbWUpID0+IHtcbiAgICByZXR1cm4ge1xuICAgICAgaXNJbkRlcHM6IHJlc3VsdC5pc0luRGVwcyB8fCBkZXBzLmRlcGVuZGVuY2llc1thbmNlc3Rvck5hbWVdICE9PSB1bmRlZmluZWQsXG4gICAgICBpc0luRGV2RGVwczogcmVzdWx0LmlzSW5EZXZEZXBzIHx8IGRlcHMuZGV2RGVwZW5kZW5jaWVzW2FuY2VzdG9yTmFtZV0gIT09IHVuZGVmaW5lZCxcbiAgICAgIGlzSW5PcHREZXBzOiByZXN1bHQuaXNJbk9wdERlcHMgfHwgZGVwcy5vcHRpb25hbERlcGVuZGVuY2llc1thbmNlc3Rvck5hbWVdICE9PSB1bmRlZmluZWQsXG4gICAgICBpc0luUGVlckRlcHM6IHJlc3VsdC5pc0luUGVlckRlcHMgfHwgZGVwcy5wZWVyRGVwZW5kZW5jaWVzW2FuY2VzdG9yTmFtZV0gIT09IHVuZGVmaW5lZCxcbiAgICAgIGlzSW5CdW5kbGVkRGVwczpcbiAgICAgICAgcmVzdWx0LmlzSW5CdW5kbGVkRGVwcyB8fCBkZXBzLmJ1bmRsZWREZXBlbmRlbmNpZXMuaW5kZXhPZihhbmNlc3Rvck5hbWUpICE9PSAtMSxcbiAgICB9O1xuICB9LCB7XG4gICAgaXNJbkRlcHM6IGZhbHNlLFxuICAgIGlzSW5EZXZEZXBzOiBmYWxzZSxcbiAgICBpc0luT3B0RGVwczogZmFsc2UsXG4gICAgaXNJblBlZXJEZXBzOiBmYWxzZSxcbiAgICBpc0luQnVuZGxlZERlcHM6IGZhbHNlLFxuICB9KTtcbn1cblxuZnVuY3Rpb24gcmVwb3J0SWZNaXNzaW5nKGNvbnRleHQsIGRlcHMsIGRlcHNPcHRpb25zLCBub2RlLCBuYW1lKSB7XG4gIC8vIERvIG5vdCByZXBvcnQgd2hlbiBpbXBvcnRpbmcgdHlwZXNcbiAgaWYgKG5vZGUuaW1wb3J0S2luZCA9PT0gJ3R5cGUnIHx8IChub2RlLnBhcmVudCAmJiBub2RlLnBhcmVudC5pbXBvcnRLaW5kID09PSAndHlwZScpIHx8IG5vZGUuaW1wb3J0S2luZCA9PT0gJ3R5cGVvZicpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICBpZiAoaW1wb3J0VHlwZShuYW1lLCBjb250ZXh0KSAhPT0gJ2V4dGVybmFsJykge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IHJlc29sdmVkID0gcmVzb2x2ZShuYW1lLCBjb250ZXh0KTtcbiAgaWYgKCFyZXNvbHZlZCkgeyByZXR1cm47IH1cblxuICBjb25zdCBpbXBvcnRQYWNrYWdlTmFtZSA9IGdldE1vZHVsZU9yaWdpbmFsTmFtZShuYW1lKTtcbiAgY29uc3QgaW1wb3J0UGFja2FnZU5hbWVEZWNsYXJhdGlvbiA9IGNoZWNrRGVwZW5kZW5jeURlY2xhcmF0aW9uKGRlcHMsIGltcG9ydFBhY2thZ2VOYW1lKTtcblxuICBpZiAoaW1wb3J0UGFja2FnZU5hbWVEZWNsYXJhdGlvbi5pc0luRGVwcyB8fFxuICAgIChkZXBzT3B0aW9ucy5hbGxvd0RldkRlcHMgJiYgaW1wb3J0UGFja2FnZU5hbWVEZWNsYXJhdGlvbi5pc0luRGV2RGVwcykgfHxcbiAgICAoZGVwc09wdGlvbnMuYWxsb3dQZWVyRGVwcyAmJiBpbXBvcnRQYWNrYWdlTmFtZURlY2xhcmF0aW9uLmlzSW5QZWVyRGVwcykgfHxcbiAgICAoZGVwc09wdGlvbnMuYWxsb3dPcHREZXBzICYmIGltcG9ydFBhY2thZ2VOYW1lRGVjbGFyYXRpb24uaXNJbk9wdERlcHMpIHx8XG4gICAgKGRlcHNPcHRpb25zLmFsbG93QnVuZGxlZERlcHMgJiYgaW1wb3J0UGFja2FnZU5hbWVEZWNsYXJhdGlvbi5pc0luQnVuZGxlZERlcHMpXG4gICkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIHRlc3QgdGhlIHJlYWwgbmFtZSBmcm9tIHRoZSByZXNvbHZlZCBwYWNrYWdlLmpzb25cbiAgLy8gaWYgbm90IGFsaWFzZWQgaW1wb3J0cyAoYWxpYXMvcmVhY3QgZm9yIGV4YW1wbGUpLCBpbXBvcnRQYWNrYWdlTmFtZSBjYW4gYmUgIG1pc2ludGVycHJldGVkXG4gIGNvbnN0IHJlYWxQYWNrYWdlTmFtZSA9IGdldE1vZHVsZVJlYWxOYW1lKHJlc29sdmVkKTtcbiAgY29uc3QgcmVhbFBhY2thZ2VOYW1lRGVjbGFyYXRpb24gPSBjaGVja0RlcGVuZGVuY3lEZWNsYXJhdGlvbihkZXBzLCByZWFsUGFja2FnZU5hbWUpO1xuXG4gIGlmIChyZWFsUGFja2FnZU5hbWVEZWNsYXJhdGlvbi5pc0luRGVwcyB8fFxuICAgIChkZXBzT3B0aW9ucy5hbGxvd0RldkRlcHMgJiYgcmVhbFBhY2thZ2VOYW1lRGVjbGFyYXRpb24uaXNJbkRldkRlcHMpIHx8XG4gICAgKGRlcHNPcHRpb25zLmFsbG93UGVlckRlcHMgJiYgcmVhbFBhY2thZ2VOYW1lRGVjbGFyYXRpb24uaXNJblBlZXJEZXBzKSB8fFxuICAgIChkZXBzT3B0aW9ucy5hbGxvd09wdERlcHMgJiYgcmVhbFBhY2thZ2VOYW1lRGVjbGFyYXRpb24uaXNJbk9wdERlcHMpIHx8XG4gICAgKGRlcHNPcHRpb25zLmFsbG93QnVuZGxlZERlcHMgJiYgcmVhbFBhY2thZ2VOYW1lRGVjbGFyYXRpb24uaXNJbkJ1bmRsZWREZXBzKVxuICApIHtcbiAgICByZXR1cm47XG4gIH1cblxuICBpZiAoKFxuICAgIGltcG9ydFBhY2thZ2VOYW1lRGVjbGFyYXRpb24uaXNJbkRldkRlcHMgfHxcbiAgICByZWFsUGFja2FnZU5hbWVEZWNsYXJhdGlvbi5pc0luRGV2RGVwc1xuICApICYmICFkZXBzT3B0aW9ucy5hbGxvd0RldkRlcHMpIHtcbiAgICBjb250ZXh0LnJlcG9ydChub2RlLCBkZXZEZXBFcnJvck1lc3NhZ2UocmVhbFBhY2thZ2VOYW1lKSk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgaWYgKChcbiAgICBpbXBvcnRQYWNrYWdlTmFtZURlY2xhcmF0aW9uLmlzSW5PcHREZXBzIHx8XG4gICAgcmVhbFBhY2thZ2VOYW1lRGVjbGFyYXRpb24uaXNJbk9wdERlcHNcbiAgKSAmJiAhZGVwc09wdGlvbnMuYWxsb3dPcHREZXBzKSB7XG4gICAgY29udGV4dC5yZXBvcnQobm9kZSwgb3B0RGVwRXJyb3JNZXNzYWdlKHJlYWxQYWNrYWdlTmFtZSkpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnRleHQucmVwb3J0KG5vZGUsIG1pc3NpbmdFcnJvck1lc3NhZ2UocmVhbFBhY2thZ2VOYW1lKSk7XG59XG5cbmZ1bmN0aW9uIHRlc3RDb25maWcoY29uZmlnLCBmaWxlbmFtZSkge1xuICAvLyBTaW1wbGVzdCBjb25maWd1cmF0aW9uIGZpcnN0LCBlaXRoZXIgYSBib29sZWFuIG9yIG5vdGhpbmcuXG4gIGlmICh0eXBlb2YgY29uZmlnID09PSAnYm9vbGVhbicgfHwgdHlwZW9mIGNvbmZpZyA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICByZXR1cm4gY29uZmlnO1xuICB9XG4gIC8vIEFycmF5IG9mIGdsb2JzLlxuICByZXR1cm4gY29uZmlnLnNvbWUoYyA9PiAoXG4gICAgbWluaW1hdGNoKGZpbGVuYW1lLCBjKSB8fFxuICAgIG1pbmltYXRjaChmaWxlbmFtZSwgcGF0aC5qb2luKHByb2Nlc3MuY3dkKCksIGMpKVxuICApKTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIG1ldGE6IHtcbiAgICB0eXBlOiAncHJvYmxlbScsXG4gICAgZG9jczoge1xuICAgICAgdXJsOiBkb2NzVXJsKCduby1leHRyYW5lb3VzLWRlcGVuZGVuY2llcycpLFxuICAgIH0sXG5cbiAgICBzY2hlbWE6IFtcbiAgICAgIHtcbiAgICAgICAgJ3R5cGUnOiAnb2JqZWN0JyxcbiAgICAgICAgJ3Byb3BlcnRpZXMnOiB7XG4gICAgICAgICAgJ2RldkRlcGVuZGVuY2llcyc6IHsgJ3R5cGUnOiBbJ2Jvb2xlYW4nLCAnYXJyYXknXSB9LFxuICAgICAgICAgICdvcHRpb25hbERlcGVuZGVuY2llcyc6IHsgJ3R5cGUnOiBbJ2Jvb2xlYW4nLCAnYXJyYXknXSB9LFxuICAgICAgICAgICdwZWVyRGVwZW5kZW5jaWVzJzogeyAndHlwZSc6IFsnYm9vbGVhbicsICdhcnJheSddIH0sXG4gICAgICAgICAgJ2J1bmRsZWREZXBlbmRlbmNpZXMnOiB7ICd0eXBlJzogWydib29sZWFuJywgJ2FycmF5J10gfSxcbiAgICAgICAgICAncGFja2FnZURpcic6IHsgJ3R5cGUnOiBbJ3N0cmluZycsICdhcnJheSddIH0sXG4gICAgICAgIH0sXG4gICAgICAgICdhZGRpdGlvbmFsUHJvcGVydGllcyc6IGZhbHNlLFxuICAgICAgfSxcbiAgICBdLFxuICB9LFxuXG4gIGNyZWF0ZTogZnVuY3Rpb24gKGNvbnRleHQpIHtcbiAgICBjb25zdCBvcHRpb25zID0gY29udGV4dC5vcHRpb25zWzBdIHx8IHt9O1xuICAgIGNvbnN0IGZpbGVuYW1lID0gY29udGV4dC5nZXRGaWxlbmFtZSgpO1xuICAgIGNvbnN0IGRlcHMgPSBnZXREZXBlbmRlbmNpZXMoY29udGV4dCwgb3B0aW9ucy5wYWNrYWdlRGlyKSB8fCBleHRyYWN0RGVwRmllbGRzKHt9KTtcblxuICAgIGNvbnN0IGRlcHNPcHRpb25zID0ge1xuICAgICAgYWxsb3dEZXZEZXBzOiB0ZXN0Q29uZmlnKG9wdGlvbnMuZGV2RGVwZW5kZW5jaWVzLCBmaWxlbmFtZSkgIT09IGZhbHNlLFxuICAgICAgYWxsb3dPcHREZXBzOiB0ZXN0Q29uZmlnKG9wdGlvbnMub3B0aW9uYWxEZXBlbmRlbmNpZXMsIGZpbGVuYW1lKSAhPT0gZmFsc2UsXG4gICAgICBhbGxvd1BlZXJEZXBzOiB0ZXN0Q29uZmlnKG9wdGlvbnMucGVlckRlcGVuZGVuY2llcywgZmlsZW5hbWUpICE9PSBmYWxzZSxcbiAgICAgIGFsbG93QnVuZGxlZERlcHM6IHRlc3RDb25maWcob3B0aW9ucy5idW5kbGVkRGVwZW5kZW5jaWVzLCBmaWxlbmFtZSkgIT09IGZhbHNlLFxuICAgIH07XG5cbiAgICByZXR1cm4gbW9kdWxlVmlzaXRvcigoc291cmNlLCBub2RlKSA9PiB7XG4gICAgICByZXBvcnRJZk1pc3NpbmcoY29udGV4dCwgZGVwcywgZGVwc09wdGlvbnMsIG5vZGUsIHNvdXJjZS52YWx1ZSk7XG4gICAgfSwgeyBjb21tb25qczogdHJ1ZSB9KTtcbiAgfSxcbn07XG4iXX0=