UNPKG

eslint-plugin-import-order-autofix

Version:
314 lines (258 loc) 35.2 kB
'use strict'; var _os = require('os'); var _importType = require('../core/importType'); var _importType2 = _interopRequireDefault(_importType); var _staticRequire = require('../core/staticRequire'); var _staticRequire2 = _interopRequireDefault(_staticRequire); var _babelEslint = require('babel-eslint'); var _babelEslint2 = _interopRequireDefault(_babelEslint); var _jscodeshift = require('jscodeshift'); var _jscodeshift2 = _interopRequireDefault(_jscodeshift); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } require('./../core/add-types'); const j = _jscodeshift2.default.withParser(_babelEslint2.default); _jscodeshift2.default.types.Type.def('ExperimentalSpreadProperty').bases('Node'); _jscodeshift2.default.types.Type.def('ExperimentalRestProperty').bases('Node'); _jscodeshift2.default.types.finalize(); const defaultGroups = ['builtin', 'external', 'parent', 'sibling', 'index']; // REPORTING function reverse(array) { return array.map(function (v) { return { name: v.name, rank: -v.rank, node: v.node }; }).reverse(); } function findOutOfOrder(imported) { if (imported.length === 0) { return []; } let maxSeenRankNode = imported[0]; return imported.filter(function (importedModule) { const res = importedModule.rank < maxSeenRankNode.rank; if (maxSeenRankNode.rank < importedModule.rank) { maxSeenRankNode = importedModule; } return res; }); } function findRootNode(j, root, node) { let result = null; root.find(j.Node).filter(p => p.node === node).forEach(p => { let parent = p; while (parent.parent != null && parent.parent.value.body == null) { parent = parent.parent; } result = parent; }); return result; } function fixOutOfOrder(context, firstNode, secondNode, order) { const sourceCode = context.getSourceCode(); const root = j(sourceCode.ast); const firstRoot = findRootNode(j, root, firstNode.node); const secondRoot = findRootNode(j, root, secondNode.node); const newCode = sourceCode.getText(secondRoot.node); const msg = () => `\`${ secondNode.name }\` import should occur ${ order }` + ` import \`${ firstNode.name }\``; if (order === 'before') { context.report({ node: secondNode.node, message: msg(), fix: fixer => fixer.insertTextBefore(firstRoot.node, newCode) }); } else if (order === 'after') { context.report({ node: secondNode.node, message: msg(), fix: fixer => fixer.insertTextAfter(firstRoot.node, newCode) }); } context.report({ node: secondNode.node, message: msg(), fix: fixer => fixer.remove(secondRoot.node) }); } function reportOutOfOrder(context, imported, outOfOrder, order) { outOfOrder.forEach(function (imp) { const found = imported.find(function hasHigherRank(importedItem) { return importedItem.rank > imp.rank; }); fixOutOfOrder(context, found, imp, order); }); } function makeOutOfOrderReport(context, imported) { const outOfOrder = findOutOfOrder(imported); if (!outOfOrder.length) { return; } // There are things to report. Try to minimize the number of reported errors. const reversedImported = reverse(imported); const reversedOrder = findOutOfOrder(reversedImported); if (reversedOrder.length < outOfOrder.length) { reportOutOfOrder(context, reversedImported, reversedOrder, 'after'); return; } reportOutOfOrder(context, imported, outOfOrder, 'before'); } // DETECTING function computeRank(context, ranks, name, type) { return ranks[(0, _importType2.default)(name, context)] + (type === 'import' ? 0 : 100); } function registerNode(context, node, name, type, ranks, imported) { const rank = computeRank(context, ranks, name, type); if (rank !== -1) { imported.push({ name, rank, node }); } } function isInVariableDeclarator(node) { return node && (node.type === 'VariableDeclarator' || isInVariableDeclarator(node.parent)); } const types = ['builtin', 'external', 'internal', 'parent', 'sibling', 'index']; // Creates an object with type-rank pairs. // Example: { index: 0, sibling: 1, parent: 1, external: 1, builtin: 2, internal: 2 } // Will throw an error if it contains a type that does not exist, or has a duplicate function convertGroupsToRanks(groups) { const rankObject = groups.reduce(function (res, group, index) { if (typeof group === 'string') { group = [group]; } group.forEach(function (groupItem) { if (types.indexOf(groupItem) === -1) { throw new Error('Incorrect configuration of the rule: Unknown type `' + JSON.stringify(groupItem) + '`'); } if (res[groupItem] !== undefined) { throw new Error('Incorrect configuration of the rule: `' + groupItem + '` is duplicated'); } res[groupItem] = index; }); return res; }, {}); const omittedTypes = types.filter(function (type) { return rankObject[type] === undefined; }); return omittedTypes.reduce(function (res, type) { res[type] = groups.length; return res; }, rankObject); } function fixNewLineAfterImport(context, previousImport) { const root = j(context.getSourceCode().ast); const prevRoot = findRootNode(j, root, previousImport.node); return fixer => fixer.insertTextAfter(prevRoot.node, _os.EOL); } function removeNewLineAfterImport(context, currentImport, previousImport) { const root = j(context.getSourceCode().ast); const prevRoot = findRootNode(j, root, previousImport.node); const currRoot = findRootNode(j, root, currentImport.node); return fixer => fixer.removeRange([prevRoot.node.range[1] + 1, currRoot.node.range[0]]); } function makeNewlinesBetweenReport(context, imported, newlinesBetweenImports) { const getNumberOfEmptyLinesBetween = (currentImport, previousImport) => { const linesBetweenImports = context.getSourceCode().lines.slice(previousImport.node.loc.end.line, currentImport.node.loc.start.line - 1); return linesBetweenImports.filter(line => !line.trim().length).length; }; let previousImport = imported[0]; imported.slice(1).forEach(function (currentImport) { const emptyLinesCount = getNumberOfEmptyLinesBetween(currentImport, previousImport); if (newlinesBetweenImports === 'always') { if (currentImport.rank !== previousImport.rank && emptyLinesCount === 0) { context.report({ node: previousImport.node, message: 'There should be at least one empty line between import groups', fix: fixNewLineAfterImport(context, previousImport) }); } else if (currentImport.rank === previousImport.rank && emptyLinesCount > 0) { context.report({ node: previousImport.node, message: 'There should be no empty line within import group', fix: removeNewLineAfterImport(context, currentImport, previousImport) }); } } else if (emptyLinesCount > 0) { context.report({ node: previousImport.node, message: 'There should be no empty line between import groups', fix: removeNewLineAfterImport(context, currentImport, previousImport) }); } previousImport = currentImport; }); } module.exports = { meta: { docs: {}, fixable: 'code', schema: [{ type: 'object', properties: { groups: { type: 'array' }, 'newlines-between': { enum: ['ignore', 'always', 'never'] } }, additionalProperties: false }] }, create: function importOrderRule(context) { const options = context.options[0] || {}; const newlinesBetweenImports = options['newlines-between'] || 'ignore'; let ranks; try { ranks = convertGroupsToRanks(options.groups || defaultGroups); } catch (error) { // Malformed configuration return { Program: function (node) { context.report(node, error.message); } }; } let imported = []; let level = 0; function incrementLevel() { level++; } function decrementLevel() { level--; } return { ImportDeclaration: function handleImports(node) { if (node.specifiers.length) { // Ignoring unassigned imports const name = node.source.value; registerNode(context, node, name, 'import', ranks, imported); } }, CallExpression: function handleRequires(node) { if (level !== 0 || !(0, _staticRequire2.default)(node) || !isInVariableDeclarator(node.parent)) { return; } const name = node.arguments[0].value; registerNode(context, node, name, 'require', ranks, imported); }, 'Program:exit': function reportAndReset() { makeOutOfOrderReport(context, imported); if (newlinesBetweenImports !== 'ignore') { makeNewlinesBetweenReport(context, imported, newlinesBetweenImports); } imported = []; }, FunctionDeclaration: incrementLevel, FunctionExpression: incrementLevel, ArrowFunctionExpression: incrementLevel, BlockStatement: incrementLevel, ObjectExpression: incrementLevel, 'FunctionDeclaration:exit': decrementLevel, 'FunctionExpression:exit': decrementLevel, 'ArrowFunctionExpression:exit': decrementLevel, 'BlockStatement:exit': decrementLevel, 'ObjectExpression:exit': decrementLevel }; } }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInJ1bGVzL29yZGVyLmpzIl0sIm5hbWVzIjpbInJlcXVpcmUiLCJqIiwid2l0aFBhcnNlciIsInR5cGVzIiwiVHlwZSIsImRlZiIsImJhc2VzIiwiZmluYWxpemUiLCJkZWZhdWx0R3JvdXBzIiwicmV2ZXJzZSIsImFycmF5IiwibWFwIiwidiIsIm5hbWUiLCJyYW5rIiwibm9kZSIsImZpbmRPdXRPZk9yZGVyIiwiaW1wb3J0ZWQiLCJsZW5ndGgiLCJtYXhTZWVuUmFua05vZGUiLCJmaWx0ZXIiLCJpbXBvcnRlZE1vZHVsZSIsInJlcyIsImZpbmRSb290Tm9kZSIsInJvb3QiLCJyZXN1bHQiLCJmaW5kIiwiTm9kZSIsInAiLCJmb3JFYWNoIiwicGFyZW50IiwidmFsdWUiLCJib2R5IiwiZml4T3V0T2ZPcmRlciIsImNvbnRleHQiLCJmaXJzdE5vZGUiLCJzZWNvbmROb2RlIiwib3JkZXIiLCJzb3VyY2VDb2RlIiwiZ2V0U291cmNlQ29kZSIsImFzdCIsImZpcnN0Um9vdCIsInNlY29uZFJvb3QiLCJuZXdDb2RlIiwiZ2V0VGV4dCIsIm1zZyIsInJlcG9ydCIsIm1lc3NhZ2UiLCJmaXgiLCJmaXhlciIsImluc2VydFRleHRCZWZvcmUiLCJpbnNlcnRUZXh0QWZ0ZXIiLCJyZW1vdmUiLCJyZXBvcnRPdXRPZk9yZGVyIiwib3V0T2ZPcmRlciIsImltcCIsImZvdW5kIiwiaGFzSGlnaGVyUmFuayIsImltcG9ydGVkSXRlbSIsIm1ha2VPdXRPZk9yZGVyUmVwb3J0IiwicmV2ZXJzZWRJbXBvcnRlZCIsInJldmVyc2VkT3JkZXIiLCJjb21wdXRlUmFuayIsInJhbmtzIiwidHlwZSIsInJlZ2lzdGVyTm9kZSIsInB1c2giLCJpc0luVmFyaWFibGVEZWNsYXJhdG9yIiwiY29udmVydEdyb3Vwc1RvUmFua3MiLCJncm91cHMiLCJyYW5rT2JqZWN0IiwicmVkdWNlIiwiZ3JvdXAiLCJpbmRleCIsImdyb3VwSXRlbSIsImluZGV4T2YiLCJFcnJvciIsIkpTT04iLCJzdHJpbmdpZnkiLCJ1bmRlZmluZWQiLCJvbWl0dGVkVHlwZXMiLCJmaXhOZXdMaW5lQWZ0ZXJJbXBvcnQiLCJwcmV2aW91c0ltcG9ydCIsInByZXZSb290IiwicmVtb3ZlTmV3TGluZUFmdGVySW1wb3J0IiwiY3VycmVudEltcG9ydCIsImN1cnJSb290IiwicmVtb3ZlUmFuZ2UiLCJyYW5nZSIsIm1ha2VOZXdsaW5lc0JldHdlZW5SZXBvcnQiLCJuZXdsaW5lc0JldHdlZW5JbXBvcnRzIiwiZ2V0TnVtYmVyT2ZFbXB0eUxpbmVzQmV0d2VlbiIsImxpbmVzQmV0d2VlbkltcG9ydHMiLCJsaW5lcyIsInNsaWNlIiwibG9jIiwiZW5kIiwibGluZSIsInN0YXJ0IiwidHJpbSIsImVtcHR5TGluZXNDb3VudCIsIm1vZHVsZSIsImV4cG9ydHMiLCJtZXRhIiwiZG9jcyIsImZpeGFibGUiLCJzY2hlbWEiLCJwcm9wZXJ0aWVzIiwiZW51bSIsImFkZGl0aW9uYWxQcm9wZXJ0aWVzIiwiY3JlYXRlIiwiaW1wb3J0T3JkZXJSdWxlIiwib3B0aW9ucyIsImVycm9yIiwiUHJvZ3JhbSIsImxldmVsIiwiaW5jcmVtZW50TGV2ZWwiLCJkZWNyZW1lbnRMZXZlbCIsIkltcG9ydERlY2xhcmF0aW9uIiwiaGFuZGxlSW1wb3J0cyIsInNwZWNpZmllcnMiLCJzb3VyY2UiLCJDYWxsRXhwcmVzc2lvbiIsImhhbmRsZVJlcXVpcmVzIiwiYXJndW1lbnRzIiwicmVwb3J0QW5kUmVzZXQiLCJGdW5jdGlvbkRlY2xhcmF0aW9uIiwiRnVuY3Rpb25FeHByZXNzaW9uIiwiQXJyb3dGdW5jdGlvbkV4cHJlc3Npb24iLCJCbG9ja1N0YXRlbWVudCIsIk9iamVjdEV4cHJlc3Npb24iXSwibWFwcGluZ3MiOiJBQUFBOztBQUlBOztBQUNBOzs7O0FBQ0E7Ozs7QUFDQTs7OztBQUVBOzs7Ozs7QUFQQUEsUUFBUSxxQkFBUjs7QUFRQSxNQUFNQyxJQUFJLHNCQUFZQyxVQUFaLHVCQUFWOztBQUVBLHNCQUFZQyxLQUFaLENBQWtCQyxJQUFsQixDQUF1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QTVCLEVBQWtDLFFBQWxDLEVBQTRDa0QsS0FBNUMsRUFBbUQ5QyxRQUFuRDtBQUNEO0FBQ0YsT0FOSTtBQU9MeUcsc0JBQWdCLFNBQVNDLGNBQVQsQ0FBd0I1RyxJQUF4QixFQUE4QjtBQUM1QyxZQUFJb0csVUFBVSxDQUFWLElBQWUsQ0FBQyw2QkFBZ0JwRyxJQUFoQixDQUFoQixJQUF5QyxDQUFDb0QsdUJBQXVCcEQsS0FBS2UsTUFBNUIsQ0FBOUMsRUFBbUY7QUFDakY7QUFDRDtBQUNELGNBQU1qQixPQUFPRSxLQUFLNkcsU0FBTCxDQUFlLENBQWYsRUFBa0I3RixLQUEvQjtBQUNBa0MscUJBQWEvQixPQUFiLEVBQXNCbkIsSUFBdEIsRUFBNEJGLElBQTVCLEVBQWtDLFNBQWxDLEVBQTZDa0QsS0FBN0MsRUFBb0Q5QyxRQUFwRDtBQUNELE9BYkk7QUFjTCxzQkFBZ0IsU0FBUzRHLGNBQVQsR0FBMEI7QUFDeENsRSw2QkFBcUJ6QixPQUFyQixFQUE4QmpCLFFBQTlCOztBQUVBLFlBQUl5RSwyQkFBMkIsUUFBL0IsRUFBeUM7QUFDdkNELG9DQUEwQnZELE9BQTFCLEVBQW1DakIsUUFBbkMsRUFBNkN5RSxzQkFBN0M7QUFDRDs7QUFFRHpFLG1CQUFXLEVBQVg7QUFDRCxPQXRCSTtBQXVCTDZHLDJCQUFxQlYsY0F2QmhCO0FBd0JMVywwQkFBb0JYLGNBeEJmO0FBeUJMWSwrQkFBeUJaLGNBekJwQjtBQTBCTGEsc0JBQWdCYixjQTFCWDtBQTJCTGMsd0JBQWtCZCxjQTNCYjtBQTRCTCxrQ0FBNEJDLGNBNUJ2QjtBQTZCTCxpQ0FBMkJBLGNBN0J0QjtBQThCTCxzQ0FBZ0NBLGNBOUIzQjtBQStCTCw2QkFBdUJBLGNBL0JsQjtBQWdDTCwrQkFBeUJBO0FBaENwQixLQUFQO0FBa0NEO0FBL0VjLENBQWpCIiwiZmlsZSI6InJ1bGVzL29yZGVyLmpzIiwic291cmNlc0NvbnRlbnQiOlsiJ3VzZSBzdHJpY3QnXG5cbnJlcXVpcmUoJy4vLi4vY29yZS9hZGQtdHlwZXMnKTtcblxuaW1wb3J0IHsgRU9MIH0gZnJvbSAnb3MnO1xuaW1wb3J0IGltcG9ydFR5cGUgZnJvbSAnLi4vY29yZS9pbXBvcnRUeXBlJ1xuaW1wb3J0IGlzU3RhdGljUmVxdWlyZSBmcm9tICcuLi9jb3JlL3N0YXRpY1JlcXVpcmUnXG5pbXBvcnQgcGFyc2VyIGZyb20gJ2JhYmVsLWVzbGludCc7XG5cbmltcG9ydCBqc2NvZGVzaGlmdCBmcm9tICdqc2NvZGVzaGlmdCc7XG5jb25zdCBqID0ganNjb2Rlc2hpZnQud2l0aFBhcnNlcihwYXJzZXIpO1xuXG5qc2NvZGVzaGlmdC50eXBlcy5UeXBlLmRlZignRXhwZXJpbWVudGFsU3ByZWFkUHJvcGVydHknKS5iYXNlcygnTm9kZScpO1xuanNjb2Rlc2hpZnQudHlwZXMuVHlwZS5kZWYoJ0V4cGVyaW1lbnRhbFJlc3RQcm9wZXJ0eScpLmJhc2VzKCdOb2RlJyk7XG5cbmpzY29kZXNoaWZ0LnR5cGVzLmZpbmFsaXplKCk7XG5cbmNvbnN0IGRlZmF1bHRHcm91cHMgPSBbJ2J1aWx0aW4nLCAnZXh0ZXJuYWwnLCAncGFyZW50JywgJ3NpYmxpbmcnLCAnaW5kZXgnXVxuXG4vLyBSRVBPUlRJTkdcblxuZnVuY3Rpb24gcmV2ZXJzZShhcnJheSkge1xuICByZXR1cm4gYXJyYXkubWFwKGZ1bmN0aW9uICh2KSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG5hbWU6IHYubmFtZSxcbiAgICAgIHJhbms6IC12LnJhbmssXG4gICAgICBub2RlOiB2Lm5vZGUsXG4gICAgfVxuICB9KS5yZXZlcnNlKClcbn1cblxuZnVuY3Rpb24gZmluZE91dE9mT3JkZXIoaW1wb3J0ZWQpIHtcbiAgaWYgKGltcG9ydGVkLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBbXVxuICB9XG4gIGxldCBtYXhTZWVuUmFua05vZGUgPSBpbXBvcnRlZFswXVxuICByZXR1cm4gaW1wb3J0ZWQuZmlsdGVyKGZ1bmN0aW9uIChpbXBvcnRlZE1vZHVsZSkge1xuICAgIGNvbnN0IHJlcyA9IGltcG9ydGVkTW9kdWxlLnJhbmsgPCBtYXhTZWVuUmFua05vZGUucmFua1xuICAgIGlmIChtYXhTZWVuUmFua05vZGUucmFuayA8IGltcG9ydGVkTW9kdWxlLnJhbmspIHtcbiAgICAgIG1heFNlZW5SYW5rTm9kZSA9IGltcG9ydGVkTW9kdWxlXG4gICAgfVxuICAgIHJldHVybiByZXNcbiAgfSlcbn1cblxuXG5mdW5jdGlvbiBmaW5kUm9vdE5vZGUoaiwgcm9vdCwgbm9kZSkge1xuICBsZXQgcmVzdWx0ID0gbnVsbDtcblxuICByb290XG4gICAgLmZpbmQoai5Ob2RlKVxuICAgIC5maWx0ZXIoKHApID0+IHAubm9kZSA9PT0gbm9kZSkuZm9yRWFjaChwID0+IHtcbiAgICBsZXQgcGFyZW50ID0gcDtcblxuICAgIHdoaWxlIChwYXJlbnQucGFyZW50ICE9IG51bGwgJiYgcGFyZW50LnBhcmVudC52YWx1ZS5ib2R5ID09IG51bGwpIHtcbiAgICAgIHBhcmVudCA9IHBhcmVudC5wYXJlbnQ7XG4gICAgfVxuXG4gICAgcmVzdWx0ID0gcGFyZW50O1xuICB9KTtcblxuICByZXR1cm4gcmVzdWx0O1xufVxuXG5mdW5jdGlvbiBmaXhPdXRPZk9yZGVyKGNvbnRleHQsIGZpcnN0Tm9kZSwgc2Vjb25kTm9kZSwgb3JkZXIpIHtcbiAgY29uc3Qgc291cmNlQ29kZSA9IGNvbnRleHQuZ2V0U291cmNlQ29kZSgpO1xuICBjb25zdCByb290ID0gaihzb3VyY2VDb2RlLmFzdCk7XG5cbiAgY29uc3QgZmlyc3RSb290ID0gZmluZFJvb3ROb2RlKGosIHJvb3QsIGZpcnN0Tm9kZS5ub2RlKTtcbiAgY29uc3Qgc2Vjb25kUm9vdCA9IGZpbmRSb290Tm9kZShqLCByb290LCBzZWNvbmROb2RlLm5vZGUpO1xuICBjb25zdCBuZXdDb2RlID0gc291cmNlQ29kZS5nZXRUZXh0KHNlY29uZFJvb3Qubm9kZSk7XG5cbiAgY29uc3QgbXNnID0gKCkgPT4gYFxcYCR7c2Vjb25kTm9kZS5uYW1lfVxcYCBpbXBvcnQgc2hvdWxkIG9jY3VyICR7b3JkZXJ9YCArXG4gICAgYCBpbXBvcnQgXFxgJHtmaXJzdE5vZGUubmFtZX1cXGBgO1xuXG4gIGlmIChvcmRlciA9PT0gJ2JlZm9yZScpIHtcbiAgICBjb250ZXh0LnJlcG9ydCh7XG4gICAgICBub2RlOiBzZWNvbmROb2RlLm5vZGUsXG4gICAgICBtZXNzYWdlOiBtc2coKSxcbiAgICAgIGZpeDogZml4ZXIgPT4gZml4ZXIuaW5zZXJ0VGV4dEJlZm9yZShmaXJzdFJvb3Qubm9kZSwgbmV3Q29kZSlcbiAgICB9KTtcbiAgfSBlbHNlIGlmIChvcmRlciA9PT0gJ2FmdGVyJykge1xuICAgIGNvbnRleHQucmVwb3J0KHtcbiAgICAgIG5vZGU6IHNlY29uZE5vZGUubm9kZSxcbiAgICAgIG1lc3NhZ2U6IG1zZygpLFxuICAgICAgZml4OiBmaXhlciA9PiBmaXhlci5pbnNlcnRUZXh0QWZ0ZXIoZmlyc3RSb290Lm5vZGUsIG5ld0NvZGUpXG4gICAgfSk7XG4gIH1cblxuICBjb250ZXh0LnJlcG9ydCh7XG4gICAgbm9kZTogc2Vjb25kTm9kZS5ub2RlLFxuICAgIG1lc3NhZ2U6IG1zZygpLFxuICAgIGZpeDogZml4ZXIgPT4gZml4ZXIucmVtb3ZlKHNlY29uZFJvb3Qubm9kZSlcbiAgfSk7XG59XG5cbmZ1bmN0aW9uIHJlcG9ydE91dE9mT3JkZXIoY29udGV4dCwgaW1wb3J0ZWQsIG91dE9mT3JkZXIsIG9yZGVyKSB7XG4gIG91dE9mT3JkZXIuZm9yRWFjaChmdW5jdGlvbiAoaW1wKSB7XG4gICAgY29uc3QgZm91bmQgPSBpbXBvcnRlZC5maW5kKGZ1bmN0aW9uIGhhc0hpZ2hlclJhbmsoaW1wb3J0ZWRJdGVtKSB7XG4gICAgICByZXR1cm4gaW1wb3J0ZWRJdGVtLnJhbmsgPiBpbXAucmFua1xuICAgIH0pXG4gICAgZml4T3V0T2ZPcmRlcihjb250ZXh0LCBmb3VuZCwgaW1wLCBvcmRlcik7XG4gIH0pXG59XG5cbmZ1bmN0aW9uIG1ha2VPdXRPZk9yZGVyUmVwb3J0KGNvbnRleHQsIGltcG9ydGVkKSB7XG4gIGNvbnN0IG91dE9mT3JkZXIgPSBmaW5kT3V0T2ZPcmRlcihpbXBvcnRlZClcbiAgaWYgKCFvdXRPZk9yZGVyLmxlbmd0aCkge1xuICAgIHJldHVyblxuICB9XG4gIC8vIFRoZXJlIGFyZSB0aGluZ3MgdG8gcmVwb3J0LiBUcnkgdG8gbWluaW1pemUgdGhlIG51bWJlciBvZiByZXBvcnRlZCBlcnJvcnMuXG4gIGNvbnN0IHJldmVyc2VkSW1wb3J0ZWQgPSByZXZlcnNlKGltcG9ydGVkKVxuICBjb25zdCByZXZlcnNlZE9yZGVyID0gZmluZE91dE9mT3JkZXIocmV2ZXJzZWRJbXBvcnRlZClcbiAgaWYgKHJldmVyc2VkT3JkZXIubGVuZ3RoIDwgb3V0T2ZPcmRlci5sZW5ndGgpIHtcbiAgICByZXBvcnRPdXRPZk9yZGVyKGNvbnRleHQsIHJldmVyc2VkSW1wb3J0ZWQsIHJldmVyc2VkT3JkZXIsICdhZnRlcicpXG4gICAgcmV0dXJuXG4gIH1cbiAgcmVwb3J0T3V0T2ZPcmRlcihjb250ZXh0LCBpbXBvcnRlZCwgb3V0T2ZPcmRlciwgJ2JlZm9yZScpXG59XG5cbi8vIERFVEVDVElOR1xuXG5mdW5jdGlvbiBjb21wdXRlUmFuayhjb250ZXh0LCByYW5rcywgbmFtZSwgdHlwZSkge1xuICByZXR1cm4gcmFua3NbaW1wb3J0VHlwZShuYW1lLCBjb250ZXh0KV0gK1xuICAgICh0eXBlID09PSAnaW1wb3J0JyA/IDAgOiAxMDApXG59XG5cbmZ1bmN0aW9uIHJlZ2lzdGVyTm9kZShjb250ZXh0LCBub2RlLCBuYW1lLCB0eXBlLCByYW5rcywgaW1wb3J0ZWQpIHtcbiAgY29uc3QgcmFuayA9IGNvbXB1dGVSYW5rKGNvbnRleHQsIHJhbmtzLCBuYW1lLCB0eXBlKVxuICBpZiAocmFuayAhPT0gLTEpIHtcbiAgICBpbXBvcnRlZC5wdXNoKHtuYW1lLCByYW5rLCBub2RlfSlcbiAgfVxufVxuXG5mdW5jdGlvbiBpc0luVmFyaWFibGVEZWNsYXJhdG9yKG5vZGUpIHtcbiAgcmV0dXJuIG5vZGUgJiZcbiAgICAobm9kZS50eXBlID09PSAnVmFyaWFibGVEZWNsYXJhdG9yJyB8fCBpc0luVmFyaWFibGVEZWNsYXJhdG9yKG5vZGUucGFyZW50KSlcbn1cblxuY29uc3QgdHlwZXMgPSBbJ2J1aWx0aW4nLCAnZXh0ZXJuYWwnLCAnaW50ZXJuYWwnLCAncGFyZW50JywgJ3NpYmxpbmcnLCAnaW5kZXgnXVxuXG4vLyBDcmVhdGVzIGFuIG9iamVjdCB3aXRoIHR5cGUtcmFuayBwYWlycy5cbi8vIEV4YW1wbGU6IHsgaW5kZXg6IDAsIHNpYmxpbmc6IDEsIHBhcmVudDogMSwgZXh0ZXJuYWw6IDEsIGJ1aWx0aW46IDIsIGludGVybmFsOiAyIH1cbi8vIFdpbGwgdGhyb3cgYW4gZXJyb3IgaWYgaXQgY29udGFpbnMgYSB0eXBlIHRoYXQgZG9lcyBub3QgZXhpc3QsIG9yIGhhcyBhIGR1cGxpY2F0ZVxuZnVuY3Rpb24gY29udmVydEdyb3Vwc1RvUmFua3MoZ3JvdXBzKSB7XG4gIGNvbnN0IHJhbmtPYmplY3QgPSBncm91cHMucmVkdWNlKGZ1bmN0aW9uKHJlcywgZ3JvdXAsIGluZGV4KSB7XG4gICAgaWYgKHR5cGVvZiBncm91cCA9PT0gJ3N0cmluZycpIHtcbiAgICAgIGdyb3VwID0gW2dyb3VwXVxuICAgIH1cbiAgICBncm91cC5mb3JFYWNoKGZ1bmN0aW9uKGdyb3VwSXRlbSkge1xuICAgICAgaWYgKHR5cGVzLmluZGV4T2YoZ3JvdXBJdGVtKSA9PT0gLTEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbmNvcnJlY3QgY29uZmlndXJhdGlvbiBvZiB0aGUgcnVsZTogVW5rbm93biB0eXBlIGAnICtcbiAgICAgICAgICBKU09OLnN0cmluZ2lmeShncm91cEl0ZW0pICsgJ2AnKVxuICAgICAgfVxuICAgICAgaWYgKHJlc1tncm91cEl0ZW1dICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbmNvcnJlY3QgY29uZmlndXJhdGlvbiBvZiB0aGUgcnVsZTogYCcgKyBncm91cEl0ZW0gKyAnYCBpcyBkdXBsaWNhdGVkJylcbiAgICAgIH1cbiAgICAgIHJlc1tncm91cEl0ZW1dID0gaW5kZXhcbiAgICB9KVxuICAgIHJldHVybiByZXNcbiAgfSwge30pXG5cbiAgY29uc3Qgb21pdHRlZFR5cGVzID0gdHlwZXMuZmlsdGVyKGZ1bmN0aW9uKHR5cGUpIHtcbiAgICByZXR1cm4gcmFua09iamVjdFt0eXBlXSA9PT0gdW5kZWZpbmVkXG4gIH0pXG5cbiAgcmV0dXJuIG9taXR0ZWRUeXBlcy5yZWR1Y2UoZnVuY3Rpb24ocmVzLCB0eXBlKSB7XG4gICAgcmVzW3R5cGVdID0gZ3JvdXBzLmxlbmd0aFxuICAgIHJldHVybiByZXNcbiAgfSwgcmFua09iamVjdClcbn1cblxuZnVuY3Rpb24gZml4TmV3TGluZUFmdGVySW1wb3J0KGNvbnRleHQsIHByZXZpb3VzSW1wb3J0KSB7XG4gIGNvbnN0IHJvb3QgPSBqKGNvbnRleHQuZ2V0U291cmNlQ29kZSgpLmFzdCk7XG5cbiAgY29uc3QgcHJldlJvb3QgPSBmaW5kUm9vdE5vZGUoaiwgcm9vdCwgcHJldmlvdXNJbXBvcnQubm9kZSk7XG5cbiAgcmV0dXJuIChmaXhlcikgPT4gZml4ZXIuaW5zZXJ0VGV4dEFmdGVyKHByZXZSb290Lm5vZGUsIEVPTCk7XG59XG5cbmZ1bmN0aW9uIHJlbW92ZU5ld0xpbmVBZnRlckltcG9ydChjb250ZXh0LCBjdXJyZW50SW1wb3J0LCBwcmV2aW91c0ltcG9ydCkge1xuICBjb25zdCByb290ID0gaihjb250ZXh0LmdldFNvdXJjZUNvZGUoKS5hc3QpO1xuXG4gIGNvbnN0IHByZXZSb290ID0gZmluZFJvb3ROb2RlKGosIHJvb3QsIHByZXZpb3VzSW1wb3J0Lm5vZGUpO1xuICBjb25zdCBjdXJyUm9vdCA9IGZpbmRSb290Tm9kZShqLCByb290LCBjdXJyZW50SW1wb3J0Lm5vZGUpO1xuXG4gIHJldHVybiAoZml4ZXIpID0+IGZpeGVyLnJlbW92ZVJhbmdlKFtwcmV2Um9vdC5ub2RlLnJhbmdlWzFdICsgMSwgY3VyclJvb3Qubm9kZS5yYW5nZVswXV0pO1xufVxuXG5mdW5jdGlvbiBtYWtlTmV3bGluZXNCZXR3ZWVuUmVwb3J0IChjb250ZXh0LCBpbXBvcnRlZCwgbmV3bGluZXNCZXR3ZWVuSW1wb3J0cykge1xuICBjb25zdCBnZXROdW1iZXJPZkVtcHR5TGluZXNCZXR3ZWVuID0gKGN1cnJlbnRJbXBvcnQsIHByZXZpb3VzSW1wb3J0KSA9PiB7XG4gICAgY29uc3QgbGluZXNCZXR3ZWVuSW1wb3J0cyA9IGNvbnRleHQuZ2V0U291cmNlQ29kZSgpLmxpbmVzLnNsaWNlKFxuICAgICAgcHJldmlvdXNJbXBvcnQubm9kZS5sb2MuZW5kLmxpbmUsXG4gICAgICBjdXJyZW50SW1wb3J0Lm5vZGUubG9jLnN0YXJ0LmxpbmUgLSAxXG4gICAgKVxuXG4gICAgcmV0dXJuIGxpbmVzQmV0d2VlbkltcG9ydHMuZmlsdGVyKChsaW5lKSA9PiAhbGluZS50cmltKCkubGVuZ3RoKS5sZW5ndGhcbiAgfVxuXG4gIGxldCBwcmV2aW91c0ltcG9ydCA9IGltcG9ydGVkWzBdXG5cbiAgaW1wb3J0ZWQuc2xpY2UoMSkuZm9yRWFjaChmdW5jdGlvbihjdXJyZW50SW1wb3J0KSB7XG4gICAgY29uc3QgZW1wdHlMaW5lc0NvdW50ID0gZ2V0TnVtYmVyT2ZFbXB0eUxpbmVzQmV0d2VlbihjdXJyZW50SW1wb3J0LCBwcmV2aW91c0ltcG9ydCk7XG4gICAgaWYgKG5ld2xpbmVzQmV0d2VlbkltcG9ydHMgPT09ICdhbHdheXMnKSB7XG4gICAgICBpZiAoY3VycmVudEltcG9ydC5yYW5rICE9PSBwcmV2aW91c0ltcG9ydC5yYW5rICYmIGVtcHR5TGluZXNDb3VudCA9PT0gMCkge1xuICAgICAgICBjb250ZXh0LnJlcG9ydCh7XG4gICAgICAgICAgbm9kZTogcHJldmlvdXNJbXBvcnQubm9kZSxcbiAgICAgICAgICBtZXNzYWdlOiAnVGhlcmUgc2hvdWxkIGJlIGF0IGxlYXN0IG9uZSBlbXB0eSBsaW5lIGJldHdlZW4gaW1wb3J0IGdyb3VwcycsXG4gICAgICAgICAgZml4OiBmaXhOZXdMaW5lQWZ0ZXJJbXBvcnQoY29udGV4dCwgcHJldmlvdXNJbXBvcnQpXG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIGlmIChjdXJyZW50SW1wb3J0LnJhbmsgPT09IHByZXZpb3VzSW1wb3J0LnJhbmsgJiYgZW1wdHlMaW5lc0NvdW50ID4gMCkge1xuICAgICAgICBjb250ZXh0LnJlcG9ydCh7XG4gICAgICAgICAgbm9kZTogcHJldmlvdXNJbXBvcnQubm9kZSxcbiAgICAgICAgICBtZXNzYWdlOiAnVGhlcmUgc2hvdWxkIGJlIG5vIGVtcHR5IGxpbmUgd2l0aGluIGltcG9ydCBncm91cCcsXG4gICAgICAgICAgZml4OiByZW1vdmVOZXdMaW5lQWZ0ZXJJbXBvcnQoY29udGV4dCwgY3VycmVudEltcG9ydCwgcHJldmlvdXNJbXBvcnQpXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoZW1wdHlMaW5lc0NvdW50ID4gMCkge1xuICAgICAgY29udGV4dC5yZXBvcnQoe1xuICAgICAgICBub2RlOiBwcmV2aW91c0ltcG9ydC5ub2RlLFxuICAgICAgICBtZXNzYWdlOiAnVGhlcmUgc2hvdWxkIGJlIG5vIGVtcHR5IGxpbmUgYmV0d2VlbiBpbXBvcnQgZ3JvdXBzJyxcbiAgICAgICAgZml4OiByZW1vdmVOZXdMaW5lQWZ0ZXJJbXBvcnQoY29udGV4dCwgY3VycmVudEltcG9ydCwgcHJldmlvdXNJbXBvcnQpXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBwcmV2aW91c0ltcG9ydCA9IGN1cnJlbnRJbXBvcnRcbiAgfSlcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIG1ldGE6IHtcbiAgICBkb2NzOiB7fSxcbiAgICBmaXhhYmxlOiAnY29kZScsXG4gICAgc2NoZW1hOiBbXG4gICAgICB7XG4gICAgICAgIHR5cGU6ICdvYmplY3QnLFxuICAgICAgICBwcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgZ3JvdXBzOiB7XG4gICAgICAgICAgICB0eXBlOiAnYXJyYXknLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgJ25ld2xpbmVzLWJldHdlZW4nOiB7XG4gICAgICAgICAgICBlbnVtOiBbICdpZ25vcmUnLCAnYWx3YXlzJywgJ25ldmVyJyBdLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICAgIGFkZGl0aW9uYWxQcm9wZXJ0aWVzOiBmYWxzZSxcbiAgICAgIH0sXG4gICAgXSxcbiAgfSxcblxuICBjcmVhdGU6IGZ1bmN0aW9uIGltcG9ydE9yZGVyUnVsZSAoY29udGV4dCkge1xuICAgIGNvbnN0IG9wdGlvbnMgPSBjb250ZXh0Lm9wdGlvbnNbMF0gfHwge31cbiAgICBjb25zdCBuZXdsaW5lc0JldHdlZW5JbXBvcnRzID0gb3B0aW9uc1snbmV3bGluZXMtYmV0d2VlbiddIHx8ICdpZ25vcmUnXG4gICAgbGV0IHJhbmtzXG5cbiAgICB0cnkge1xuICAgICAgcmFua3MgPSBjb252ZXJ0R3JvdXBzVG9SYW5rcyhvcHRpb25zLmdyb3VwcyB8fCBkZWZhdWx0R3JvdXBzKVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAvLyBNYWxmb3JtZWQgY29uZmlndXJhdGlvblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgUHJvZ3JhbTogZnVuY3Rpb24obm9kZSkge1xuICAgICAgICAgIGNvbnRleHQucmVwb3J0KG5vZGUsIGVycm9yLm1lc3NhZ2UpXG4gICAgICAgIH0sXG4gICAgICB9XG4gICAgfVxuICAgIGxldCBpbXBvcnRlZCA9IFtdXG4gICAgbGV0IGxldmVsID0gMFxuXG4gICAgZnVuY3Rpb24gaW5jcmVtZW50TGV2ZWwoKSB7XG4gICAgICBsZXZlbCsrXG4gICAgfVxuICAgIGZ1bmN0aW9uIGRlY3JlbWVudExldmVsKCkge1xuICAgICAgbGV2ZWwtLVxuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBJbXBvcnREZWNsYXJhdGlvbjogZnVuY3Rpb24gaGFuZGxlSW1wb3J0cyhub2RlKSB7XG4gICAgICAgIGlmIChub2RlLnNwZWNpZmllcnMubGVuZ3RoKSB7IC8vIElnbm9yaW5nIHVuYXNzaWduZWQgaW1wb3J0c1xuICAgICAgICAgIGNvbnN0IG5hbWUgPSBub2RlLnNvdXJjZS52YWx1ZVxuICAgICAgICAgIHJlZ2lzdGVyTm9kZShjb250ZXh0LCBub2RlLCBuYW1lLCAnaW1wb3J0JywgcmFua3MsIGltcG9ydGVkKVxuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgQ2FsbEV4cHJlc3Npb246IGZ1bmN0aW9uIGhhbmRsZVJlcXVpcmVzKG5vZGUpIHtcbiAgICAgICAgaWYgKGxldmVsICE9PSAwIHx8ICFpc1N0YXRpY1JlcXVpcmUobm9kZSkgfHwgIWlzSW5WYXJpYWJsZURlY2xhcmF0b3Iobm9kZS5wYXJlbnQpKSB7XG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgbmFtZSA9IG5vZGUuYXJndW1lbnRzWzBdLnZhbHVlXG4gICAgICAgIHJlZ2lzdGVyTm9kZShjb250ZXh0LCBub2RlLCBuYW1lLCAncmVxdWlyZScsIHJhbmtzLCBpbXBvcnRlZClcbiAgICAgIH0sXG4gICAgICAnUHJvZ3JhbTpleGl0JzogZnVuY3Rpb24gcmVwb3J0QW5kUmVzZXQoKSB7XG4gICAgICAgIG1ha2VPdXRPZk9yZGVyUmVwb3J0KGNvbnRleHQsIGltcG9ydGVkKVxuXG4gICAgICAgIGlmIChuZXdsaW5lc0JldHdlZW5JbXBvcnRzICE9PSAnaWdub3JlJykge1xuICAgICAgICAgIG1ha2VOZXdsaW5lc0JldHdlZW5SZXBvcnQoY29udGV4dCwgaW1wb3J0ZWQsIG5ld2xpbmVzQmV0d2VlbkltcG9ydHMpXG4gICAgICAgIH1cblxuICAgICAgICBpbXBvcnRlZCA9IFtdXG4gICAgICB9LFxuICAgICAgRnVuY3Rpb25EZWNsYXJhdGlvbjogaW5jcmVtZW50TGV2ZWwsXG4gICAgICBGdW5jdGlvbkV4cHJlc3Npb246IGluY3JlbWVudExldmVsLFxuICAgICAgQXJyb3dGdW5jdGlvbkV4cHJlc3Npb246IGluY3JlbWVudExldmVsLFxuICAgICAgQmxvY2tTdGF0ZW1lbnQ6IGluY3JlbWVudExldmVsLFxuICAgICAgT2JqZWN0RXhwcmVzc2lvbjogaW5jcmVtZW50TGV2ZWwsXG4gICAgICAnRnVuY3Rpb25EZWNsYXJhdGlvbjpleGl0JzogZGVjcmVtZW50TGV2ZWwsXG4gICAgICAnRnVuY3Rpb25FeHByZXNzaW9uOmV4aXQnOiBkZWNyZW1lbnRMZXZlbCxcbiAgICAgICdBcnJvd0Z1bmN0aW9uRXhwcmVzc2lvbjpleGl0JzogZGVjcmVtZW50TGV2ZWwsXG4gICAgICAnQmxvY2tTdGF0ZW1lbnQ6ZXhpdCc6IGRlY3JlbWVudExldmVsLFxuICAgICAgJ09iamVjdEV4cHJlc3Npb246ZXhpdCc6IGRlY3JlbWVudExldmVsLFxuICAgIH1cbiAgfSxcbn1cbiJdfQ==