@angular/material
Version:
Angular Material
177 lines • 28.8 kB
JavaScript
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
(function (factory) {
if (typeof module === "object" && typeof module.exports === "object") {
var v = factory(require, exports);
if (v !== undefined) module.exports = v;
}
else if (typeof define === "function" && define.amd) {
define("@angular/material/schematics/ng-update/upgrade-rules/package-imports-v8/secondary-entry-points-rule", ["require", "exports", "@angular/cdk/schematics", "typescript", "@angular/material/schematics/ng-update/typescript/module-specifiers"], factory);
}
})(function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const schematics_1 = require("@angular/cdk/schematics");
const ts = require("typescript");
const module_specifiers_1 = require("@angular/material/schematics/ng-update/typescript/module-specifiers");
const ONLY_SUBPACKAGE_FAILURE_STR = `Importing from "@angular/material" is deprecated. ` +
`Instead import from the entry-point the symbol belongs to.`;
const NO_IMPORT_NAMED_SYMBOLS_FAILURE_STR = `Imports from Angular Material should import ` +
`specific symbols rather than importing the entire library.`;
/**
* Regex for testing file paths against to determine if the file is from the
* Angular Material library.
*/
const ANGULAR_MATERIAL_FILEPATH_REGEX = new RegExp(`${module_specifiers_1.materialModuleSpecifier}/(.*?)/`);
/**
* Mapping of Material symbol names to their module names. Used as a fallback if
* we didn't manage to resolve the module name of a symbol using the type checker.
*/
const ENTRY_POINT_MAPPINGS = require('./material-symbols.json');
/**
* A migration rule that updates imports which refer to the primary Angular Material
* entry-point to use the appropriate secondary entry points (e.g. @angular/material/button).
*/
class SecondaryEntryPointsRule extends schematics_1.MigrationRule {
constructor() {
super(...arguments);
this.printer = ts.createPrinter();
// Only enable this rule if the migration targets version 8. The primary
// entry-point of Material has been marked as deprecated in version 8.
this.ruleEnabled = this.targetVersion === schematics_1.TargetVersion.V8 || this.targetVersion === schematics_1.TargetVersion.V9;
}
visitNode(declaration) {
// Only look at import declarations.
if (!ts.isImportDeclaration(declaration) ||
!ts.isStringLiteralLike(declaration.moduleSpecifier)) {
return;
}
const importLocation = declaration.moduleSpecifier.text;
// If the import module is not @angular/material, skip the check.
if (importLocation !== module_specifiers_1.materialModuleSpecifier) {
return;
}
// If no import clause is found, or nothing is named as a binding in the
// import, add failure saying to import symbols in clause.
if (!declaration.importClause || !declaration.importClause.namedBindings) {
this.createFailureAtNode(declaration, NO_IMPORT_NAMED_SYMBOLS_FAILURE_STR);
return;
}
// All named bindings in import clauses must be named symbols, otherwise add
// failure saying to import symbols in clause.
if (!ts.isNamedImports(declaration.importClause.namedBindings)) {
this.createFailureAtNode(declaration, NO_IMPORT_NAMED_SYMBOLS_FAILURE_STR);
return;
}
// If no symbols are in the named bindings then add failure saying to
// import symbols in clause.
if (!declaration.importClause.namedBindings.elements.length) {
this.createFailureAtNode(declaration, NO_IMPORT_NAMED_SYMBOLS_FAILURE_STR);
return;
}
// Whether the existing import declaration is using a single quote module specifier.
const singleQuoteImport = declaration.moduleSpecifier.getText()[0] === `'`;
// Map which consists of secondary entry-points and import specifiers which are used
// within the current import declaration.
const importMap = new Map();
// Determine the subpackage each symbol in the namedBinding comes from.
for (const element of declaration.importClause.namedBindings.elements) {
const elementName = element.propertyName ? element.propertyName : element.name;
// Try to resolve the module name via the type checker, and if it fails, fall back to
// resolving it from our list of symbol to entry point mappings. Using the type checker is
// more accurate and doesn't require us to keep a list of symbols, but it won't work if
// the symbols don't exist anymore (e.g. after we remove the top-level @angular/material).
const moduleName = resolveModuleName(elementName, this.typeChecker) ||
ENTRY_POINT_MAPPINGS[elementName.text] || null;
if (!moduleName) {
this.createFailureAtNode(element, `"${element.getText()}" was not found in the Material library.`);
return;
}
// The module name where the symbol is defined e.g. card, dialog. The
// first capture group is contains the module name.
if (importMap.has(moduleName)) {
importMap.get(moduleName).push(element);
}
else {
importMap.set(moduleName, [element]);
}
}
// Transforms the import declaration into multiple import declarations that import
// the given symbols from the individual secondary entry-points. For example:
// import {MatCardModule, MatCardTitle} from '@angular/material/card';
// import {MatRadioModule} from '@angular/material/radio';
const newImportStatements = Array.from(importMap.entries())
.sort()
.map(([name, elements]) => {
const newImport = ts.createImportDeclaration(undefined, undefined, ts.createImportClause(undefined, ts.createNamedImports(elements)), createStringLiteral(`${module_specifiers_1.materialModuleSpecifier}/${name}`, singleQuoteImport));
return this.printer.printNode(ts.EmitHint.Unspecified, newImport, declaration.getSourceFile());
})
.join('\n');
// Without any import statements that were generated, we can assume that this was an empty
// import declaration. We still want to add a failure in order to make developers aware that
// importing from "@angular/material" is deprecated.
if (!newImportStatements) {
this.createFailureAtNode(declaration.moduleSpecifier, ONLY_SUBPACKAGE_FAILURE_STR);
return;
}
const recorder = this.getUpdateRecorder(declaration.moduleSpecifier.getSourceFile().fileName);
// Perform the replacement that switches the primary entry-point import to
// the individual secondary entry-point imports.
recorder.remove(declaration.getStart(), declaration.getWidth());
recorder.insertRight(declaration.getStart(), newImportStatements);
}
}
exports.SecondaryEntryPointsRule = SecondaryEntryPointsRule;
/**
* Creates a string literal from the specified text.
* @param text Text of the string literal.
* @param singleQuotes Whether single quotes should be used when printing the literal node.
*/
function createStringLiteral(text, singleQuotes) {
const literal = ts.createStringLiteral(text);
// See: https://github.com/microsoft/TypeScript/blob/master/src/compiler/utilities.ts#L584-L590
literal['singleQuote'] = singleQuotes;
return literal;
}
/** Gets the symbol that contains the value declaration of the given node. */
function getDeclarationSymbolOfNode(node, checker) {
const symbol = checker.getSymbolAtLocation(node);
// Symbols can be aliases of the declaration symbol. e.g. in named import specifiers.
// We need to resolve the aliased symbol back to the declaration symbol.
// tslint:disable-next-line:no-bitwise
if (symbol && (symbol.flags & ts.SymbolFlags.Alias) !== 0) {
return checker.getAliasedSymbol(symbol);
}
return symbol;
}
/** Tries to resolve the name of the Material module that a node is imported from. */
function resolveModuleName(node, typeChecker) {
// Get the symbol for the named binding element. Note that we cannot determine the
// value declaration based on the type of the element as types are not necessarily
// specific to a given secondary entry-point (e.g. exports with the type of "string")
// would resolve to the module types provided by TypeScript itself.
const symbol = getDeclarationSymbolOfNode(node, typeChecker);
// If the symbol can't be found, or no declaration could be found within
// the symbol, add failure to report that the given symbol can't be found.
if (!symbol ||
!(symbol.valueDeclaration || (symbol.declarations && symbol.declarations.length !== 0))) {
return null;
}
// The filename for the source file of the node that contains the
// first declaration of the symbol. All symbol declarations must be
// part of a defining node, so parent can be asserted to be defined.
const resolvedNode = symbol.valueDeclaration || symbol.declarations[0];
const sourceFile = resolvedNode.getSourceFile().fileName;
// File the module the symbol belongs to from a regex match of the
// filename. This will always match since only "@angular/material"
// elements are analyzed.
const matches = sourceFile.match(ANGULAR_MATERIAL_FILEPATH_REGEX);
return matches ? matches[1] : null;
}
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vjb25kYXJ5LWVudHJ5LXBvaW50cy1ydWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL21hdGVyaWFsL3NjaGVtYXRpY3MvbmctdXBkYXRlL3VwZ3JhZGUtcnVsZXMvcGFja2FnZS1pbXBvcnRzLXY4L3NlY29uZGFyeS1lbnRyeS1wb2ludHMtcnVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7Ozs7Ozs7Ozs7OztJQUVILHdEQUFxRTtJQUNyRSxpQ0FBaUM7SUFDakMsMkdBQXdGO0lBRXhGLE1BQU0sMkJBQTJCLEdBQUcsb0RBQW9EO1FBQ3BGLDREQUE0RCxDQUFDO0lBRWpFLE1BQU0sbUNBQW1DLEdBQUcsOENBQThDO1FBQ3RGLDREQUE0RCxDQUFDO0lBRWpFOzs7T0FHRztJQUNILE1BQU0sK0JBQStCLEdBQUcsSUFBSSxNQUFNLENBQUMsR0FBRywyQ0FBdUIsU0FBUyxDQUFDLENBQUM7SUFFeEY7OztPQUdHO0lBQ0gsTUFBTSxvQkFBb0IsR0FBNkIsT0FBTyxDQUFDLHlCQUF5QixDQUFDLENBQUM7SUFFMUY7OztPQUdHO0lBQ0gsTUFBYSx3QkFBeUIsU0FBUSwwQkFBbUI7UUFBakU7O1lBQ0UsWUFBTyxHQUFHLEVBQUUsQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUU3Qix3RUFBd0U7WUFDeEUsc0VBQXNFO1lBQ3RFLGdCQUFXLEdBQUcsSUFBSSxDQUFDLGFBQWEsS0FBSywwQkFBYSxDQUFDLEVBQUUsSUFBSSxJQUFJLENBQUMsYUFBYSxLQUFLLDBCQUFhLENBQUMsRUFBRSxDQUFDO1FBcUduRyxDQUFDO1FBbkdDLFNBQVMsQ0FBQyxXQUFvQjtZQUM1QixvQ0FBb0M7WUFDcEMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxtQkFBbUIsQ0FBQyxXQUFXLENBQUM7Z0JBQ3BDLENBQUMsRUFBRSxDQUFDLG1CQUFtQixDQUFDLFdBQVcsQ0FBQyxlQUFlLENBQUMsRUFBRTtn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LEdBQUcsVUFBVSxDQUFDLEtBQUssQ0FBQywrQkFBK0IsQ0FBQyxDQUFDO1FBQ2xFLE9BQU8sT0FBTyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztJQUNyQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IEdvb2dsZSBMTEMgQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2FuZ3VsYXIuaW8vbGljZW5zZVxuICovXG5cbmltcG9ydCB7TWlncmF0aW9uUnVsZSwgVGFyZ2V0VmVyc2lvbn0gZnJvbSAnQGFuZ3VsYXIvY2RrL3NjaGVtYXRpY3MnO1xuaW1wb3J0ICogYXMgdHMgZnJvbSAndHlwZXNjcmlwdCc7XG5pbXBvcnQge21hdGVyaWFsTW9kdWxlU3BlY2lmaWVyfSBmcm9tICcuLi8uLi8uLi9uZy11cGRhdGUvdHlwZXNjcmlwdC9tb2R1bGUtc3BlY2lmaWVycyc7XG5cbmNvbnN0IE9OTFlfU1VCUEFDS0FHRV9GQUlMVVJFX1NUUiA9IGBJbXBvcnRpbmcgZnJvbSBcIkBhbmd1bGFyL21hdGVyaWFsXCIgaXMgZGVwcmVjYXRlZC4gYCArXG4gICAgYEluc3RlYWQgaW1wb3J0IGZyb20gdGhlIGVudHJ5LXBvaW50IHRoZSBzeW1ib2wgYmVsb25ncyB0by5gO1xuXG5jb25zdCBOT19JTVBPUlRfTkFNRURfU1lNQk9MU19GQUlMVVJFX1NUUiA9IGBJbXBvcnRzIGZyb20gQW5ndWxhciBNYXRlcmlhbCBzaG91bGQgaW1wb3J0IGAgK1xuICAgIGBzcGVjaWZpYyBzeW1ib2xzIHJhdGhlciB0aGFuIGltcG9ydGluZyB0aGUgZW50aXJlIGxpYnJhcnkuYDtcblxuLyoqXG4gKiBSZWdleCBmb3IgdGVzdGluZyBmaWxlIHBhdGhzIGFnYWluc3QgdG8gZGV0ZXJtaW5lIGlmIHRoZSBmaWxlIGlzIGZyb20gdGhlXG4gKiBBbmd1bGFyIE1hdGVyaWFsIGxpYnJhcnkuXG4gKi9cbmNvbnN0IEFOR1VMQVJfTUFURVJJQUxfRklMRVBBVEhfUkVHRVggPSBuZXcgUmVnRXhwKGAke21hdGVyaWFsTW9kdWxlU3BlY2lmaWVyfS8oLio/KS9gKTtcblxuLyoqXG4gKiBNYXBwaW5nIG9mIE1hdGVyaWFsIHN5bWJvbCBuYW1lcyB0byB0aGVpciBtb2R1bGUgbmFtZXMuIFVzZWQgYXMgYSBmYWxsYmFjayBpZlxuICogd2UgZGlkbid0IG1hbmFnZSB0byByZXNvbHZlIHRoZSBtb2R1bGUgbmFtZSBvZiBhIHN5bWJvbCB1c2luZyB0aGUgdHlwZSBjaGVja2VyLlxuICovXG5jb25zdCBFTlRSWV9QT0lOVF9NQVBQSU5HUzoge1tuYW1lOiBzdHJpbmddOiBzdHJpbmd9ID0gcmVxdWlyZSgnLi9tYXRlcmlhbC1zeW1ib2xzLmpzb24nKTtcblxuLyoqXG4gKiBBIG1pZ3JhdGlvbiBydWxlIHRoYXQgdXBkYXRlcyBpbXBvcnRzIHdoaWNoIHJlZmVyIHRvIHRoZSBwcmltYXJ5IEFuZ3VsYXIgTWF0ZXJpYWxcbiAqIGVudHJ5LXBvaW50IHRvIHVzZSB0aGUgYXBwcm9wcmlhdGUgc2Vjb25kYXJ5IGVudHJ5IHBvaW50cyAoZS5nLiBAYW5ndWxhci9tYXRlcmlhbC9idXR0b24pLlxuICovXG5leHBvcnQgY2xhc3MgU2Vjb25kYXJ5RW50cnlQb2ludHNSdWxlIGV4dGVuZHMgTWlncmF0aW9uUnVsZTxudWxsPiB7XG4gIHByaW50ZXIgPSB0cy5jcmVhdGVQcmludGVyKCk7XG5cbiAgLy8gT25seSBlbmFibGUgdGhpcyBydWxlIGlmIHRoZSBtaWdyYXRpb24gdGFyZ2V0cyB2ZXJzaW9uIDguIFRoZSBwcmltYXJ5XG4gIC8vIGVudHJ5LXBvaW50IG9mIE1hdGVyaWFsIGhhcyBiZWVuIG1hcmtlZCBhcyBkZXByZWNhdGVkIGluIHZlcnNpb24gOC5cbiAgcnVsZUVuYWJsZWQgPSB0aGlzLnRhcmdldFZlcnNpb24gPT09IFRhcmdldFZlcnNpb24uVjggfHwgdGhpcy50YXJnZXRWZXJzaW9uID09PSBUYXJnZXRWZXJzaW9uLlY5O1xuXG4gIHZpc2l0Tm9kZShkZWNsYXJhdGlvbjogdHMuTm9kZSk6IHZvaWQge1xuICAgIC8vIE9ubHkgbG9vayBhdCBpbXBvcnQgZGVjbGFyYXRpb25zLlxuICAgIGlmICghdHMuaXNJbXBvcnREZWNsYXJhdGlvbihkZWNsYXJhdGlvbikgfHxcbiAgICAgICAgIXRzLmlzU3RyaW5nTGl0ZXJhbExpa2UoZGVjbGFyYXRpb24ubW9kdWxlU3BlY2lmaWVyKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IGltcG9ydExvY2F0aW9uID0gZGVjbGFyYXRpb24ubW9kdWxlU3BlY2lmaWVyLnRleHQ7XG4gICAgLy8gSWYgdGhlIGltcG9ydCBtb2R1bGUgaXMgbm90IEBhbmd1bGFyL21hdGVyaWFsLCBza2lwIHRoZSBjaGVjay5cbiAgICBpZiAoaW1wb3J0TG9jYXRpb24gIT09IG1hdGVyaWFsTW9kdWxlU3BlY2lmaWVyKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gSWYgbm8gaW1wb3J0IGNsYXVzZSBpcyBmb3VuZCwgb3Igbm90aGluZyBpcyBuYW1lZCBhcyBhIGJpbmRpbmcgaW4gdGhlXG4gICAgLy8gaW1wb3J0LCBhZGQgZmFpbHVyZSBzYXlpbmcgdG8gaW1wb3J0IHN5bWJvbHMgaW4gY2xhdXNlLlxuICAgIGlmICghZGVjbGFyYXRpb24uaW1wb3J0Q2xhdXNlIHx8ICFkZWNsYXJhdGlvbi5pbXBvcnRDbGF1c2UubmFtZWRCaW5kaW5ncykge1xuICAgICAgdGhpcy5jcmVhdGVGYWlsdXJlQXROb2RlKGRlY2xhcmF0aW9uLCBOT19JTVBPUlRfTkFNRURfU1lNQk9MU19GQUlMVVJFX1NUUik7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gQWxsIG5hbWVkIGJpbmRpbmdzIGluIGltcG9ydCBjbGF1c2VzIG11c3QgYmUgbmFtZWQgc3ltYm9scywgb3RoZXJ3aXNlIGFkZFxuICAgIC8vIGZhaWx1cmUgc2F5aW5nIHRvIGltcG9ydCBzeW1ib2xzIGluIGNsYXVzZS5cbiAgICBpZiAoIXRzLmlzTmFtZWRJbXBvcnRzKGRlY2xhcmF0aW9uLmltcG9ydENsYXVzZS5uYW1lZEJpbmRpbmdzKSkge1xuICAgICAgdGhpcy5jcmVhdGVGYWlsdXJlQXROb2RlKGRlY2xhcmF0aW9uLCBOT19JTVBPUlRfTkFNRURfU1lNQk9MU19GQUlMVVJFX1NUUik7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gSWYgbm8gc3ltYm9scyBhcmUgaW4gdGhlIG5hbWVkIGJpbmRpbmdzIHRoZW4gYWRkIGZhaWx1cmUgc2F5aW5nIHRvXG4gICAgLy8gaW1wb3J0IHN5bWJvbHMgaW4gY2xhdXNlLlxuICAgIGlmICghZGVjbGFyYXRpb24uaW1wb3J0Q2xhdXNlLm5hbWVkQmluZGluZ3MuZWxlbWVudHMubGVuZ3RoKSB7XG4gICAgICB0aGlzLmNyZWF0ZUZhaWx1cmVBdE5vZGUoZGVjbGFyYXRpb24sIE5PX0lNUE9SVF9OQU1FRF9TWU1CT0xTX0ZBSUxVUkVfU1RSKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBXaGV0aGVyIHRoZSBleGlzdGluZyBpbXBvcnQgZGVjbGFyYXRpb24gaXMgdXNpbmcgYSBzaW5nbGUgcXVvdGUgbW9kdWxlIHNwZWNpZmllci5cbiAgICBjb25zdCBzaW5nbGVRdW90ZUltcG9ydCA9IGRlY2xhcmF0aW9uLm1vZHVsZVNwZWNpZmllci5nZXRUZXh0KClbMF0gPT09IGAnYDtcblxuICAgIC8vIE1hcCB3aGljaCBjb25zaXN0cyBvZiBzZWNvbmRhcnkgZW50cnktcG9pbnRzIGFuZCBpbXBvcnQgc3BlY2lmaWVycyB3aGljaCBhcmUgdXNlZFxuICAgIC8vIHdpdGhpbiB0aGUgY3VycmVudCBpbXBvcnQgZGVjbGFyYXRpb24uXG4gICAgY29uc3QgaW1wb3J0TWFwID0gbmV3IE1hcDxzdHJpbmcsIHRzLkltcG9ydFNwZWNpZmllcltdPigpO1xuXG4gICAgLy8gRGV0ZXJtaW5lIHRoZSBzdWJwYWNrYWdlIGVhY2ggc3ltYm9sIGluIHRoZSBuYW1lZEJpbmRpbmcgY29tZXMgZnJvbS5cbiAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgZGVjbGFyYXRpb24uaW1wb3J0Q2xhdXNlLm5hbWVkQmluZGluZ3MuZWxlbWVudHMpIHtcbiAgICAgIGNvbnN0IGVsZW1lbnROYW1lID0gZWxlbWVudC5wcm9wZXJ0eU5hbWUgPyBlbGVtZW50LnByb3BlcnR5TmFtZSA6IGVsZW1lbnQubmFtZTtcblxuICAgICAgLy8gVHJ5IHRvIHJlc29sdmUgdGhlIG1vZHVsZSBuYW1lIHZpYSB0aGUgdHlwZSBjaGVja2VyLCBhbmQgaWYgaXQgZmFpbHMsIGZhbGwgYmFjayB0b1xuICAgICAgLy8gcmVzb2x2aW5nIGl0IGZyb20gb3VyIGxpc3Qgb2Ygc3ltYm9sIHRvIGVudHJ5IHBvaW50IG1hcHBpbmdzLiBVc2luZyB0aGUgdHlwZSBjaGVja2VyIGlzXG4gICAgICAvLyBtb3JlIGFjY3VyYXRlIGFuZCBkb2Vzbid0IHJlcXVpcmUgdXMgdG8ga2VlcCBhIGxpc3Qgb2Ygc3ltYm9scywgYnV0IGl0IHdvbid0IHdvcmsgaWZcbiAgICAgIC8vIHRoZSBzeW1ib2xzIGRvbid0IGV4aXN0IGFueW1vcmUgKGUuZy4gYWZ0ZXIgd2UgcmVtb3ZlIHRoZSB0b3AtbGV2ZWwgQGFuZ3VsYXIvbWF0ZXJpYWwpLlxuICAgICAgY29uc3QgbW9kdWxlTmFtZSA9IHJlc29sdmVNb2R1bGVOYW1lKGVsZW1lbnROYW1lLCB0aGlzLnR5cGVDaGVja2VyKSB8fFxuICAgICAgICAgIEVOVFJZX1BPSU5UX01BUFBJTkdTW2VsZW1lbnROYW1lLnRleHRdIHx8IG51bGw7XG5cbiAgICAgIGlmICghbW9kdWxlTmFtZSkge1xuICAgICAgICB0aGlzLmNyZWF0ZUZhaWx1cmVBdE5vZGUoXG4gICAgICAgICAgZWxlbWVudCwgYFwiJHtlbGVtZW50LmdldFRleHQoKX1cIiB3YXMgbm90IGZvdW5kIGluIHRoZSBNYXRlcmlhbCBsaWJyYXJ5LmApO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgICAgLy8gVGhlIG1vZHVsZSBuYW1lIHdoZXJlIHRoZSBzeW1ib2wgaXMgZGVmaW5lZCBlLmcuIGNhcmQsIGRpYWxvZy4gVGhlXG4gICAgICAgIC8vIGZpcnN0IGNhcHR1cmUgZ3JvdXAgaXMgY29udGFpbnMgdGhlIG1vZHVsZSBuYW1lLlxuICAgICAgICBpZiAoaW1wb3J0TWFwLmhhcyhtb2R1bGVOYW1lKSkge1xuICAgICAgICAgIGltcG9ydE1hcC5nZXQobW9kdWxlTmFtZSkhLnB1c2goZWxlbWVudCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgaW1wb3J0TWFwLnNldChtb2R1bGVOYW1lLCBbZWxlbWVudF0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gVHJhbnNmb3JtcyB0aGUgaW1wb3J0IGRlY2xhcmF0aW9uIGludG8gbXVsdGlwbGUgaW1wb3J0IGRlY2xhcmF0aW9ucyB0aGF0IGltcG9ydFxuICAgIC8vIHRoZSBnaXZlbiBzeW1ib2xzIGZyb20gdGhlIGluZGl2aWR1YWwgc2Vjb25kYXJ5IGVudHJ5LXBvaW50cy4gRm9yIGV4YW1wbGU6XG4gICAgLy8gaW1wb3J0IHtNYXRDYXJkTW9kdWxlLCBNYXRDYXJkVGl0bGV9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2NhcmQnO1xuICAgIC8vIGltcG9ydCB7TWF0UmFkaW9Nb2R1bGV9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3JhZGlvJztcbiAgICBjb25zdCBuZXdJbXBvcnRTdGF0ZW1lbnRzID1cbiAgICAgICAgQXJyYXkuZnJvbShpbXBvcnRNYXAuZW50cmllcygpKVxuICAgICAgICAgICAgLnNvcnQoKVxuICAgICAgICAgICAgLm1hcCgoW25hbWUsIGVsZW1lbnRzXSkgPT4ge1xuICAgICAgICAgICAgICBjb25zdCBuZXdJbXBvcnQgPSB0cy5jcmVhdGVJbXBvcnREZWNsYXJhdGlvbihcbiAgICAgICAgICAgICAgICAgIHVuZGVmaW5lZCwgdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgICAgdHMuY3JlYXRlSW1wb3J0Q2xhdXNlKHVuZGVmaW5lZCwgdHMuY3JlYXRlTmFtZWRJbXBvcnRzKGVsZW1lbnRzKSksXG4gICAgICAgICAgICAgICAgICBjcmVhdGVTdHJpbmdMaXRlcmFsKGAke21hdGVyaWFsTW9kdWxlU3BlY2lmaWVyfS8ke25hbWV9YCwgc2luZ2xlUXVvdGVJbXBvcnQpKTtcbiAgICAgICAgICAgICAgcmV0dXJuIHRoaXMucHJpbnRlci5wcmludE5vZGUoXG4gICAgICAgICAgICAgICAgICB0cy5FbWl0SGludC5VbnNwZWNpZmllZCwgbmV3SW1wb3J0LCBkZWNsYXJhdGlvbi5nZXRTb3VyY2VGaWxlKCkpO1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC5qb2luKCdcXG4nKTtcblxuICAgIC8vIFdpdGhvdXQgYW55IGltcG9ydCBzdGF0ZW1lbnRzIHRoYXQgd2VyZSBnZW5lcmF0ZWQsIHdlIGNhbiBhc3N1bWUgdGhhdCB0aGlzIHdhcyBhbiBlbXB0eVxuICAgIC8vIGltcG9ydCBkZWNsYXJhdGlvbi4gV2Ugc3RpbGwgd2FudCB0byBhZGQgYSBmYWlsdXJlIGluIG9yZGVyIHRvIG1ha2UgZGV2ZWxvcGVycyBhd2FyZSB0aGF0XG4gICAgLy8gaW1wb3J0aW5nIGZyb20gXCJAYW5ndWxhci9tYXRlcmlhbFwiIGlzIGRlcHJlY2F0ZWQuXG4gICAgaWYgKCFuZXdJbXBvcnRTdGF0ZW1lbnRzKSB7XG4gICAgICB0aGlzLmNyZWF0ZUZhaWx1cmVBdE5vZGUoZGVjbGFyYXRpb24ubW9kdWxlU3BlY2lmaWVyLCBPTkxZX1NVQlBBQ0tBR0VfRkFJTFVSRV9TVFIpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHJlY29yZGVyID0gdGhpcy5nZXRVcGRhdGVSZWNvcmRlcihkZWNsYXJhdGlvbi5tb2R1bGVTcGVjaWZpZXIuZ2V0U291cmNlRmlsZSgpLmZpbGVOYW1lKTtcblxuICAgIC8vIFBlcmZvcm0gdGhlIHJlcGxhY2VtZW50IHRoYXQgc3dpdGNoZXMgdGhlIHByaW1hcnkgZW50cnktcG9pbnQgaW1wb3J0IHRvXG4gICAgLy8gdGhlIGluZGl2aWR1YWwgc2Vjb25kYXJ5IGVudHJ5LXBvaW50IGltcG9ydHMuXG4gICAgcmVjb3JkZXIucmVtb3ZlKGRlY2xhcmF0aW9uLmdldFN0YXJ0KCksIGRlY2xhcmF0aW9uLmdldFdpZHRoKCkpO1xuICAgIHJlY29yZGVyLmluc2VydFJpZ2h0KGRlY2xhcmF0aW9uLmdldFN0YXJ0KCksIG5ld0ltcG9ydFN0YXRlbWVudHMpO1xuICB9XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIHN0cmluZyBsaXRlcmFsIGZyb20gdGhlIHNwZWNpZmllZCB0ZXh0LlxuICogQHBhcmFtIHRleHQgVGV4dCBvZiB0aGUgc3RyaW5nIGxpdGVyYWwuXG4gKiBAcGFyYW0gc2luZ2xlUXVvdGVzIFdoZXRoZXIgc2luZ2xlIHF1b3RlcyBzaG91bGQgYmUgdXNlZCB3aGVuIHByaW50aW5nIHRoZSBsaXRlcmFsIG5vZGUuXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZVN0cmluZ0xpdGVyYWwodGV4dDogc3RyaW5nLCBzaW5nbGVRdW90ZXM6IGJvb2xlYW4pOiB0cy5TdHJpbmdMaXRlcmFsIHtcbiAgY29uc3QgbGl0ZXJhbCA9IHRzLmNyZWF0ZVN0cmluZ0xpdGVyYWwodGV4dCk7XG4gIC8vIFNlZTogaHR0cHM6Ly9naXRodWIuY29tL21pY3Jvc29mdC9UeXBlU2NyaXB0L2Jsb2IvbWFzdGVyL3NyYy9jb21waWxlci91dGlsaXRpZXMudHMjTDU4NC1MNTkwXG4gIGxpdGVyYWxbJ3NpbmdsZVF1b3RlJ10gPSBzaW5nbGVRdW90ZXM7XG4gIHJldHVybiBsaXRlcmFsO1xufVxuXG4vKiogR2V0cyB0aGUgc3ltYm9sIHRoYXQgY29udGFpbnMgdGhlIHZhbHVlIGRlY2xhcmF0aW9uIG9mIHRoZSBnaXZlbiBub2RlLiAqL1xuZnVuY3Rpb24gZ2V0RGVjbGFyYXRpb25TeW1ib2xPZk5vZGUobm9kZTogdHMuTm9kZSwgY2hlY2tlcjogdHMuVHlwZUNoZWNrZXIpOiB0cy5TeW1ib2x8dW5kZWZpbmVkIHtcbiAgY29uc3Qgc3ltYm9sID0gY2hlY2tlci5nZXRTeW1ib2xBdExvY2F0aW9uKG5vZGUpO1xuXG4gIC8vIFN5bWJvbHMgY2FuIGJlIGFsaWFzZXMgb2YgdGhlIGRlY2xhcmF0aW9uIHN5bWJvbC4gZS5nLiBpbiBuYW1lZCBpbXBvcnQgc3BlY2lmaWVycy5cbiAgLy8gV2UgbmVlZCB0byByZXNvbHZlIHRoZSBhbGlhc2VkIHN5bWJvbCBiYWNrIHRvIHRoZSBkZWNsYXJhdGlvbiBzeW1ib2wuXG4gIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTpuby1iaXR3aXNlXG4gIGlmIChzeW1ib2wgJiYgKHN5bWJvbC5mbGFncyAmIHRzLlN5bWJvbEZsYWdzLkFsaWFzKSAhPT0gMCkge1xuICAgIHJldHVybiBjaGVja2VyLmdldEFsaWFzZWRTeW1ib2woc3ltYm9sKTtcbiAgfVxuICByZXR1cm4gc3ltYm9sO1xufVxuXG5cbi8qKiBUcmllcyB0byByZXNvbHZlIHRoZSBuYW1lIG9mIHRoZSBNYXRlcmlhbCBtb2R1bGUgdGhhdCBhIG5vZGUgaXMgaW1wb3J0ZWQgZnJvbS4gKi9cbmZ1bmN0aW9uIHJlc29sdmVNb2R1bGVOYW1lKG5vZGU6IHRzLklkZW50aWZpZXIsIHR5cGVDaGVja2VyOiB0cy5UeXBlQ2hlY2tlcikge1xuICAvLyBHZXQgdGhlIHN5bWJvbCBmb3IgdGhlIG5hbWVkIGJpbmRpbmcgZWxlbWVudC4gTm90ZSB0aGF0IHdlIGNhbm5vdCBkZXRlcm1pbmUgdGhlXG4gIC8vIHZhbHVlIGRlY2xhcmF0aW9uIGJhc2VkIG9uIHRoZSB0eXBlIG9mIHRoZSBlbGVtZW50IGFzIHR5cGVzIGFyZSBub3QgbmVjZXNzYXJpbHlcbiAgLy8gc3BlY2lmaWMgdG8gYSBnaXZlbiBzZWNvbmRhcnkgZW50cnktcG9pbnQgKGUuZy4gZXhwb3J0cyB3aXRoIHRoZSB0eXBlIG9mIFwic3RyaW5nXCIpXG4gIC8vIHdvdWxkIHJlc29sdmUgdG8gdGhlIG1vZHVsZSB0eXBlcyBwcm92aWRlZCBieSBUeXBlU2NyaXB0IGl0c2VsZi5cbiAgY29uc3Qgc3ltYm9sID0gZ2V0RGVjbGFyYXRpb25TeW1ib2xPZk5vZGUobm9kZSwgdHlwZUNoZWNrZXIpO1xuXG4gIC8vIElmIHRoZSBzeW1ib2wgY2FuJ3QgYmUgZm91bmQsIG9yIG5vIGRlY2xhcmF0aW9uIGNvdWxkIGJlIGZvdW5kIHdpdGhpblxuICAvLyB0aGUgc3ltYm9sLCBhZGQgZmFpbHVyZSB0byByZXBvcnQgdGhhdCB0aGUgZ2l2ZW4gc3ltYm9sIGNhbid0IGJlIGZvdW5kLlxuICBpZiAoIXN5bWJvbCB8fFxuICAgICAgIShzeW1ib2wudmFsdWVEZWNsYXJhdGlvbiB8fCAoc3ltYm9sLmRlY2xhcmF0aW9ucyAmJiBzeW1ib2wuZGVjbGFyYXRpb25zLmxlbmd0aCAhPT0gMCkpKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICAvLyBUaGUgZmlsZW5hbWUgZm9yIHRoZSBzb3VyY2UgZmlsZSBvZiB0aGUgbm9kZSB0aGF0IGNvbnRhaW5zIHRoZVxuICAvLyBmaXJzdCBkZWNsYXJhdGlvbiBvZiB0aGUgc3ltYm9sLiBBbGwgc3ltYm9sIGRlY2xhcmF0aW9ucyBtdXN0IGJlXG4gIC8vIHBhcnQgb2YgYSBkZWZpbmluZyBub2RlLCBzbyBwYXJlbnQgY2FuIGJlIGFzc2VydGVkIHRvIGJlIGRlZmluZWQuXG4gIGNvbnN0IHJlc29sdmVkTm9kZSA9IHN5bWJvbC52YWx1ZURlY2xhcmF0aW9uIHx8IHN5bWJvbC5kZWNsYXJhdGlvbnNbMF07XG4gIGNvbnN0IHNvdXJjZUZpbGUgPSByZXNvbHZlZE5vZGUuZ2V0U291cmNlRmlsZSgpLmZpbGVOYW1lO1xuXG4gIC8vIEZpbGUgdGhlIG1vZHVsZSB0aGUgc3ltYm9sIGJlbG9uZ3MgdG8gZnJvbSBhIHJlZ2V4IG1hdGNoIG9mIHRoZVxuICAvLyBmaWxlbmFtZS4gVGhpcyB3aWxsIGFsd2F5cyBtYXRjaCBzaW5jZSBvbmx5IFwiQGFuZ3VsYXIvbWF0ZXJpYWxcIlxuICAvLyBlbGVtZW50cyBhcmUgYW5hbHl6ZWQuXG4gIGNvbnN0IG1hdGNoZXMgPSBzb3VyY2VGaWxlLm1hdGNoKEFOR1VMQVJfTUFURVJJQUxfRklMRVBBVEhfUkVHRVgpO1xuICByZXR1cm4gbWF0Y2hlcyA/IG1hdGNoZXNbMV0gOiBudWxsO1xufVxuIl19