UNPKG

@nguniversal/express-engine

Version:

Express Engine for running Server Angular Apps

264 lines 37.7 kB
/** * @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 */ import { dirname, join, normalize, strings } from '@angular-devkit/core'; import { SchematicsException, apply, chain, externalSchematic, mergeWith, move, noop, template, url, } from '@angular-devkit/schematics'; import { DependencyType, addDependency, updateWorkspace } from '@schematics/angular/utility'; import { JSONFile } from '@schematics/angular/utility/json-file'; import { isStandaloneApp } from '@schematics/angular/utility/ng-ast-utils'; import { targetBuildNotFoundError } from '@schematics/angular/utility/project-targets'; import * as ts from 'typescript'; import { addInitialNavigation, findImport, getImportOfIdentifier, getOutputPath, getProject, stripTsExtension, } from '../utils'; const SERVE_SSR_TARGET_NAME = 'serve-ssr'; const PRERENDER_TARGET_NAME = 'prerender'; function addScriptsRule(options) { return async (host) => { const pkgPath = '/package.json'; const buffer = host.read(pkgPath); if (buffer === null) { throw new SchematicsException('Could not find package.json'); } const serverDist = await getOutputPath(host, options.project, 'server'); const pkg = JSON.parse(buffer.toString()); pkg.scripts = { ...pkg.scripts, 'dev:ssr': `ng run ${options.project}:${SERVE_SSR_TARGET_NAME}`, 'serve:ssr': `node ${serverDist}/main.js`, 'build:ssr': `ng build && ng run ${options.project}:server`, 'prerender': `ng run ${options.project}:${PRERENDER_TARGET_NAME}`, }; host.overwrite(pkgPath, JSON.stringify(pkg, null, 2)); }; } function updateWorkspaceConfigRule(options) { return () => { return updateWorkspace((workspace) => { const projectName = options.project; const project = workspace.projects.get(projectName); if (!project) { return; } const serverTarget = project.targets.get('server'); serverTarget.options.main = join(normalize(project.root), stripTsExtension(options.serverFileName) + '.ts'); const serveSSRTarget = project.targets.get(SERVE_SSR_TARGET_NAME); if (serveSSRTarget) { return; } project.targets.add({ name: SERVE_SSR_TARGET_NAME, builder: '@nguniversal/builders:ssr-dev-server', defaultConfiguration: 'development', options: {}, configurations: { development: { browserTarget: `${projectName}:build:development`, serverTarget: `${projectName}:server:development`, }, production: { browserTarget: `${projectName}:build:production`, serverTarget: `${projectName}:server:production`, }, }, }); const prerenderTarget = project.targets.get(PRERENDER_TARGET_NAME); if (prerenderTarget) { return; } project.targets.add({ name: PRERENDER_TARGET_NAME, builder: '@nguniversal/builders:prerender', defaultConfiguration: 'production', options: { routes: ['/'], }, configurations: { production: { browserTarget: `${projectName}:build:production`, serverTarget: `${projectName}:server:production`, }, development: { browserTarget: `${projectName}:build:development`, serverTarget: `${projectName}:server:development`, }, }, }); }); }; } function updateServerTsConfigRule(options) { return async (host) => { const project = await getProject(host, options.project); const serverTarget = project.targets.get('server'); if (!serverTarget || !serverTarget.options) { return; } const tsConfigPath = serverTarget.options.tsConfig; if (!tsConfigPath || typeof tsConfigPath !== 'string') { // No tsconfig path return; } const tsConfig = new JSONFile(host, tsConfigPath); const filesAstNode = tsConfig.get(['files']); const serverFilePath = stripTsExtension(options.serverFileName) + '.ts'; if (Array.isArray(filesAstNode) && !filesAstNode.some(({ text }) => text === serverFilePath)) { tsConfig.modify(['files'], [...filesAstNode, serverFilePath]); } }; } function routingInitialNavigationRule(options) { return async (host) => { const project = await getProject(host, options.project); const serverTarget = project.targets.get('server'); if (!serverTarget || !serverTarget.options) { return; } const tsConfigPath = serverTarget.options.tsConfig; if (!tsConfigPath || typeof tsConfigPath !== 'string' || !host.exists(tsConfigPath)) { // No tsconfig path return; } const parseConfigHost = { useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames, readDirectory: ts.sys.readDirectory, fileExists: function (fileName) { return host.exists(fileName); }, readFile: function (fileName) { return host.read(fileName).toString(); }, }; const { config } = ts.readConfigFile(tsConfigPath, parseConfigHost.readFile); const parsed = ts.parseJsonConfigFileContent(config, parseConfigHost, dirname(normalize(tsConfigPath))); const tsHost = ts.createCompilerHost(parsed.options, true); // Strip BOM as otherwise TSC methods (Ex: getWidth) will return an offset, // which breaks the CLI UpdateRecorder. // See: https://github.com/angular/angular/pull/30719 tsHost.readFile = function (fileName) { return host .read(fileName) .toString() .replace(/^\uFEFF/, ''); }; tsHost.directoryExists = function (directoryName) { // When the path is file getDir will throw. try { const dir = host.getDir(directoryName); return !!(dir.subdirs.length || dir.subfiles.length); } catch { return false; } }; tsHost.fileExists = function (fileName) { return host.exists(fileName); }; tsHost.realpath = function (path) { return path; }; tsHost.getCurrentDirectory = function () { return host.root.path; }; const program = ts.createProgram(parsed.fileNames, parsed.options, tsHost); const typeChecker = program.getTypeChecker(); const sourceFiles = program .getSourceFiles() .filter((f) => !f.isDeclarationFile && !program.isSourceFileFromExternalLibrary(f)); const printer = ts.createPrinter(); const routerModule = 'RouterModule'; const routerSource = '@angular/router'; sourceFiles.forEach((sourceFile) => { const routerImport = findImport(sourceFile, routerSource, routerModule); if (!routerImport) { return; } let routerModuleNode; ts.forEachChild(sourceFile, function visitNode(node) { if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.expression) && node.expression.name.text === 'forRoot') { const imp = getImportOfIdentifier(typeChecker, node.expression.expression); if (imp && imp.name === routerModule && imp.importModule === routerSource) { routerModuleNode = node; } } ts.forEachChild(node, visitNode); }); if (routerModuleNode) { const print = printer.printNode(ts.EmitHint.Unspecified, addInitialNavigation(routerModuleNode), sourceFile); const recorder = host.beginUpdate(sourceFile.fileName); recorder.remove(routerModuleNode.getStart(), routerModuleNode.getWidth()); recorder.insertRight(routerModuleNode.getStart(), print); host.commitUpdate(recorder); } }); }; } function addDependencies() { return (_host) => { return chain([ addDependency('@nguniversal/builders', '^16.2.0', { type: DependencyType.Dev, }), addDependency('@nguniversal/express-engine', '^16.2.0', { type: DependencyType.Default, }), addDependency('express', '^4.15.2', { type: DependencyType.Default, }), addDependency('@types/express', '^4.17.0', { type: DependencyType.Dev, }), ]); }; } function addServerFile(options, isStandalone) { return async (host) => { const project = await getProject(host, options.project); const browserDistDirectory = await getOutputPath(host, options.project, 'build'); return mergeWith(apply(url('./files'), [ template({ ...strings, ...options, stripTsExtension, browserDistDirectory, isStandalone, }), move(project.root), ])); }; } export default function (options) { return async (host) => { const project = await getProject(host, options.project); const universalOptions = { ...options, skipInstall: true, }; const clientBuildTarget = project.targets.get('build'); if (!clientBuildTarget) { throw targetBuildNotFoundError(); } const clientBuildOptions = (clientBuildTarget.options || {}); const isStandalone = isStandaloneApp(host, clientBuildOptions.main); delete universalOptions.serverFileName; delete universalOptions.serverPort; return chain([ project.targets.has('server') ? noop() : externalSchematic('@schematics/angular', 'universal', universalOptions), addScriptsRule(options), updateServerTsConfigRule(options), updateWorkspaceConfigRule(options), isStandalone ? noop() : routingInitialNavigationRule(options), addServerFile(options, isStandalone), addDependencies(), ]); }; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9tb2R1bGVzL2V4cHJlc3MtZW5naW5lL3NjaGVtYXRpY3MvaW5zdGFsbC9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFFSCxPQUFPLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDekUsT0FBTyxFQUVMLG1CQUFtQixFQUVuQixLQUFLLEVBQ0wsS0FBSyxFQUNMLGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsSUFBSSxFQUNKLElBQUksRUFDSixRQUFRLEVBQ1IsR0FBRyxHQUNKLE1BQU0sNEJBQTRCLENBQUM7QUFFcEMsT0FBTyxFQUFFLGNBQWMsRUFBRSxhQUFhLEVBQUUsZUFBZSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDN0YsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLHVDQUF1QyxDQUFDO0FBQ2pFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwwQ0FBMEMsQ0FBQztBQUMzRSxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSw2Q0FBNkMsQ0FBQztBQUV2RixPQUFPLEtBQUssRUFBRSxNQUFNLFlBQVksQ0FBQztBQUVqQyxPQUFPLEVBQ0wsb0JBQW9CLEVBQ3BCLFVBQVUsRUFDVixxQkFBcUIsRUFDckIsYUFBYSxFQUNiLFVBQVUsRUFDVixnQkFBZ0IsR0FDakIsTUFBTSxVQUFVLENBQUM7QUFJbEIsTUFBTSxxQkFBcUIsR0FBRyxXQUFXLENBQUM7QUFDMUMsTUFBTSxxQkFBcUIsR0FBRyxXQUFXLENBQUM7QUFFMUMsU0FBUyxjQUFjLENBQUMsT0FBNEI7SUFDbEQsT0FBTyxLQUFLLEVBQUUsSUFBSSxFQUFFLEVBQUU7UUFDcEIsTUFBTSxPQUFPLEdBQUcsZUFBZSxDQUFDO1FBQ2hDLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxJQUFJLENB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O1FBQ3hELE1BQU0sZ0JBQWdCLEdBQUc7WUFDdkIsR0FBRyxPQUFPO1lBQ1YsV0FBVyxFQUFFLElBQUk7U0FDbEIsQ0FBQztRQUNGLE1BQU0saUJBQWlCLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDdkQsSUFBSSxDQUFDLGlCQUFpQixFQUFFO1lBQ3RCLE1BQU0sd0JBQXdCLEVBQUUsQ0FBQztTQUNsQztRQUVELE1BQU0sa0JBQWtCLEdBQUcsQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPO1lBQ25ELEVBQUUsQ0FBcUMsQ0FBQztRQUUxQyxNQUFNLFlBQVksR0FBRyxlQUFlLENBQUMsSUFBSSxFQUFFLGtCQUFrQixDQUFDLElBQUksQ0FBQyxDQUFDO1FBRXBFLE9BQU8sZ0JBQWdCLENBQUMsY0FBYyxDQUFDO1FBQ3ZDLE9BQU8sZ0JBQWdCLENBQUMsVUFBVSxDQUFDO1FBRW5DLE9BQU8sS0FBSyxDQUFDO1lBQ1gsT0FBTyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDO2dCQUMzQixDQUFDLENBQUMsSUFBSSxFQUFFO2dCQUNSLENBQUMsQ0FBQyxpQkFBaUIsQ0FBQyxxQkFBcUIsRUFBRSxXQUFXLEVBQUUsZ0JBQWdCLENBQUM7WUFDM0UsY0FBYyxDQUFDLE9BQU8sQ0FBQztZQUN2Qix3QkFBd0IsQ0FBQyxPQUFPLENBQUM7WUFDakMseUJBQXlCLENBQUMsT0FBTyxDQUFDO1lBQ2xDLFlBQVksQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLDRCQUE0QixDQUFDLE9BQU8sQ0FBQztZQUM3RCxhQUFhLENBQUMsT0FBTyxFQUFFLFlBQVksQ0FBQztZQUNwQyxlQUFlLEVBQUU7U0FDbEIsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgTExDIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlIGxpY2Vuc2UgdGhhdCBjYW4gYmVcbiAqIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgYXQgaHR0cHM6Ly9hbmd1bGFyLmlvL2xpY2Vuc2VcbiAqL1xuXG5pbXBvcnQgeyBkaXJuYW1lLCBqb2luLCBub3JtYWxpemUsIHN0cmluZ3MgfSBmcm9tICdAYW5ndWxhci1kZXZraXQvY29yZSc7XG5pbXBvcnQge1xuICBSdWxlLFxuICBTY2hlbWF0aWNzRXhjZXB0aW9uLFxuICBUcmVlLFxuICBhcHBseSxcbiAgY2hhaW4sXG4gIGV4dGVybmFsU2NoZW1hdGljLFxuICBtZXJnZVdpdGgsXG4gIG1vdmUsXG4gIG5vb3AsXG4gIHRlbXBsYXRlLFxuICB1cmwsXG59IGZyb20gJ0Bhbmd1bGFyLWRldmtpdC9zY2hlbWF0aWNzJztcbmltcG9ydCB7IFNjaGVtYSBhcyBVbml2ZXJzYWxPcHRpb25zIH0gZnJvbSAnQHNjaGVtYXRpY3MvYW5ndWxhci91bml2ZXJzYWwvc2NoZW1hJztcbmltcG9ydCB7IERlcGVuZGVuY3lUeXBlLCBhZGREZXBlbmRlbmN5LCB1cGRhdGVXb3Jrc3BhY2UgfSBmcm9tICdAc2NoZW1hdGljcy9hbmd1bGFyL3V0aWxpdHknO1xuaW1wb3J0IHsgSlNPTkZpbGUgfSBmcm9tICdAc2NoZW1hdGljcy9hbmd1bGFyL3V0aWxpdHkvanNvbi1maWxlJztcbmltcG9ydCB7IGlzU3RhbmRhbG9uZUFwcCB9IGZyb20gJ0BzY2hlbWF0aWNzL2FuZ3VsYXIvdXRpbGl0eS9uZy1hc3QtdXRpbHMnO1xuaW1wb3J0IHsgdGFyZ2V0QnVpbGROb3RGb3VuZEVycm9yIH0gZnJvbSAnQHNjaGVtYXRpY3MvYW5ndWxhci91dGlsaXR5L3Byb2plY3QtdGFyZ2V0cyc7XG5pbXBvcnQgeyBCcm93c2VyQnVpbGRlck9wdGlvbnMgfSBmcm9tICdAc2NoZW1hdGljcy9hbmd1bGFyL3V0aWxpdHkvd29ya3NwYWNlLW1vZGVscyc7XG5pbXBvcnQgKiBhcyB0cyBmcm9tICd0eXBlc2NyaXB0JztcblxuaW1wb3J0IHtcbiAgYWRkSW5pdGlhbE5hdmlnYXRpb24sXG4gIGZpbmRJbXBvcnQsXG4gIGdldEltcG9ydE9mSWRlbnRpZmllcixcbiAgZ2V0T3V0cHV0UGF0aCxcbiAgZ2V0UHJvamVjdCxcbiAgc3RyaXBUc0V4dGVuc2lvbixcbn0gZnJvbSAnLi4vdXRpbHMnO1xuXG5pbXBvcnQgeyBTY2hlbWEgYXMgQWRkVW5pdmVyc2FsT3B0aW9ucyB9IGZyb20gJy4vc2NoZW1hJztcblxuY29uc3QgU0VSVkVfU1NSX1RBUkdFVF9OQU1FID0gJ3NlcnZlLXNzcic7XG5jb25zdCBQUkVSRU5ERVJfVEFSR0VUX05BTUUgPSAncHJlcmVuZGVyJztcblxuZnVuY3Rpb24gYWRkU2NyaXB0c1J1bGUob3B0aW9uczogQWRkVW5pdmVyc2FsT3B0aW9ucyk6IFJ1bGUge1xuICByZXR1cm4gYXN5bmMgKGhvc3QpID0+IHtcbiAgICBjb25zdCBwa2dQYXRoID0gJy9wYWNrYWdlLmpzb24nO1xuICAgIGNvbnN0IGJ1ZmZlciA9IGhvc3QucmVhZChwa2dQYXRoKTtcbiAgICBpZiAoYnVmZmVyID09PSBudWxsKSB7XG4gICAgICB0aHJvdyBuZXcgU2NoZW1hdGljc0V4Y2VwdGlvbignQ291bGQgbm90IGZpbmQgcGFja2FnZS5qc29uJyk7XG4gICAgfVxuXG4gICAgY29uc3Qgc2VydmVyRGlzdCA9IGF3YWl0IGdldE91dHB1dFBhdGgoaG9zdCwgb3B0aW9ucy5wcm9qZWN0LCAnc2VydmVyJyk7XG4gICAgY29uc3QgcGtnID0gSlNPTi5wYXJzZShidWZmZXIudG9TdHJpbmcoKSkgYXMgYW55O1xuICAgIHBrZy5zY3JpcHRzID0ge1xuICAgICAgLi4ucGtnLnNjcmlwdHMsXG4gICAgICAnZGV2OnNzcic6IGBuZyBydW4gJHtvcHRpb25zLnByb2plY3R9OiR7U0VSVkVfU1NSX1RBUkdFVF9OQU1FfWAsXG4gICAgICAnc2VydmU6c3NyJzogYG5vZGUgJHtzZXJ2ZXJEaXN0fS9tYWluLmpzYCxcbiAgICAgICdidWlsZDpzc3InOiBgbmcgYnVpbGQgJiYgbmcgcnVuICR7b3B0aW9ucy5wcm9qZWN0fTpzZXJ2ZXJgLFxuICAgICAgJ3ByZXJlbmRlcic6IGBuZyBydW4gJHtvcHRpb25zLnByb2plY3R9OiR7UFJFUkVOREVSX1RBUkdFVF9OQU1FfWAsXG4gICAgfTtcblxuICAgIGhvc3Qub3ZlcndyaXRlKHBrZ1BhdGgsIEpTT04uc3RyaW5naWZ5KHBrZywgbnVsbCwgMikpO1xuICB9O1xufVxuXG5mdW5jdGlvbiB1cGRhdGVXb3Jrc3BhY2VDb25maWdSdWxlKG9wdGlvbnM6IEFkZFVuaXZlcnNhbE9wdGlvbnMpOiBSdWxlIHtcbiAgcmV0dXJuICgpID0+IHtcbiAgICByZXR1cm4gdXBkYXRlV29ya3NwYWNlKCh3b3Jrc3BhY2UpID0+IHtcbiAgICAgIGNvbnN0IHByb2plY3ROYW1lID0gb3B0aW9ucy5wcm9qZWN0O1xuICAgICAgY29uc3QgcHJvamVjdCA9IHdvcmtzcGFjZS5wcm9qZWN0cy5nZXQocHJvamVjdE5hbWUpO1xuICAgICAgaWYgKCFwcm9qZWN0KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc2VydmVyVGFyZ2V0ID0gcHJvamVjdC50YXJnZXRzLmdldCgnc2VydmVyJyk7XG4gICAgICBzZXJ2ZXJUYXJnZXQub3B0aW9ucy5tYWluID0gam9pbihcbiAgICAgICAgbm9ybWFsaXplKHByb2plY3Qucm9vdCksXG4gICAgICAgIHN0cmlwVHNFeHRlbnNpb24ob3B0aW9ucy5zZXJ2ZXJGaWxlTmFtZSkgKyAnLnRzJyxcbiAgICAgICk7XG5cbiAgICAgIGNvbnN0IHNlcnZlU1NSVGFyZ2V0ID0gcHJvamVjdC50YXJnZXRzLmdldChTRVJWRV9TU1JfVEFSR0VUX05BTUUpO1xuICAgICAgaWYgKHNlcnZlU1NSVGFyZ2V0KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgcHJvamVjdC50YXJnZXRzLmFkZCh7XG4gICAgICAgIG5hbWU6IFNFUlZFX1NTUl9UQVJHRVRfTkFNRSxcbiAgICAgICAgYnVpbGRlcjogJ0BuZ3VuaXZlcnNhbC9idWlsZGVyczpzc3ItZGV2LXNlcnZlcicsXG4gICAgICAgIGRlZmF1bHRDb25maWd1cmF0aW9uOiAnZGV2ZWxvcG1lbnQnLFxuICAgICAgICBvcHRpb25zOiB7fSxcbiAgICAgICAgY29uZmlndXJhdGlvbnM6IHtcbiAgICAgICAgICBkZXZlbG9wbWVudDoge1xuICAgICAgICAgICAgYnJvd3NlclRhcmdldDogYCR7cHJvamVjdE5hbWV9OmJ1aWxkOmRldmVsb3BtZW50YCxcbiAgICAgICAgICAgIHNlcnZlclRhcmdldDogYCR7cHJvamVjdE5hbWV9OnNlcnZlcjpkZXZlbG9wbWVudGAsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBwcm9kdWN0aW9uOiB7XG4gICAgICAgICAgICBicm93c2VyVGFyZ2V0OiBgJHtwcm9qZWN0TmFtZX06YnVpbGQ6cHJvZHVjdGlvbmAsXG4gICAgICAgICAgICBzZXJ2ZXJUYXJnZXQ6IGAke3Byb2plY3ROYW1lfTpzZXJ2ZXI6cHJvZHVjdGlvbmAsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCBwcmVyZW5kZXJUYXJnZXQgPSBwcm9qZWN0LnRhcmdldHMuZ2V0KFBSRVJFTkRFUl9UQVJHRVRfTkFNRSk7XG4gICAgICBpZiAocHJlcmVuZGVyVGFyZ2V0KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgcHJvamVjdC50YXJnZXRzLmFkZCh7XG4gICAgICAgIG5hbWU6IFBSRVJFTkRFUl9UQVJHRVRfTkFNRSxcbiAgICAgICAgYnVpbGRlcjogJ0BuZ3VuaXZlcnNhbC9idWlsZGVyczpwcmVyZW5kZXInLFxuICAgICAgICBkZWZhdWx0Q29uZmlndXJhdGlvbjogJ3Byb2R1Y3Rpb24nLFxuICAgICAgICBvcHRpb25zOiB7XG4gICAgICAgICAgcm91dGVzOiBbJy8nXSxcbiAgICAgICAgfSxcbiAgICAgICAgY29uZmlndXJhdGlvbnM6IHtcbiAgICAgICAgICBwcm9kdWN0aW9uOiB7XG4gICAgICAgICAgICBicm93c2VyVGFyZ2V0OiBgJHtwcm9qZWN0TmFtZX06YnVpbGQ6cHJvZHVjdGlvbmAsXG4gICAgICAgICAgICBzZXJ2ZXJUYXJnZXQ6IGAke3Byb2plY3ROYW1lfTpzZXJ2ZXI6cHJvZHVjdGlvbmAsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBkZXZlbG9wbWVudDoge1xuICAgICAgICAgICAgYnJvd3NlclRhcmdldDogYCR7cHJvamVjdE5hbWV9OmJ1aWxkOmRldmVsb3BtZW50YCxcbiAgICAgICAgICAgIHNlcnZlclRhcmdldDogYCR7cHJvamVjdE5hbWV9OnNlcnZlcjpkZXZlbG9wbWVudGAsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9O1xufVxuXG5mdW5jdGlvbiB1cGRhdGVTZXJ2ZXJUc0NvbmZpZ1J1bGUob3B0aW9uczogQWRkVW5pdmVyc2FsT3B0aW9ucyk6IFJ1bGUge1xuICByZXR1cm4gYXN5bmMgKGhvc3QpID0+IHtcbiAgICBjb25zdCBwcm9qZWN0ID0gYXdhaXQgZ2V0UHJvamVjdChob3N0LCBvcHRpb25zLnByb2plY3QpO1xuICAgIGNvbnN0IHNlcnZlclRhcmdldCA9IHByb2plY3QudGFyZ2V0cy5nZXQoJ3NlcnZlcicpO1xuICAgIGlmICghc2VydmVyVGFyZ2V0IHx8ICFzZXJ2ZXJUYXJnZXQub3B0aW9ucykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHRzQ29uZmlnUGF0aCA9IHNlcnZlclRhcmdldC5vcHRpb25zLnRzQ29uZmlnO1xuICAgIGlmICghdHNDb25maWdQYXRoIHx8IHR5cGVvZiB0c0NvbmZpZ1BhdGggIT09ICdzdHJpbmcnKSB7XG4gICAgICAvLyBObyB0c2NvbmZpZyBwYXRoXG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgdHNDb25maWcgPSBuZXcgSlNPTkZpbGUoaG9zdCwgdHNDb25maWdQYXRoKTtcbiAgICBjb25zdCBmaWxlc0FzdE5vZGUgPSB0c0NvbmZpZy5nZXQoWydmaWxlcyddKTtcbiAgICBjb25zdCBzZXJ2ZXJGaWxlUGF0aCA9IHN0cmlwVHNFeHRlbnNpb24ob3B0aW9ucy5zZXJ2ZXJGaWxlTmFtZSkgKyAnLnRzJztcbiAgICBpZiAoQXJyYXkuaXNBcnJheShmaWxlc0FzdE5vZGUpICYmICFmaWxlc0FzdE5vZGUuc29tZSgoeyB0ZXh0IH0pID0+IHRleHQgPT09IHNlcnZlckZpbGVQYXRoKSkge1xuICAgICAgdHNDb25maWcubW9kaWZ5KFsnZmlsZXMnXSwgWy4uLmZpbGVzQXN0Tm9kZSwgc2VydmVyRmlsZVBhdGhdKTtcbiAgICB9XG4gIH07XG59XG5cbmZ1bmN0aW9uIHJvdXRpbmdJbml0aWFsTmF2aWdhdGlvblJ1bGUob3B0aW9uczogVW5pdmVyc2FsT3B0aW9ucyk6IFJ1bGUge1xuICByZXR1cm4gYXN5bmMgKGhvc3QpID0+IHtcbiAgICBjb25zdCBwcm9qZWN0ID0gYXdhaXQgZ2V0UHJvamVjdChob3N0LCBvcHRpb25zLnByb2plY3QpO1xuICAgIGNvbnN0IHNlcnZlclRhcmdldCA9IHByb2plY3QudGFyZ2V0cy5nZXQoJ3NlcnZlcicpO1xuICAgIGlmICghc2VydmVyVGFyZ2V0IHx8ICFzZXJ2ZXJUYXJnZXQub3B0aW9ucykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHRzQ29uZmlnUGF0aCA9IHNlcnZlclRhcmdldC5vcHRpb25zLnRzQ29uZmlnO1xuICAgIGlmICghdHNDb25maWdQYXRoIHx8IHR5cGVvZiB0c0NvbmZpZ1BhdGggIT09ICdzdHJpbmcnIHx8ICFob3N0LmV4aXN0cyh0c0NvbmZpZ1BhdGgpKSB7XG4gICAgICAvLyBObyB0c2NvbmZpZyBwYXRoXG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgcGFyc2VDb25maWdIb3N0OiB0cy5QYXJzZUNvbmZpZ0hvc3QgPSB7XG4gICAgICB1c2VDYXNlU2Vuc2l0aXZlRmlsZU5hbWVzOiB0cy5zeXMudXNlQ2FzZVNlbnNpdGl2ZUZpbGVOYW1lcyxcbiAgICAgIHJlYWREaXJlY3Rvcnk6IHRzLnN5cy5yZWFkRGlyZWN0b3J5LFxuICAgICAgZmlsZUV4aXN0czogZnVuY3Rpb24gKGZpbGVOYW1lOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIGhvc3QuZXhpc3RzKGZpbGVOYW1lKTtcbiAgICAgIH0sXG4gICAgICByZWFkRmlsZTogZnVuY3Rpb24gKGZpbGVOYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gaG9zdC5yZWFkKGZpbGVOYW1lKS50b1N0cmluZygpO1xuICAgICAgfSxcbiAgICB9O1xuICAgIGNvbnN0IHsgY29uZmlnIH0gPSB0cy5yZWFkQ29uZmlnRmlsZSh0c0NvbmZpZ1BhdGgsIHBhcnNlQ29uZmlnSG9zdC5yZWFkRmlsZSk7XG4gICAgY29uc3QgcGFyc2VkID0gdHMucGFyc2VKc29uQ29uZmlnRmlsZUNvbnRlbnQoXG4gICAgICBjb25maWcsXG4gICAgICBwYXJzZUNvbmZpZ0hvc3QsXG4gICAgICBkaXJuYW1lKG5vcm1hbGl6ZSh0c0NvbmZpZ1BhdGgpKSxcbiAgICApO1xuICAgIGNvbnN0IHRzSG9zdCA9IHRzLmNyZWF0ZUNvbXBpbGVySG9zdChwYXJzZWQub3B0aW9ucywgdHJ1ZSk7XG4gICAgLy8gU3RyaXAgQk9NIGFzIG90aGVyd2lzZSBUU0MgbWV0aG9kcyAoRXg6IGdldFdpZHRoKSB3aWxsIHJldHVybiBhbiBvZmZzZXQsXG4gICAgLy8gd2hpY2ggYnJlYWtzIHRoZSBDTEkgVXBkYXRlUmVjb3JkZXIuXG4gICAgLy8gU2VlOiBodHRwczovL2dpdGh1Yi5jb20vYW5ndWxhci9hbmd1bGFyL3B1bGwvMzA3MTlcbiAgICB0c0hvc3QucmVhZEZpbGUgPSBmdW5jdGlvbiAoZmlsZU5hbWU6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgICByZXR1cm4gaG9zdFxuICAgICAgICAucmVhZChmaWxlTmFtZSlcbiAgICAgICAgLnRvU3RyaW5nKClcbiAgICAgICAgLnJlcGxhY2UoL15cXHVGRUZGLywgJycpO1xuICAgIH07XG4gICAgdHNIb3N0LmRpcmVjdG9yeUV4aXN0cyA9IGZ1bmN0aW9uIChkaXJlY3RvcnlOYW1lOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICAgIC8vIFdoZW4gdGhlIHBhdGggaXMgZmlsZSBnZXREaXIgd2lsbCB0aHJvdy5cbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGRpciA9IGhvc3QuZ2V0RGlyKGRpcmVjdG9yeU5hbWUpO1xuXG4gICAgICAgIHJldHVybiAhIShkaXIuc3ViZGlycy5sZW5ndGggfHwgZGlyLnN1YmZpbGVzLmxlbmd0aCk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgIH07XG4gICAgdHNIb3N0LmZpbGVFeGlzdHMgPSBmdW5jdGlvbiAoZmlsZU5hbWU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgICAgcmV0dXJuIGhvc3QuZXhpc3RzKGZpbGVOYW1lKTtcbiAgICB9O1xuICAgIHRzSG9zdC5yZWFscGF0aCA9IGZ1bmN0aW9uIChwYXRoOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgICAgcmV0dXJuIHBhdGg7XG4gICAgfTtcbiAgICB0c0hvc3QuZ2V0Q3VycmVudERpcmVjdG9yeSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBob3N0LnJvb3QucGF0aDtcbiAgICB9O1xuXG4gICAgY29uc3QgcHJvZ3JhbSA9IHRzLmNyZWF0ZVByb2dyYW0ocGFyc2VkLmZpbGVOYW1lcywgcGFyc2VkLm9wdGlvbnMsIHRzSG9zdCk7XG4gICAgY29uc3QgdHlwZUNoZWNrZXIgPSBwcm9ncmFtLmdldFR5cGVDaGVja2VyKCk7XG4gICAgY29uc3Qgc291cmNlRmlsZXMgPSBwcm9ncmFtXG4gICAgICAuZ2V0U291cmNlRmlsZXMoKVxuICAgICAgLmZpbHRlcigoZikgPT4gIWYuaXNEZWNsYXJhdGlvbkZpbGUgJiYgIXByb2dyYW0uaXNTb3VyY2VGaWxlRnJvbUV4dGVybmFsTGlicmFyeShmKSk7XG4gICAgY29uc3QgcHJpbnRlciA9IHRzLmNyZWF0ZVByaW50ZXIoKTtcbiAgICBjb25zdCByb3V0ZXJNb2R1bGUgPSAnUm91dGVyTW9kdWxlJztcbiAgICBjb25zdCByb3V0ZXJTb3VyY2UgPSAnQGFuZ3VsYXIvcm91dGVyJztcblxuICAgIHNvdXJjZUZpbGVzLmZvckVhY2goKHNvdXJjZUZpbGUpID0+IHtcbiAgICAgIGNvbnN0IHJvdXRlckltcG9ydCA9IGZpbmRJbXBvcnQoc291cmNlRmlsZSwgcm91dGVyU291cmNlLCByb3V0ZXJNb2R1bGUpO1xuICAgICAgaWYgKCFyb3V0ZXJJbXBvcnQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBsZXQgcm91dGVyTW9kdWxlTm9kZTogdHMuQ2FsbEV4cHJlc3Npb247XG4gICAgICB0cy5mb3JFYWNoQ2hpbGQoc291cmNlRmlsZSwgZnVuY3Rpb24gdmlzaXROb2RlKG5vZGU6IHRzLk5vZGUpIHtcbiAgICAgICAgaWYgKFxuICAgICAgICAgIHRzLmlzQ2FsbEV4cHJlc3Npb24obm9kZSkgJiZcbiAgICAgICAgICB0cy5pc1Byb3BlcnR5QWNjZXNzRXhwcmVzc2lvbihub2RlLmV4cHJlc3Npb24pICYmXG4gICAgICAgICAgdHMuaXNJZGVudGlmaWVyKG5vZGUuZXhwcmVzc2lvbi5leHByZXNzaW9uKSAmJlxuICAgICAgICAgIG5vZGUuZXhwcmVzc2lvbi5uYW1lLnRleHQgPT09ICdmb3JSb290J1xuICAgICAgICApIHtcbiAgICAgICAgICBjb25zdCBpbXAgPSBnZXRJbXBvcnRPZklkZW50aWZpZXIodHlwZUNoZWNrZXIsIG5vZGUuZXhwcmVzc2lvbi5leHByZXNzaW9uKTtcblxuICAgICAgICAgIGlmIChpbXAgJiYgaW1wLm5hbWUgPT09IHJvdXRlck1vZHVsZSAmJiBpbXAuaW1wb3J0TW9kdWxlID09PSByb3V0ZXJTb3VyY2UpIHtcbiAgICAgICAgICAgIHJvdXRlck1vZHVsZU5vZGUgPSBub2RlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHRzLmZvckVhY2hDaGlsZChub2RlLCB2aXNpdE5vZGUpO1xuICAgICAgfSk7XG5cbiAgICAgIGlmIChyb3V0ZXJNb2R1bGVOb2RlKSB7XG4gICAgICAgIGNvbnN0IHByaW50ID0gcHJpbnRlci5wcmludE5vZGUoXG4gICAgICAgICAgdHMuRW1pdEhpbnQuVW5zcGVjaWZpZWQsXG4gICAgICAgICAgYWRkSW5pdGlhbE5hdmlnYXRpb24ocm91dGVyTW9kdWxlTm9kZSksXG4gICAgICAgICAgc291cmNlRmlsZSxcbiAgICAgICAgKTtcblxuICAgICAgICBjb25zdCByZWNvcmRlciA9IGhvc3QuYmVnaW5VcGRhdGUoc291cmNlRmlsZS5maWxlTmFtZSk7XG4gICAgICAgIHJlY29yZGVyLnJlbW92ZShyb3V0ZXJNb2R1bGVOb2RlLmdldFN0YXJ0KCksIHJvdXRlck1vZHVsZU5vZGUuZ2V0V2lkdGgoKSk7XG4gICAgICAgIHJlY29yZGVyLmluc2VydFJpZ2h0KHJvdXRlck1vZHVsZU5vZGUuZ2V0U3RhcnQoKSwgcHJpbnQpO1xuICAgICAgICBob3N0LmNvbW1pdFVwZGF0ZShyZWNvcmRlcik7XG4gICAgICB9XG4gICAgfSk7XG4gIH07XG59XG5cbmZ1bmN0aW9uIGFkZERlcGVuZGVuY2llcygpOiBSdWxlIHtcbiAgcmV0dXJuIChfaG9zdDogVHJlZSkgPT4ge1xuICAgIHJldHVybiBjaGFpbihbXG4gICAgICBhZGREZXBlbmRlbmN5KCdAbmd1bml2ZXJzYWwvYnVpbGRlcnMnLCAnXjAuMC4wLVBMQUNFSE9MREVSJywge1xuICAgICAgICB0eXBlOiBEZXBlbmRlbmN5VHlwZS5EZXYsXG4gICAgICB9KSxcbiAgICAgIGFkZERlcGVuZGVuY3koJ0BuZ3VuaXZlcnNhbC9leHByZXNzLWVuZ2luZScsICdeMC4wLjAtUExBQ0VIT0xERVInLCB7XG4gICAgICAgIHR5cGU6IERlcGVuZGVuY3lUeXBlLkRlZmF1bHQsXG4gICAgICB9KSxcbiAgICAgIGFkZERlcGVuZGVuY3koJ2V4cHJlc3MnLCAnRVhQUkVTU19WRVJTSU9OJywge1xuICAgICAgICB0eXBlOiBEZXBlbmRlbmN5VHlwZS5EZWZhdWx0LFxuICAgICAgfSksXG4gICAgICBhZGREZXBlbmRlbmN5KCdAdHlwZXMvZXhwcmVzcycsICdFWFBSRVNTX1RZUEVTX1ZFUlNJT04nLCB7XG4gICAgICAgIHR5cGU6IERlcGVuZGVuY3lUeXBlLkRldixcbiAgICAgIH0pLFxuICAgIF0pO1xuICB9O1xufVxuXG5mdW5jdGlvbiBhZGRTZXJ2ZXJGaWxlKG9wdGlvbnM6IFVuaXZlcnNhbE9wdGlvbnMsIGlzU3RhbmRhbG9uZTogYm9vbGVhbik6IFJ1bGUge1xuICByZXR1cm4gYXN5bmMgKGhvc3QpID0+IHtcbiAgICBjb25zdCBwcm9qZWN0ID0gYXdhaXQgZ2V0UHJvamVjdChob3N0LCBvcHRpb25zLnByb2plY3QpO1xuICAgIGNvbnN0IGJyb3dzZXJEaXN0RGlyZWN0b3J5ID0gYXdhaXQgZ2V0T3V0cHV0UGF0aChob3N0LCBvcHRpb25zLnByb2plY3QsICdidWlsZCcpO1xuXG4gICAgcmV0dXJuIG1lcmdlV2l0aChcbiAgICAgIGFwcGx5KHVybCgnLi9maWxlcycpLCBbXG4gICAgICAgIHRlbXBsYXRlKHtcbiAgICAgICAgICAuLi5zdHJpbmdzLFxuICAgICAgICAgIC4uLm9wdGlvbnMsXG4gICAgICAgICAgc3RyaXBUc0V4dGVuc2lvbixcbiAgICAgICAgICBicm93c2VyRGlzdERpcmVjdG9yeSxcbiAgICAgICAgICBpc1N0YW5kYWxvbmUsXG4gICAgICAgIH0pLFxuICAgICAgICBtb3ZlKHByb2plY3Qucm9vdCksXG4gICAgICBdKSxcbiAgICApO1xuICB9O1xufVxuXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiAob3B0aW9uczogQWRkVW5pdmVyc2FsT3B0aW9ucyk6IFJ1bGUge1xuICByZXR1cm4gYXN5bmMgKGhvc3QpID0+IHtcbiAgICBjb25zdCBwcm9qZWN0ID0gYXdhaXQgZ2V0UHJvamVjdChob3N0LCBvcHRpb25zLnByb2plY3QpO1xuICAgIGNvbnN0IHVuaXZlcnNhbE9wdGlvbnMgPSB7XG4gICAgICAuLi5vcHRpb25zLFxuICAgICAgc2tpcEluc3RhbGw6IHRydWUsXG4gICAgfTtcbiAgICBjb25zdCBjbGllbnRCdWlsZFRhcmdldCA9IHByb2plY3QudGFyZ2V0cy5nZXQoJ2J1aWxkJyk7XG4gICAgaWYgKCFjbGllbnRCdWlsZFRhcmdldCkge1xuICAgICAgdGhyb3cgdGFyZ2V0QnVpbGROb3RGb3VuZEVycm9yKCk7XG4gICAgfVxuXG4gICAgY29uc3QgY2xpZW50QnVpbGRPcHRpb25zID0gKGNsaWVudEJ1aWxkVGFyZ2V0Lm9wdGlvbnMgfHxcbiAgICAgIHt9KSBhcyB1bmtub3duIGFzIEJyb3dzZXJCdWlsZGVyT3B0aW9ucztcblxuICAgIGNvbnN0IGlzU3RhbmRhbG9uZSA9IGlzU3RhbmRhbG9uZUFwcChob3N0LCBjbGllbnRCdWlsZE9wdGlvbnMubWFpbik7XG5cbiAgICBkZWxldGUgdW5pdmVyc2FsT3B0aW9ucy5zZXJ2ZXJGaWxlTmFtZTtcbiAgICBkZWxldGUgdW5pdmVyc2FsT3B0aW9ucy5zZXJ2ZXJQb3J0O1xuXG4gICAgcmV0dXJuIGNoYWluKFtcbiAgICAgIHByb2plY3QudGFyZ2V0cy5oYXMoJ3NlcnZlcicpXG4gICAgICAgID8gbm9vcCgpXG4gICAgICAgIDogZXh0ZXJuYWxTY2hlbWF0aWMoJ0BzY2hlbWF0aWNzL2FuZ3VsYXInLCAndW5pdmVyc2FsJywgdW5pdmVyc2FsT3B0aW9ucyksXG4gICAgICBhZGRTY3JpcHRzUnVsZShvcHRpb25zKSxcbiAgICAgIHVwZGF0ZVNlcnZlclRzQ29uZmlnUnVsZShvcHRpb25zKSxcbiAgICAgIHVwZGF0ZVdvcmtzcGFjZUNvbmZpZ1J1bGUob3B0aW9ucyksXG4gICAgICBpc1N0YW5kYWxvbmUgPyBub29wKCkgOiByb3V0aW5nSW5pdGlhbE5hdmlnYXRpb25SdWxlKG9wdGlvbnMpLFxuICAgICAgYWRkU2VydmVyRmlsZShvcHRpb25zLCBpc1N0YW5kYWxvbmUpLFxuICAgICAgYWRkRGVwZW5kZW5jaWVzKCksXG4gICAgXSk7XG4gIH07XG59XG4iXX0=