UNPKG

37.7 kBJavaScriptView Raw
1/**
2 * @license
3 * Copyright Google LLC All Rights Reserved.
4 *
5 * Use of this source code is governed by an MIT-style license that can be
6 * found in the LICENSE file at https://angular.io/license
7 */
8import { dirname, join, normalize, strings } from '@angular-devkit/core';
9import { SchematicsException, apply, chain, externalSchematic, mergeWith, move, noop, template, url, } from '@angular-devkit/schematics';
10import { DependencyType, addDependency, updateWorkspace } from '@schematics/angular/utility';
11import { JSONFile } from '@schematics/angular/utility/json-file';
12import { isStandaloneApp } from '@schematics/angular/utility/ng-ast-utils';
13import { targetBuildNotFoundError } from '@schematics/angular/utility/project-targets';
14import * as ts from 'typescript';
15import { addInitialNavigation, findImport, getImportOfIdentifier, getOutputPath, getProject, stripTsExtension, } from '../utils';
16const SERVE_SSR_TARGET_NAME = 'serve-ssr';
17const PRERENDER_TARGET_NAME = 'prerender';
18function addScriptsRule(options) {
19 return async (host) => {
20 const pkgPath = '/package.json';
21 const buffer = host.read(pkgPath);
22 if (buffer === null) {
23 throw new SchematicsException('Could not find package.json');
24 }
25 const serverDist = await getOutputPath(host, options.project, 'server');
26 const pkg = JSON.parse(buffer.toString());
27 pkg.scripts = {
28 ...pkg.scripts,
29 'dev:ssr': `ng run ${options.project}:${SERVE_SSR_TARGET_NAME}`,
30 'serve:ssr': `node ${serverDist}/main.js`,
31 'build:ssr': `ng build && ng run ${options.project}:server`,
32 'prerender': `ng run ${options.project}:${PRERENDER_TARGET_NAME}`,
33 };
34 host.overwrite(pkgPath, JSON.stringify(pkg, null, 2));
35 };
36}
37function updateWorkspaceConfigRule(options) {
38 return () => {
39 return updateWorkspace((workspace) => {
40 const projectName = options.project;
41 const project = workspace.projects.get(projectName);
42 if (!project) {
43 return;
44 }
45 const serverTarget = project.targets.get('server');
46 serverTarget.options.main = join(normalize(project.root), stripTsExtension(options.serverFileName) + '.ts');
47 const serveSSRTarget = project.targets.get(SERVE_SSR_TARGET_NAME);
48 if (serveSSRTarget) {
49 return;
50 }
51 project.targets.add({
52 name: SERVE_SSR_TARGET_NAME,
53 builder: '@nguniversal/builders:ssr-dev-server',
54 defaultConfiguration: 'development',
55 options: {},
56 configurations: {
57 development: {
58 browserTarget: `${projectName}:build:development`,
59 serverTarget: `${projectName}:server:development`,
60 },
61 production: {
62 browserTarget: `${projectName}:build:production`,
63 serverTarget: `${projectName}:server:production`,
64 },
65 },
66 });
67 const prerenderTarget = project.targets.get(PRERENDER_TARGET_NAME);
68 if (prerenderTarget) {
69 return;
70 }
71 project.targets.add({
72 name: PRERENDER_TARGET_NAME,
73 builder: '@nguniversal/builders:prerender',
74 defaultConfiguration: 'production',
75 options: {
76 routes: ['/'],
77 },
78 configurations: {
79 production: {
80 browserTarget: `${projectName}:build:production`,
81 serverTarget: `${projectName}:server:production`,
82 },
83 development: {
84 browserTarget: `${projectName}:build:development`,
85 serverTarget: `${projectName}:server:development`,
86 },
87 },
88 });
89 });
90 };
91}
92function updateServerTsConfigRule(options) {
93 return async (host) => {
94 const project = await getProject(host, options.project);
95 const serverTarget = project.targets.get('server');
96 if (!serverTarget || !serverTarget.options) {
97 return;
98 }
99 const tsConfigPath = serverTarget.options.tsConfig;
100 if (!tsConfigPath || typeof tsConfigPath !== 'string') {
101 // No tsconfig path
102 return;
103 }
104 const tsConfig = new JSONFile(host, tsConfigPath);
105 const filesAstNode = tsConfig.get(['files']);
106 const serverFilePath = stripTsExtension(options.serverFileName) + '.ts';
107 if (Array.isArray(filesAstNode) && !filesAstNode.some(({ text }) => text === serverFilePath)) {
108 tsConfig.modify(['files'], [...filesAstNode, serverFilePath]);
109 }
110 };
111}
112function routingInitialNavigationRule(options) {
113 return async (host) => {
114 const project = await getProject(host, options.project);
115 const serverTarget = project.targets.get('server');
116 if (!serverTarget || !serverTarget.options) {
117 return;
118 }
119 const tsConfigPath = serverTarget.options.tsConfig;
120 if (!tsConfigPath || typeof tsConfigPath !== 'string' || !host.exists(tsConfigPath)) {
121 // No tsconfig path
122 return;
123 }
124 const parseConfigHost = {
125 useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames,
126 readDirectory: ts.sys.readDirectory,
127 fileExists: function (fileName) {
128 return host.exists(fileName);
129 },
130 readFile: function (fileName) {
131 return host.read(fileName).toString();
132 },
133 };
134 const { config } = ts.readConfigFile(tsConfigPath, parseConfigHost.readFile);
135 const parsed = ts.parseJsonConfigFileContent(config, parseConfigHost, dirname(normalize(tsConfigPath)));
136 const tsHost = ts.createCompilerHost(parsed.options, true);
137 // Strip BOM as otherwise TSC methods (Ex: getWidth) will return an offset,
138 // which breaks the CLI UpdateRecorder.
139 // See: https://github.com/angular/angular/pull/30719
140 tsHost.readFile = function (fileName) {
141 return host
142 .read(fileName)
143 .toString()
144 .replace(/^\uFEFF/, '');
145 };
146 tsHost.directoryExists = function (directoryName) {
147 // When the path is file getDir will throw.
148 try {
149 const dir = host.getDir(directoryName);
150 return !!(dir.subdirs.length || dir.subfiles.length);
151 }
152 catch {
153 return false;
154 }
155 };
156 tsHost.fileExists = function (fileName) {
157 return host.exists(fileName);
158 };
159 tsHost.realpath = function (path) {
160 return path;
161 };
162 tsHost.getCurrentDirectory = function () {
163 return host.root.path;
164 };
165 const program = ts.createProgram(parsed.fileNames, parsed.options, tsHost);
166 const typeChecker = program.getTypeChecker();
167 const sourceFiles = program
168 .getSourceFiles()
169 .filter((f) => !f.isDeclarationFile && !program.isSourceFileFromExternalLibrary(f));
170 const printer = ts.createPrinter();
171 const routerModule = 'RouterModule';
172 const routerSource = '@angular/router';
173 sourceFiles.forEach((sourceFile) => {
174 const routerImport = findImport(sourceFile, routerSource, routerModule);
175 if (!routerImport) {
176 return;
177 }
178 let routerModuleNode;
179 ts.forEachChild(sourceFile, function visitNode(node) {
180 if (ts.isCallExpression(node) &&
181 ts.isPropertyAccessExpression(node.expression) &&
182 ts.isIdentifier(node.expression.expression) &&
183 node.expression.name.text === 'forRoot') {
184 const imp = getImportOfIdentifier(typeChecker, node.expression.expression);
185 if (imp && imp.name === routerModule && imp.importModule === routerSource) {
186 routerModuleNode = node;
187 }
188 }
189 ts.forEachChild(node, visitNode);
190 });
191 if (routerModuleNode) {
192 const print = printer.printNode(ts.EmitHint.Unspecified, addInitialNavigation(routerModuleNode), sourceFile);
193 const recorder = host.beginUpdate(sourceFile.fileName);
194 recorder.remove(routerModuleNode.getStart(), routerModuleNode.getWidth());
195 recorder.insertRight(routerModuleNode.getStart(), print);
196 host.commitUpdate(recorder);
197 }
198 });
199 };
200}
201function addDependencies() {
202 return (_host) => {
203 return chain([
204 addDependency('@nguniversal/builders', '^16.0.2', {
205 type: DependencyType.Dev,
206 }),
207 addDependency('@nguniversal/express-engine', '^16.0.2', {
208 type: DependencyType.Default,
209 }),
210 addDependency('express', '^4.15.2', {
211 type: DependencyType.Default,
212 }),
213 addDependency('@types/express', '^4.17.0', {
214 type: DependencyType.Dev,
215 }),
216 ]);
217 };
218}
219function addServerFile(options, isStandalone) {
220 return async (host) => {
221 const project = await getProject(host, options.project);
222 const browserDistDirectory = await getOutputPath(host, options.project, 'build');
223 return mergeWith(apply(url('./files'), [
224 template({
225 ...strings,
226 ...options,
227 stripTsExtension,
228 browserDistDirectory,
229 isStandalone,
230 }),
231 move(project.root),
232 ]));
233 };
234}
235export default function (options) {
236 return async (host) => {
237 const project = await getProject(host, options.project);
238 const universalOptions = {
239 ...options,
240 skipInstall: true,
241 };
242 const clientBuildTarget = project.targets.get('build');
243 if (!clientBuildTarget) {
244 throw targetBuildNotFoundError();
245 }
246 const clientBuildOptions = (clientBuildTarget.options ||
247 {});
248 const isStandalone = isStandaloneApp(host, clientBuildOptions.main);
249 delete universalOptions.serverFileName;
250 delete universalOptions.serverPort;
251 return chain([
252 project.targets.has('server')
253 ? noop()
254 : externalSchematic('@schematics/angular', 'universal', universalOptions),
255 addScriptsRule(options),
256 updateServerTsConfigRule(options),
257 updateWorkspaceConfigRule(options),
258 isStandalone ? noop() : routingInitialNavigationRule(options),
259 addServerFile(options, isStandalone),
260 addDependencies(),
261 ]);
262 };
263}
264//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9tb2R1bGVzL2V4cHJlc3MtZW5naW5lL3NjaGVtYXRpY3MvaW5zdGFsbC9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFFSCxPQUFPLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDekUsT0FBTyxFQUVMLG1CQUFtQixFQUVuQixLQUFLLEVBQ0wsS0FBSyxFQUNMLGlCQUFpQixFQUNqQixTQUFTLEVBQ1QsSUFBSSxFQUNKLElBQUksRUFDSixRQUFRLEVBQ1IsR0FBRyxHQUNKLE1BQU0sNEJBQTRCLENBQUM7QUFFcEMsT0FBTyxFQUFFLGNBQWMsRUFBRSxhQUFhLEVBQUUsZUFBZSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDN0YsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLHVDQUF1QyxDQUFDO0FBQ2pFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwwQ0FBMEMsQ0FBQztBQUMzRSxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSw2Q0FBNkMsQ0FBQztBQUV2RixPQUFPLEtBQUssRUFBRSxNQUFNLFlBQVksQ0FBQztBQUVqQyxPQUFPLEVBQ0wsb0JBQW9CLEVBQ3BCLFVBQVUsRUFDVixxQkFBcUIsRUFDckIsYUFBYSxFQUNiLFVBQVUsRUFDVixnQkFBZ0IsR0FDakIsTUFBTSxVQUFVLENBQUM7QUFJbEIsTUFBTSxxQkFBcUIsR0FBRyxXQUFXLENBQUM7QUFDMUMsTUFBTSxxQkFBcUIsR0FBRyxXQUFXLENBQUM7QUFFMUMsU0FBUyxjQUFjLENBQUMsT0FBNEI7SUFDbEQsT0FBTyxLQUFLLEVBQUUsSUFBSSxFQUFFLEVBQUU7UUFDcEIsTUFBTSxPQUFPLEdBQUcsZUFBZSxDQUFDO1FBQ2hDLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxJQUFJLENB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O1FBQ3hELE1BQU0sZ0JBQWdCLEdBQUc7WUFDdkIsR0FBRyxPQUFPO1lBQ1YsV0FBVyxFQUFFLElBQUk7U0FDbEIsQ0FBQztRQUNGLE1BQU0saUJBQWlCLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDdkQsSUFBSSxDQUFDLGlCQUFpQixFQUFFO1lBQ3RCLE1BQU0sd0JBQXdCLEVBQUUsQ0FBQztTQUNsQztRQUVELE1BQU0sa0JBQWtCLEdBQUcsQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPO1lBQ25ELEVBQUUsQ0FBcUMsQ0FBQztRQUUxQyxNQUFNLFlBQVksR0FBRyxlQUFlLENBQUMsSUFBSSxFQUFFLGtCQUFrQixDQUFDLElBQUksQ0FBQyxDQUFDO1FBRXBFLE9BQU8sZ0JBQWdCLENBQUMsY0FBYyxDQUFDO1FBQ3ZDLE9BQU8sZ0JBQWdCLENBQUMsVUFBVSxDQUFDO1FBRW5DLE9BQU8sS0FBSyxDQUFDO1lBQ1gsT0FBTyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDO2dCQUMzQixDQUFDLENBQUMsSUFBSSxFQUFFO2dCQUNSLENBQUMsQ0FBQyxpQkFBaUIsQ0FBQyxxQkFBcUIsRUFBRSxXQUFXLEVBQUUsZ0JBQWdCLENBQUM7WUFDM0UsY0FBYyxDQUFDLE9BQU8sQ0FBQztZQUN2Qix3QkFBd0IsQ0FBQyxPQUFPLENBQUM7WUFDakMseUJBQXlCLENBQUMsT0FBTyxDQUFDO1lBQ2xDLFlBQVksQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLDRCQUE0QixDQUFDLE9BQU8sQ0FBQztZQUM3RCxhQUFhLENBQUMsT0FBTyxFQUFFLFlBQVksQ0FBQztZQUNwQyxlQUFlLEVBQUU7U0FDbEIsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgTExDIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlIGxpY2Vuc2UgdGhhdCBjYW4gYmVcbiAqIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgYXQgaHR0cHM6Ly9hbmd1bGFyLmlvL2xpY2Vuc2VcbiAqL1xuXG5pbXBvcnQgeyBkaXJuYW1lLCBqb2luLCBub3JtYWxpemUsIHN0cmluZ3MgfSBmcm9tICdAYW5ndWxhci1kZXZraXQvY29yZSc7XG5pbXBvcnQge1xuICBSdWxlLFxuICBTY2hlbWF0aWNzRXhjZXB0aW9uLFxuICBUcmVlLFxuICBhcHBseSxcbiAgY2hhaW4sXG4gIGV4dGVybmFsU2NoZW1hdGljLFxuICBtZXJnZVdpdGgsXG4gIG1vdmUsXG4gIG5vb3AsXG4gIHRlbXBsYXRlLFxuICB1cmwsXG59IGZyb20gJ0Bhbmd1bGFyLWRldmtpdC9zY2hlbWF0aWNzJztcbmltcG9ydCB7IFNjaGVtYSBhcyBVbml2ZXJzYWxPcHRpb25zIH0gZnJvbSAnQHNjaGVtYXRpY3MvYW5ndWxhci91bml2ZXJzYWwvc2NoZW1hJztcbmltcG9ydCB7IERlcGVuZGVuY3lUeXBlLCBhZGREZXBlbmRlbmN5LCB1cGRhdGVXb3Jrc3BhY2UgfSBmcm9tICdAc2NoZW1hdGljcy9hbmd1bGFyL3V0aWxpdHknO1xuaW1wb3J0IHsgSlNPTkZpbGUgfSBmcm9tICdAc2NoZW1hdGljcy9hbmd1bGFyL3V0aWxpdHkvanNvbi1maWxlJztcbmltcG9ydCB7IGlzU3RhbmRhbG9uZUFwcCB9IGZyb20gJ0BzY2hlbWF0aWNzL2FuZ3VsYXIvdXRpbGl0eS9uZy1hc3QtdXRpbHMnO1xuaW1wb3J0IHsgdGFyZ2V0QnVpbGROb3RGb3VuZEVycm9yIH0gZnJvbSAnQHNjaGVtYXRpY3MvYW5ndWxhci91dGlsaXR5L3Byb2plY3QtdGFyZ2V0cyc7XG5pbXBvcnQgeyBCcm93c2VyQnVpbGRlck9wdGlvbnMgfSBmcm9tICdAc2NoZW1hdGljcy9hbmd1bGFyL3V0aWxpdHkvd29ya3NwYWNlLW1vZGVscyc7XG5pbXBvcnQgKiBhcyB0cyBmcm9tICd0eXBlc2NyaXB0JztcblxuaW1wb3J0IHtcbiAgYWRkSW5pdGlhbE5hdmlnYXRpb24sXG4gIGZpbmRJbXBvcnQsXG4gIGdldEltcG9ydE9mSWRlbnRpZmllcixcbiAgZ2V0T3V0cHV0UGF0aCxcbiAgZ2V0UHJvamVjdCxcbiAgc3RyaXBUc0V4dGVuc2lvbixcbn0gZnJvbSAnLi4vdXRpbHMnO1xuXG5pbXBvcnQgeyBTY2hlbWEgYXMgQWRkVW5pdmVyc2FsT3B0aW9ucyB9IGZyb20gJy4vc2NoZW1hJztcblxuY29uc3QgU0VSVkVfU1NSX1RBUkdFVF9OQU1FID0gJ3NlcnZlLXNzcic7XG5jb25zdCBQUkVSRU5ERVJfVEFSR0VUX05BTUUgPSAncHJlcmVuZGVyJztcblxuZnVuY3Rpb24gYWRkU2NyaXB0c1J1bGUob3B0aW9uczogQWRkVW5pdmVyc2FsT3B0aW9ucyk6IFJ1bGUge1xuICByZXR1cm4gYXN5bmMgKGhvc3QpID0+IHtcbiAgICBjb25zdCBwa2dQYXRoID0gJy9wYWNrYWdlLmpzb24nO1xuICAgIGNvbnN0IGJ1ZmZlciA9IGhvc3QucmVhZChwa2dQYXRoKTtcbiAgICBpZiAoYnVmZmVyID09PSBudWxsKSB7XG4gICAgICB0aHJvdyBuZXcgU2NoZW1hdGljc0V4Y2VwdGlvbignQ291bGQgbm90IGZpbmQgcGFja2FnZS5qc29uJyk7XG4gICAgfVxuXG4gICAgY29uc3Qgc2VydmVyRGlzdCA9IGF3YWl0IGdldE91dHB1dFBhdGgoaG9zdCwgb3B0aW9ucy5wcm9qZWN0LCAnc2VydmVyJyk7XG4gICAgY29uc3QgcGtnID0gSlNPTi5wYXJzZShidWZmZXIudG9TdHJpbmcoKSkgYXMgYW55O1xuICAgIHBrZy5zY3JpcHRzID0ge1xuICAgICAgLi4ucGtnLnNjcmlwdHMsXG4gICAgICAnZGV2OnNzcic6IGBuZyBydW4gJHtvcHRpb25zLnByb2plY3R9OiR7U0VSVkVfU1NSX1RBUkdFVF9OQU1FfWAsXG4gICAgICAnc2VydmU6c3NyJzogYG5vZGUgJHtzZXJ2ZXJEaXN0fS9tYWluLmpzYCxcbiAgICAgICdidWlsZDpzc3InOiBgbmcgYnVpbGQgJiYgbmcgcnVuICR7b3B0aW9ucy5wcm9qZWN0fTpzZXJ2ZXJgLFxuICAgICAgJ3ByZXJlbmRlcic6IGBuZyBydW4gJHtvcHRpb25zLnByb2plY3R9OiR7UFJFUkVOREVSX1RBUkdFVF9OQU1FfWAsXG4gICAgfTtcblxuICAgIGhvc3Qub3ZlcndyaXRlKHBrZ1BhdGgsIEpTT04uc3RyaW5naWZ5KHBrZywgbnVsbCwgMikpO1xuICB9O1xufVxuXG5mdW5jdGlvbiB1cGRhdGVXb3Jrc3BhY2VDb25maWdSdWxlKG9wdGlvbnM6IEFkZFVuaXZlcnNhbE9wdGlvbnMpOiBSdWxlIHtcbiAgcmV0dXJuICgpID0+IHtcbiAgICByZXR1cm4gdXBkYXRlV29ya3NwYWNlKCh3b3Jrc3BhY2UpID0+IHtcbiAgICAgIGNvbnN0IHByb2plY3ROYW1lID0gb3B0aW9ucy5wcm9qZWN0O1xuICAgICAgY29uc3QgcHJvamVjdCA9IHdvcmtzcGFjZS5wcm9qZWN0cy5nZXQocHJvamVjdE5hbWUpO1xuICAgICAgaWYgKCFwcm9qZWN0KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3Qgc2VydmVyVGFyZ2V0ID0gcHJvamVjdC50YXJnZXRzLmdldCgnc2VydmVyJyk7XG4gICAgICBzZXJ2ZXJUYXJnZXQub3B0aW9ucy5tYWluID0gam9pbihcbiAgICAgICAgbm9ybWFsaXplKHByb2plY3Qucm9vdCksXG4gICAgICAgIHN0cmlwVHNFeHRlbnNpb24ob3B0aW9ucy5zZXJ2ZXJGaWxlTmFtZSkgKyAnLnRzJyxcbiAgICAgICk7XG5cbiAgICAgIGNvbnN0IHNlcnZlU1NSVGFyZ2V0ID0gcHJvamVjdC50YXJnZXRzLmdldChTRVJWRV9TU1JfVEFSR0VUX05BTUUpO1xuICAgICAgaWYgKHNlcnZlU1NSVGFyZ2V0KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgcHJvamVjdC50YXJnZXRzLmFkZCh7XG4gICAgICAgIG5hbWU6IFNFUlZFX1NTUl9UQVJHRVRfTkFNRSxcbiAgICAgICAgYnVpbGRlcjogJ0BuZ3VuaXZlcnNhbC9idWlsZGVyczpzc3ItZGV2LXNlcnZlcicsXG4gICAgICAgIGRlZmF1bHRDb25maWd1cmF0aW9uOiAnZGV2ZWxvcG1lbnQnLFxuICAgICAgICBvcHRpb25zOiB7fSxcbiAgICAgICAgY29uZmlndXJhdGlvbnM6IHtcbiAgICAgICAgICBkZXZlbG9wbWVudDoge1xuICAgICAgICAgICAgYnJvd3NlclRhcmdldDogYCR7cHJvamVjdE5hbWV9OmJ1aWxkOmRldmVsb3BtZW50YCxcbiAgICAgICAgICAgIHNlcnZlclRhcmdldDogYCR7cHJvamVjdE5hbWV9OnNlcnZlcjpkZXZlbG9wbWVudGAsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBwcm9kdWN0aW9uOiB7XG4gICAgICAgICAgICBicm93c2VyVGFyZ2V0OiBgJHtwcm9qZWN0TmFtZX06YnVpbGQ6cHJvZHVjdGlvbmAsXG4gICAgICAgICAgICBzZXJ2ZXJUYXJnZXQ6IGAke3Byb2plY3ROYW1lfTpzZXJ2ZXI6cHJvZHVjdGlvbmAsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuXG4gICAgICBjb25zdCBwcmVyZW5kZXJUYXJnZXQgPSBwcm9qZWN0LnRhcmdldHMuZ2V0KFBSRVJFTkRFUl9UQVJHRVRfTkFNRSk7XG4gICAgICBpZiAocHJlcmVuZGVyVGFyZ2V0KSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgcHJvamVjdC50YXJnZXRzLmFkZCh7XG4gICAgICAgIG5hbWU6IFBSRVJFTkRFUl9UQVJHRVRfTkFNRSxcbiAgICAgICAgYnVpbGRlcjogJ0BuZ3VuaXZlcnNhbC9idWlsZGVyczpwcmVyZW5kZXInLFxuICAgICAgICBkZWZhdWx0Q29uZmlndXJhdGlvbjogJ3Byb2R1Y3Rpb24nLFxuICAgICAgICBvcHRpb25zOiB7XG4gICAgICAgICAgcm91dGVzOiBbJy8nXSxcbiAgICAgICAgfSxcbiAgICAgICAgY29uZmlndXJhdGlvbnM6IHtcbiAgICAgICAgICBwcm9kdWN0aW9uOiB7XG4gICAgICAgICAgICBicm93c2VyVGFyZ2V0OiBgJHtwcm9qZWN0TmFtZX06YnVpbGQ6cHJvZHVjdGlvbmAsXG4gICAgICAgICAgICBzZXJ2ZXJUYXJnZXQ6IGAke3Byb2plY3ROYW1lfTpzZXJ2ZXI6cHJvZHVjdGlvbmAsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBkZXZlbG9wbWVudDoge1xuICAgICAgICAgICAgYnJvd3NlclRhcmdldDogYCR7cHJvamVjdE5hbWV9OmJ1aWxkOmRldmVsb3BtZW50YCxcbiAgICAgICAgICAgIHNlcnZlclRhcmdldDogYCR7cHJvamVjdE5hbWV9OnNlcnZlcjpkZXZlbG9wbWVudGAsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9O1xufVxuXG5mdW5jdGlvbiB1cGRhdGVTZXJ2ZXJUc0NvbmZpZ1J1bGUob3B0aW9uczogQWRkVW5pdmVyc2FsT3B0aW9ucyk6IFJ1bGUge1xuICByZXR1cm4gYXN5bmMgKGhvc3QpID0+IHtcbiAgICBjb25zdCBwcm9qZWN0ID0gYXdhaXQgZ2V0UHJvamVjdChob3N0LCBvcHRpb25zLnByb2plY3QpO1xuICAgIGNvbnN0IHNlcnZlclRhcmdldCA9IHByb2plY3QudGFyZ2V0cy5nZXQoJ3NlcnZlcicpO1xuICAgIGlmICghc2VydmVyVGFyZ2V0IHx8ICFzZXJ2ZXJUYXJnZXQub3B0aW9ucykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHRzQ29uZmlnUGF0aCA9IHNlcnZlclRhcmdldC5vcHRpb25zLnRzQ29uZmlnO1xuICAgIGlmICghdHNDb25maWdQYXRoIHx8IHR5cGVvZiB0c0NvbmZpZ1BhdGggIT09ICdzdHJpbmcnKSB7XG4gICAgICAvLyBObyB0c2NvbmZpZyBwYXRoXG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgdHNDb25maWcgPSBuZXcgSlNPTkZpbGUoaG9zdCwgdHNDb25maWdQYXRoKTtcbiAgICBjb25zdCBmaWxlc0FzdE5vZGUgPSB0c0NvbmZpZy5nZXQoWydmaWxlcyddKTtcbiAgICBjb25zdCBzZXJ2ZXJGaWxlUGF0aCA9IHN0cmlwVHNFeHRlbnNpb24ob3B0aW9ucy5zZXJ2ZXJGaWxlTmFtZSkgKyAnLnRzJztcbiAgICBpZiAoQXJyYXkuaXNBcnJheShmaWxlc0FzdE5vZGUpICYmICFmaWxlc0FzdE5vZGUuc29tZSgoeyB0ZXh0IH0pID0+IHRleHQgPT09IHNlcnZlckZpbGVQYXRoKSkge1xuICAgICAgdHNDb25maWcubW9kaWZ5KFsnZmlsZXMnXSwgWy4uLmZpbGVzQXN0Tm9kZSwgc2VydmVyRmlsZVBhdGhdKTtcbiAgICB9XG4gIH07XG59XG5cbmZ1bmN0aW9uIHJvdXRpbmdJbml0aWFsTmF2aWdhdGlvblJ1bGUob3B0aW9uczogVW5pdmVyc2FsT3B0aW9ucyk6IFJ1bGUge1xuICByZXR1cm4gYXN5bmMgKGhvc3QpID0+IHtcbiAgICBjb25zdCBwcm9qZWN0ID0gYXdhaXQgZ2V0UHJvamVjdChob3N0LCBvcHRpb25zLnByb2plY3QpO1xuICAgIGNvbnN0IHNlcnZlclRhcmdldCA9IHByb2plY3QudGFyZ2V0cy5nZXQoJ3NlcnZlcicpO1xuICAgIGlmICghc2VydmVyVGFyZ2V0IHx8ICFzZXJ2ZXJUYXJnZXQub3B0aW9ucykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHRzQ29uZmlnUGF0aCA9IHNlcnZlclRhcmdldC5vcHRpb25zLnRzQ29uZmlnO1xuICAgIGlmICghdHNDb25maWdQYXRoIHx8IHR5cGVvZiB0c0NvbmZpZ1BhdGggIT09ICdzdHJpbmcnIHx8ICFob3N0LmV4aXN0cyh0c0NvbmZpZ1BhdGgpKSB7XG4gICAgICAvLyBObyB0c2NvbmZpZyBwYXRoXG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgcGFyc2VDb25maWdIb3N0OiB0cy5QYXJzZUNvbmZpZ0hvc3QgPSB7XG4gICAgICB1c2VDYXNlU2Vuc2l0aXZlRmlsZU5hbWVzOiB0cy5zeXMudXNlQ2FzZVNlbnNpdGl2ZUZpbGVOYW1lcyxcbiAgICAgIHJlYWREaXJlY3Rvcnk6IHRzLnN5cy5yZWFkRGlyZWN0b3J5LFxuICAgICAgZmlsZUV4aXN0czogZnVuY3Rpb24gKGZpbGVOYW1lOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIGhvc3QuZXhpc3RzKGZpbGVOYW1lKTtcbiAgICAgIH0sXG4gICAgICByZWFkRmlsZTogZnVuY3Rpb24gKGZpbGVOYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gaG9zdC5yZWFkKGZpbGVOYW1lKS50b1N0cmluZygpO1xuICAgICAgfSxcbiAgICB9O1xuICAgIGNvbnN0IHsgY29uZmlnIH0gPSB0cy5yZWFkQ29uZmlnRmlsZSh0c0NvbmZpZ1BhdGgsIHBhcnNlQ29uZmlnSG9zdC5yZWFkRmlsZSk7XG4gICAgY29uc3QgcGFyc2VkID0gdHMucGFyc2VKc29uQ29uZmlnRmlsZUNvbnRlbnQoXG4gICAgICBjb25maWcsXG4gICAgICBwYXJzZUNvbmZpZ0hvc3QsXG4gICAgICBkaXJuYW1lKG5vcm1hbGl6ZSh0c0NvbmZpZ1BhdGgpKSxcbiAgICApO1xuICAgIGNvbnN0IHRzSG9zdCA9IHRzLmNyZWF0ZUNvbXBpbGVySG9zdChwYXJzZWQub3B0aW9ucywgdHJ1ZSk7XG4gICAgLy8gU3RyaXAgQk9NIGFzIG90aGVyd2lzZSBUU0MgbWV0aG9kcyAoRXg6IGdldFdpZHRoKSB3aWxsIHJldHVybiBhbiBvZmZzZXQsXG4gICAgLy8gd2hpY2ggYnJlYWtzIHRoZSBDTEkgVXBkYXRlUmVjb3JkZXIuXG4gICAgLy8gU2VlOiBodHRwczovL2dpdGh1Yi5jb20vYW5ndWxhci9hbmd1bGFyL3B1bGwvMzA3MTlcbiAgICB0c0hvc3QucmVhZEZpbGUgPSBmdW5jdGlvbiAoZmlsZU5hbWU6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgICByZXR1cm4gaG9zdFxuICAgICAgICAucmVhZChmaWxlTmFtZSlcbiAgICAgICAgLnRvU3RyaW5nKClcbiAgICAgICAgLnJlcGxhY2UoL15cXHVGRUZGLywgJycpO1xuICAgIH07XG4gICAgdHNIb3N0LmRpcmVjdG9yeUV4aXN0cyA9IGZ1bmN0aW9uIChkaXJlY3RvcnlOYW1lOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICAgIC8vIFdoZW4gdGhlIHBhdGggaXMgZmlsZSBnZXREaXIgd2lsbCB0aHJvdy5cbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGRpciA9IGhvc3QuZ2V0RGlyKGRpcmVjdG9yeU5hbWUpO1xuXG4gICAgICAgIHJldHVybiAhIShkaXIuc3ViZGlycy5sZW5ndGggfHwgZGlyLnN1YmZpbGVzLmxlbmd0aCk7XG4gICAgICB9IGNhdGNoIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgIH07XG4gICAgdHNIb3N0LmZpbGVFeGlzdHMgPSBmdW5jdGlvbiAoZmlsZU5hbWU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgICAgcmV0dXJuIGhvc3QuZXhpc3RzKGZpbGVOYW1lKTtcbiAgICB9O1xuICAgIHRzSG9zdC5yZWFscGF0aCA9IGZ1bmN0aW9uIChwYXRoOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgICAgcmV0dXJuIHBhdGg7XG4gICAgfTtcbiAgICB0c0hvc3QuZ2V0Q3VycmVudERpcmVjdG9yeSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiBob3N0LnJvb3QucGF0aDtcbiAgICB9O1xuXG4gICAgY29uc3QgcHJvZ3JhbSA9IHRzLmNyZWF0ZVByb2dyYW0ocGFyc2VkLmZpbGVOYW1lcywgcGFyc2VkLm9wdGlvbnMsIHRzSG9zdCk7XG4gICAgY29uc3QgdHlwZUNoZWNrZXIgPSBwcm9ncmFtLmdldFR5cGVDaGVja2VyKCk7XG4gICAgY29uc3Qgc291cmNlRmlsZXMgPSBwcm9ncmFtXG4gICAgICAuZ2V0U291cmNlRmlsZXMoKVxuICAgICAgLmZpbHRlcigoZikgPT4gIWYuaXNEZWNsYXJhdGlvbkZpbGUgJiYgIXByb2dyYW0uaXNTb3VyY2VGaWxlRnJvbUV4dGVybmFsTGlicmFyeShmKSk7XG4gICAgY29uc3QgcHJpbnRlciA9IHRzLmNyZWF0ZVByaW50ZXIoKTtcbiAgICBjb25zdCByb3V0ZXJNb2R1bGUgPSAnUm91dGVyTW9kdWxlJztcbiAgICBjb25zdCByb3V0ZXJTb3VyY2UgPSAnQGFuZ3VsYXIvcm91dGVyJztcblxuICAgIHNvdXJjZUZpbGVzLmZvckVhY2goKHNvdXJjZUZpbGUpID0+IHtcbiAgICAgIGNvbnN0IHJvdXRlckltcG9ydCA9IGZpbmRJbXBvcnQoc291cmNlRmlsZSwgcm91dGVyU291cmNlLCByb3V0ZXJNb2R1bGUpO1xuICAgICAgaWYgKCFyb3V0ZXJJbXBvcnQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBsZXQgcm91dGVyTW9kdWxlTm9kZTogdHMuQ2FsbEV4cHJlc3Npb247XG4gICAgICB0cy5mb3JFYWNoQ2hpbGQoc291cmNlRmlsZSwgZnVuY3Rpb24gdmlzaXROb2RlKG5vZGU6IHRzLk5vZGUpIHtcbiAgICAgICAgaWYgKFxuICAgICAgICAgIHRzLmlzQ2FsbEV4cHJlc3Npb24obm9kZSkgJiZcbiAgICAgICAgICB0cy5pc1Byb3BlcnR5QWNjZXNzRXhwcmVzc2lvbihub2RlLmV4cHJlc3Npb24pICYmXG4gICAgICAgICAgdHMuaXNJZGVudGlmaWVyKG5vZGUuZXhwcmVzc2lvbi5leHByZXNzaW9uKSAmJlxuICAgICAgICAgIG5vZGUuZXhwcmVzc2lvbi5uYW1lLnRleHQgPT09ICdmb3JSb290J1xuICAgICAgICApIHtcbiAgICAgICAgICBjb25zdCBpbXAgPSBnZXRJbXBvcnRPZklkZW50aWZpZXIodHlwZUNoZWNrZXIsIG5vZGUuZXhwcmVzc2lvbi5leHByZXNzaW9uKTtcblxuICAgICAgICAgIGlmIChpbXAgJiYgaW1wLm5hbWUgPT09IHJvdXRlck1vZHVsZSAmJiBpbXAuaW1wb3J0TW9kdWxlID09PSByb3V0ZXJTb3VyY2UpIHtcbiAgICAgICAgICAgIHJvdXRlck1vZHVsZU5vZGUgPSBub2RlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHRzLmZvckVhY2hDaGlsZChub2RlLCB2aXNpdE5vZGUpO1xuICAgICAgfSk7XG5cbiAgICAgIGlmIChyb3V0ZXJNb2R1bGVOb2RlKSB7XG4gICAgICAgIGNvbnN0IHByaW50ID0gcHJpbnRlci5wcmludE5vZGUoXG4gICAgICAgICAgdHMuRW1pdEhpbnQuVW5zcGVjaWZpZWQsXG4gICAgICAgICAgYWRkSW5pdGlhbE5hdmlnYXRpb24ocm91dGVyTW9kdWxlTm9kZSksXG4gICAgICAgICAgc291cmNlRmlsZSxcbiAgICAgICAgKTtcblxuICAgICAgICBjb25zdCByZWNvcmRlciA9IGhvc3QuYmVnaW5VcGRhdGUoc291cmNlRmlsZS5maWxlTmFtZSk7XG4gICAgICAgIHJlY29yZGVyLnJlbW92ZShyb3V0ZXJNb2R1bGVOb2RlLmdldFN0YXJ0KCksIHJvdXRlck1vZHVsZU5vZGUuZ2V0V2lkdGgoKSk7XG4gICAgICAgIHJlY29yZGVyLmluc2VydFJpZ2h0KHJvdXRlck1vZHVsZU5vZGUuZ2V0U3RhcnQoKSwgcHJpbnQpO1xuICAgICAgICBob3N0LmNvbW1pdFVwZGF0ZShyZWNvcmRlcik7XG4gICAgICB9XG4gICAgfSk7XG4gIH07XG59XG5cbmZ1bmN0aW9uIGFkZERlcGVuZGVuY2llcygpOiBSdWxlIHtcbiAgcmV0dXJuIChfaG9zdDogVHJlZSkgPT4ge1xuICAgIHJldHVybiBjaGFpbihbXG4gICAgICBhZGREZXBlbmRlbmN5KCdAbmd1bml2ZXJzYWwvYnVpbGRlcnMnLCAnXjAuMC4wLVBMQUNFSE9MREVSJywge1xuICAgICAgICB0eXBlOiBEZXBlbmRlbmN5VHlwZS5EZXYsXG4gICAgICB9KSxcbiAgICAgIGFkZERlcGVuZGVuY3koJ0BuZ3VuaXZlcnNhbC9leHByZXNzLWVuZ2luZScsICdeMC4wLjAtUExBQ0VIT0xERVInLCB7XG4gICAgICAgIHR5cGU6IERlcGVuZGVuY3lUeXBlLkRlZmF1bHQsXG4gICAgICB9KSxcbiAgICAgIGFkZERlcGVuZGVuY3koJ2V4cHJlc3MnLCAnRVhQUkVTU19WRVJTSU9OJywge1xuICAgICAgICB0eXBlOiBEZXBlbmRlbmN5VHlwZS5EZWZhdWx0LFxuICAgICAgfSksXG4gICAgICBhZGREZXBlbmRlbmN5KCdAdHlwZXMvZXhwcmVzcycsICdFWFBSRVNTX1RZUEVTX1ZFUlNJT04nLCB7XG4gICAgICAgIHR5cGU6IERlcGVuZGVuY3lUeXBlLkRldixcbiAgICAgIH0pLFxuICAgIF0pO1xuICB9O1xufVxuXG5mdW5jdGlvbiBhZGRTZXJ2ZXJGaWxlKG9wdGlvbnM6IFVuaXZlcnNhbE9wdGlvbnMsIGlzU3RhbmRhbG9uZTogYm9vbGVhbik6IFJ1bGUge1xuICByZXR1cm4gYXN5bmMgKGhvc3QpID0+IHtcbiAgICBjb25zdCBwcm9qZWN0ID0gYXdhaXQgZ2V0UHJvamVjdChob3N0LCBvcHRpb25zLnByb2plY3QpO1xuICAgIGNvbnN0IGJyb3dzZXJEaXN0RGlyZWN0b3J5ID0gYXdhaXQgZ2V0T3V0cHV0UGF0aChob3N0LCBvcHRpb25zLnByb2plY3QsICdidWlsZCcpO1xuXG4gICAgcmV0dXJuIG1lcmdlV2l0aChcbiAgICAgIGFwcGx5KHVybCgnLi9maWxlcycpLCBbXG4gICAgICAgIHRlbXBsYXRlKHtcbiAgICAgICAgICAuLi5zdHJpbmdzLFxuICAgICAgICAgIC4uLm9wdGlvbnMsXG4gICAgICAgICAgc3RyaXBUc0V4dGVuc2lvbixcbiAgICAgICAgICBicm93c2VyRGlzdERpcmVjdG9yeSxcbiAgICAgICAgICBpc1N0YW5kYWxvbmUsXG4gICAgICAgIH0pLFxuICAgICAgICBtb3ZlKHByb2plY3Qucm9vdCksXG4gICAgICBdKSxcbiAgICApO1xuICB9O1xufVxuXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiAob3B0aW9uczogQWRkVW5pdmVyc2FsT3B0aW9ucyk6IFJ1bGUge1xuICByZXR1cm4gYXN5bmMgKGhvc3QpID0+IHtcbiAgICBjb25zdCBwcm9qZWN0ID0gYXdhaXQgZ2V0UHJvamVjdChob3N0LCBvcHRpb25zLnByb2plY3QpO1xuICAgIGNvbnN0IHVuaXZlcnNhbE9wdGlvbnMgPSB7XG4gICAgICAuLi5vcHRpb25zLFxuICAgICAgc2tpcEluc3RhbGw6IHRydWUsXG4gICAgfTtcbiAgICBjb25zdCBjbGllbnRCdWlsZFRhcmdldCA9IHByb2plY3QudGFyZ2V0cy5nZXQoJ2J1aWxkJyk7XG4gICAgaWYgKCFjbGllbnRCdWlsZFRhcmdldCkge1xuICAgICAgdGhyb3cgdGFyZ2V0QnVpbGROb3RGb3VuZEVycm9yKCk7XG4gICAgfVxuXG4gICAgY29uc3QgY2xpZW50QnVpbGRPcHRpb25zID0gKGNsaWVudEJ1aWxkVGFyZ2V0Lm9wdGlvbnMgfHxcbiAgICAgIHt9KSBhcyB1bmtub3duIGFzIEJyb3dzZXJCdWlsZGVyT3B0aW9ucztcblxuICAgIGNvbnN0IGlzU3RhbmRhbG9uZSA9IGlzU3RhbmRhbG9uZUFwcChob3N0LCBjbGllbnRCdWlsZE9wdGlvbnMubWFpbik7XG5cbiAgICBkZWxldGUgdW5pdmVyc2FsT3B0aW9ucy5zZXJ2ZXJGaWxlTmFtZTtcbiAgICBkZWxldGUgdW5pdmVyc2FsT3B0aW9ucy5zZXJ2ZXJQb3J0O1xuXG4gICAgcmV0dXJuIGNoYWluKFtcbiAgICAgIHByb2plY3QudGFyZ2V0cy5oYXMoJ3NlcnZlcicpXG4gICAgICAgID8gbm9vcCgpXG4gICAgICAgIDogZXh0ZXJuYWxTY2hlbWF0aWMoJ0BzY2hlbWF0aWNzL2FuZ3VsYXInLCAndW5pdmVyc2FsJywgdW5pdmVyc2FsT3B0aW9ucyksXG4gICAgICBhZGRTY3JpcHRzUnVsZShvcHRpb25zKSxcbiAgICAgIHVwZGF0ZVNlcnZlclRzQ29uZmlnUnVsZShvcHRpb25zKSxcbiAgICAgIHVwZGF0ZVdvcmtzcGFjZUNvbmZpZ1J1bGUob3B0aW9ucyksXG4gICAgICBpc1N0YW5kYWxvbmUgPyBub29wKCkgOiByb3V0aW5nSW5pdGlhbE5hdmlnYXRpb25SdWxlKG9wdGlvbnMpLFxuICAgICAgYWRkU2VydmVyRmlsZShvcHRpb25zLCBpc1N0YW5kYWxvbmUpLFxuICAgICAgYWRkRGVwZW5kZW5jaWVzKCksXG4gICAgXSk7XG4gIH07XG59XG4iXX0=
\No newline at end of file