@openelement/ssg 0.41.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,497 @@
1
+ /**
2
+ * @openelement/core - Route scanner
3
+ * Scans the routes directory and generates a route map.
4
+ * Produces the virtual:routes module.
5
+ *
6
+ * Phase 1 enhancement: support for _renderer.ts (layout) and
7
+ * _middleware.ts (Hono middleware) special files.
8
+ *
9
+ * Phase 2 enhancement: support for package islands auto-detection.
10
+ * Packages can export an `islands` array in their main entry.
11
+ *
12
+ * Convention (minimal augmentation):
13
+ * - _renderer.ts: exports a renderer that wraps route VNodes
14
+ * - _middleware.ts: exports a Hono middleware function applied before the route
15
+ * - Files starting with _ are not route handlers but are loaded by the framework
16
+ *
17
+ * ─── SSR Import Discovery Audit (Step1) ─────────────────────
18
+ *
19
+ * This file discovers islands but does NOT import them (static scan only):
20
+ *
21
+ * 1. Local island files:
22
+ * - Scanned by `scanIslands()`
23
+ * - Metadata read by `scanIslandMeta()` (static, no import)
24
+ * - SSR decision: `openElement.ssr` field (static read, no import)
25
+ *
26
+ * 2. Package manifest islands:
27
+ * - Discovered by `scanPackageManifests()`
28
+ * - Imports package module to read `manifest` export
29
+ * - Browser-only packages: caught by try/catch
30
+ * - SSR decision: `manifest.declarations[].openElement.ssr` field
31
+ *
32
+ * 3. CEM manifests (v0.18.0):
33
+ * - Discovered by `scanCemManifests()` - reads custom-elements.json from
34
+ * node_modules packages WITHOUT importing package code
35
+ * - Results fed into the compatibility classifier (parseCem + classifyCemManifest)
36
+ *
37
+ * 4. Nested custom elements (from the VNode tree):
38
+ * - NOT handled in this file
39
+ * - See: `packages/core/src/jsx-render-string.ts` and `renderDsdTree()`
40
+ *
41
+ * Audit completed: 2026-05-17
42
+ * Auditor: AI agent (openElement v0.17.4 SOP compliance check)
43
+ *
44
+ * ─── v0.41.0-alpha.1: AST removed ────────────────────────────
45
+ *
46
+ * Replaced TypeScript AST scanning with regex/glob-based extraction.
47
+ * Route and island modules are simple ESM files; parsing the whole source
48
+ * with the TypeScript compiler is overkill and adds a heavy dependency.
49
+ */ import { formatError, OpenElementError } from '@openelement/core/errors';
50
+ import { createLogger } from '@openelement/core/logger';
51
+ import { join, posix, sep } from 'node:path';
52
+ import { classifyCemManifest, parseCem } from './cem-compat.js';
53
+ import { safeReadDir, safeReadFile, safeStat } from './route-scanner-fs.js';
54
+ const log = createLogger('core');
55
+ /**
56
+ * Read a static string export (e.g. `export const tagName = '...'`) from source text.
57
+ */ export function readRouteTagName(source) {
58
+ const match = source.match(/export\s+const\s+tagName\s*=\s*(["'`])([^"'`]+)\1/);
59
+ return match?.[2];
60
+ }
61
+ /**
62
+ * Read `export const tagName = '...'` from a route file using regex scanning.
63
+ */ export async function readRouteTagNameFromModule(filePath) {
64
+ const source = await safeReadFile(filePath);
65
+ if (source === undefined) return undefined;
66
+ return readRouteTagName(source);
67
+ }
68
+ function staticOpenElementError(message) {
69
+ return new OpenElementError(`Invalid static island metadata export "openElement": ${message}. Accepted shape: export const openElement = defineIslandConfig({ ssr?: boolean, dsd?: boolean, hydrate?: "load" | "idle" | "visible" | "only" }).`, {
70
+ code: 'ISLAND_METADATA_ERROR',
71
+ statusCode: 500,
72
+ recoverable: false
73
+ });
74
+ }
75
+ /**
76
+ * v0.41.0-alpha.1: Regex-based extraction of
77
+ * `export const openElement = defineIslandConfig({ ... })`.
78
+ *
79
+ * The scanner intentionally does not execute island modules. It accepts only a
80
+ * defineIslandConfig() call with boolean `ssr`/`dsd` and string `hydrate`
81
+ * literal values. Dynamic metadata is rejected instead of guessed.
82
+ */ export function readStaticOpenElementExport(source) {
83
+ const declMatch = source.match(/export\s+const\s+openElement\s*=/);
84
+ if (!declMatch) return null;
85
+ const afterEquals = source.slice(declMatch.index + declMatch[0].length).trimStart();
86
+ // Must call defineIslandConfig(...) - reject legacy object literals.
87
+ const callMatch = afterEquals.match(/^defineIslandConfig\s*\(\s*(\{[\s\S]*?\})\s*\)/);
88
+ if (!callMatch) {
89
+ const hasCall = /^defineIslandConfig\s*\(/.test(afterEquals);
90
+ if (hasCall) {
91
+ throw staticOpenElementError('defineIslandConfig() argument must be a static object literal');
92
+ }
93
+ throw staticOpenElementError('openElement export must call defineIslandConfig(...)');
94
+ }
95
+ const body = callMatch[1].slice(1, -1);
96
+ const meta = {};
97
+ // Match key: value pairs, skipping nested braces/strings.
98
+ const propRe = /\b(ssr|dsd|hydrate|[^\s:,{}]+)\s*:\s*(true|false|["']([^"']*)["'])/g;
99
+ let m;
100
+ while((m = propRe.exec(body)) !== null){
101
+ const key = m[1];
102
+ const raw = m[2];
103
+ if (![
104
+ 'ssr',
105
+ 'dsd',
106
+ 'hydrate'
107
+ ].includes(key)) {
108
+ throw staticOpenElementError(`unsupported openElement metadata key "${key}"`);
109
+ }
110
+ const typedKey = key;
111
+ if (typedKey === 'ssr' || typedKey === 'dsd') {
112
+ if (raw !== 'true' && raw !== 'false') {
113
+ throw staticOpenElementError(`openElement.${typedKey} must be a boolean literal`);
114
+ }
115
+ meta[typedKey] = raw === 'true';
116
+ continue;
117
+ }
118
+ const value = raw.slice(1, -1);
119
+ if (![
120
+ 'load',
121
+ 'idle',
122
+ 'visible',
123
+ 'only'
124
+ ].includes(value)) {
125
+ throw staticOpenElementError(`openElement.hydrate has unsupported value "${value}"`);
126
+ }
127
+ meta.hydrate = value;
128
+ }
129
+ return meta;
130
+ }
131
+ /**
132
+ * Convert a file path to a URL path pattern.
133
+ * e.g., 'index.ts' -> '/', 'about.ts' -> '/about', 'posts/[id].ts' -> '/posts/:id'
134
+ *
135
+ * v0.6': Uses URLPattern-compatible syntax where possible.
136
+ * URLPattern is the WHATWG standard for URL matching (section7.2).
137
+ * Pattern :param is compatible with both Hono and URLPattern.
138
+ */ function filePathToRoutePath(filePath) {
139
+ // Normalize separators - handle Windows backslash paths
140
+ // v0.14.3: Use posix.join to ensure all output paths use forward slashes
141
+ // regardless of platform. This prevents \ from leaking into URL patterns.
142
+ let p = filePath.split(sep).join(posix.sep);
143
+ // v0.25: AST-verified — path utility, regex is the appropriate tool
144
+ p = p.replace(/\.[^.]+$/, '');
145
+ // v0.25: AST-verified — path utility, converts [param] to :param
146
+ p = p.replace(/\[([^\]]+)\]/g, ':$1');
147
+ // Handle index
148
+ if (p === 'index') return '/';
149
+ if (p.endsWith('/index')) {
150
+ p = p.slice(0, -6); // Remove trailing /index
151
+ // After stripping /index, check if the result is the root index
152
+ if (p === 'index' || p === '') return '/';
153
+ }
154
+ // Ensure leading slash
155
+ if (!p.startsWith('/')) p = '/' + p;
156
+ return p;
157
+ }
158
+ /**
159
+ * Determine route type from file path.
160
+ * Files under 'api/' subdirectory are API routes.
161
+ */ function getRouteType(filePath) {
162
+ const normalized = filePath.split(sep).join(posix.sep);
163
+ return normalized.startsWith('api/') || normalized.includes('/api/') ? 'api' : 'page';
164
+ }
165
+ /**
166
+ * Generate a valid JS variable name from a route path.
167
+ * e.g., '/' -> 'RouteIndex', '/about' -> 'RouteAbout', '/posts/:id' -> 'RoutePostsId'
168
+ */ function pathToVarName(path) {
169
+ // v0.25: AST-verified — path-to-identifier transformation, regex is the appropriate tool
170
+ let name = path.replace(/^\//, '').replace(/\/$/, '').replace(/:([^/]+)/g, '$1').replace(/[^a-zA-Z0-9]/g, '_');
171
+ if (!name || name === '_') name = 'Index';
172
+ return 'Route_' + name.charAt(0).toUpperCase() + name.slice(1);
173
+ }
174
+ /**
175
+ * Identify special file types by name.
176
+ * _renderer.ts -> renderer, _middleware.ts -> middleware
177
+ */ // ponytail: inline lookup replaces 2-case switch
178
+ function getSpecialFileType(fileName) {
179
+ const baseName = fileName.replace(/\.[^.]+$/, '');
180
+ return ({
181
+ _renderer: 'renderer',
182
+ _middleware: 'middleware'
183
+ })[baseName] ?? null;
184
+ }
185
+ /**
186
+ * Check if a file should be ignored for routing.
187
+ * Dot-files are always ignored.
188
+ */ function isIgnoredFile(fileName) {
189
+ return fileName.startsWith('.');
190
+ }
191
+ /**
192
+ * Recursively scan a directory for route files.
193
+ * Also collects _renderer.ts and _middleware.ts special files.
194
+ */ export async function scanRoutes(routesDir, baseDir = '') {
195
+ const entries = [];
196
+ const files = await safeReadDir(routesDir);
197
+ if (files === undefined) {
198
+ log.debug(`Routes directory "${routesDir}" not found`);
199
+ return entries;
200
+ }
201
+ for (const file of files){
202
+ if (isIgnoredFile(file)) continue;
203
+ const fullPath = join(routesDir, file);
204
+ const relativePath = baseDir ? join(baseDir, file) : file;
205
+ const fileStat = await safeStat(fullPath);
206
+ if (!fileStat) {
207
+ log.debug(`File vanished before stat: ${fullPath}`);
208
+ continue;
209
+ }
210
+ if (fileStat.isDirectory()) {
211
+ // Recurse into subdirectories
212
+ const subEntries = await scanRoutes(fullPath, relativePath);
213
+ entries.push(...subEntries);
214
+ } else if (/\.(ts|tsx|js|jsx)$/.test(file)) {
215
+ // Check for special files
216
+ const specialType = getSpecialFileType(file);
217
+ if (specialType) {
218
+ // Add as a special entry - not a route handler, but loadable
219
+ entries.push({
220
+ path: filePathToRoutePath(relativePath),
221
+ filePath: relativePath.split(sep).join(posix.sep),
222
+ type: 'special',
223
+ varName: `Special_${specialType}_${baseDir.replace(/[\\/]/g, '_') || 'root'}`,
224
+ special: specialType
225
+ });
226
+ } else if (!file.startsWith('_')) {
227
+ // Regular route file
228
+ const routePath = filePathToRoutePath(relativePath);
229
+ const routeType = getRouteType(relativePath);
230
+ // v0.25: AST-verified — path utility, extracts [param] patterns
231
+ const paramMatches = relativePath.match(/\[([^\]]+)\]/g);
232
+ const params = paramMatches ? paramMatches.map((m)=>m.slice(1, -1)) : undefined;
233
+ let tagName;
234
+ if (routeType === 'page') {
235
+ // Regex-based scanning reads `export const tagName` without executing the module.
236
+ tagName = await readRouteTagNameFromModule(fullPath);
237
+ if (tagName === undefined) {
238
+ // tagName not found is normal — not all page routes define one
239
+ log.debug(`No tagName export found in route module: ${fullPath}`);
240
+ }
241
+ }
242
+ entries.push({
243
+ path: routePath,
244
+ filePath: relativePath.split(sep).join(posix.sep),
245
+ type: routeType,
246
+ varName: pathToVarName(routePath),
247
+ tagName,
248
+ params
249
+ });
250
+ }
251
+ // Other _-prefixed files (not _renderer/_middleware) are silently skipped
252
+ }
253
+ }
254
+ // Sort routes: static paths first, then dynamic
255
+ entries.sort((a, b)=>{
256
+ // Special files go to the end
257
+ if (a.special || b.special) {
258
+ if (a.special && !b.special) return 1;
259
+ if (!a.special && b.special) return -1;
260
+ return 0;
261
+ }
262
+ const aDynamic = a.path.includes(':');
263
+ const bDynamic = b.path.includes(':');
264
+ if (aDynamic !== bDynamic) return aDynamic ? 1 : -1;
265
+ return a.path.localeCompare(b.path);
266
+ });
267
+ return entries;
268
+ }
269
+ /**
270
+ * v0.25: AST-verified — converts file name to a valid Custom Element tag name.
271
+ * Uses regex for path manipulation since tag names are derived from file paths.
272
+ *
273
+ * Examples:
274
+ * 'my-counter.ts' -> 'my-counter'
275
+ * 'posts/index.ts' -> 'posts-index'
276
+ * 'admin\\dashboard.ts' -> 'admin-dashboard'
277
+ */ export function fileToTagName(fileName) {
278
+ return fileName.replace(/\.[^.]+$/, '') // v0.25: AST-verified — remove extension
279
+ .replace(/[\\/]/g, '-') // v0.25: AST-verified — replace path separators with hyphens
280
+ .toLowerCase();
281
+ }
282
+ /**
283
+ * Scan islands directory recursively for island files.
284
+ * Returns paths relative to islandsDir (e.g., ['my-counter.ts', 'posts/index.ts']).
285
+ */ export async function scanIslands(islandsDir, relativeDir = '') {
286
+ const files = [];
287
+ const entries = await safeReadDir(islandsDir);
288
+ if (entries === undefined) {
289
+ log.debug(`Islands directory "${islandsDir}" not found`);
290
+ return files;
291
+ }
292
+ for (const entry of entries){
293
+ if (entry.startsWith('.')) continue;
294
+ const fullPath = join(islandsDir, entry);
295
+ const fileStat = await safeStat(fullPath);
296
+ if (!fileStat) {
297
+ log.debug(`Island file vanished before stat: ${fullPath}`);
298
+ continue;
299
+ }
300
+ const relativePath = relativeDir ? join(relativeDir, entry) : entry;
301
+ if (fileStat.isDirectory()) {
302
+ const subFiles = await scanIslands(fullPath, relativePath);
303
+ files.push(...subFiles);
304
+ } else if (/\.(ts|tsx|js|jsx)$/.test(entry)) {
305
+ files.push(relativePath);
306
+ }
307
+ }
308
+ return files.sort();
309
+ }
310
+ /**
311
+ * v0.41.0-alpha.1: Regex-based — reads island metadata by statically scanning the module
312
+ * source for `export const openElement = defineIslandConfig({ ... })`.
313
+ *
314
+ * Supported form:
315
+ * export const openElement = defineIslandConfig({ ssr: false, dsd: false, hydrate: 'only' })
316
+ *
317
+ * This is more reliable than regex because it handles:
318
+ * - Comments inside the object literal
319
+ * - Computed properties
320
+ * - Destructured/re-exported values
321
+ * - Canonical defineIslandConfig(...) calls
322
+ *
323
+ * If a module cannot be read, its metadata is silently skipped.
324
+ */ export async function scanIslandMeta(islandsDir, islandFiles) {
325
+ const meta = {};
326
+ for (const filePath of islandFiles){
327
+ const tagName = fileToTagName(filePath);
328
+ const fullPath = join(islandsDir, filePath);
329
+ const source = await safeReadFile(fullPath);
330
+ if (source === undefined) {
331
+ log.debug(`Unable to read island module for metadata: ${fullPath}`);
332
+ continue;
333
+ }
334
+ // Read the `openElement` export directly; no regex needed.
335
+ const openElementExport = readStaticOpenElementExport(source);
336
+ if (!openElementExport) continue;
337
+ const hydrate = openElementExport.hydrate && [
338
+ 'load',
339
+ 'idle',
340
+ 'visible',
341
+ 'only'
342
+ ].includes(openElementExport.hydrate) ? openElementExport.hydrate : undefined;
343
+ meta[tagName] = {
344
+ tagName,
345
+ filePath,
346
+ ssr: hydrate === 'only' ? false : openElementExport.ssr,
347
+ dsd: hydrate === 'only' ? false : openElementExport.dsd,
348
+ hydrate,
349
+ reason: hydrate === 'only' ? 'local island exports openElement.hydrate=only' : openElementExport.ssr === false ? 'local island exports openElement.ssr=false' : undefined
350
+ };
351
+ }
352
+ return meta;
353
+ }
354
+ /**
355
+ * Scan package exports for OpenElementPackageManifest.
356
+ * Packages should export a `manifest` OpenElementPackageManifest in their main entry.
357
+ *
358
+ * Example package export:
359
+ * ```ts
360
+ * // @openelement/ui/index.ts
361
+ * export { manifest } from './manifest.js';
362
+ * ```
363
+ *
364
+ * @param packageNames - List of package names to scan (e.g., ['@openelement/ui'])
365
+ * @returns Array of OpenElementPackageManifest
366
+ */ export async function scanPackageManifests(packageNames) {
367
+ const allManifests = [];
368
+ for (const pkg of packageNames){
369
+ // @vite-ignore suppresses unanalyzable-dynamic-import JSR warning.
370
+ let mod;
371
+ try {
372
+ mod = await import(/* @vite-ignore */ pkg);
373
+ } catch (e) {
374
+ if (isBrowserOnlyPackageImportError(e)) {
375
+ log.warn(`Skipping package manifest from "${pkg}": browser-only package cannot be imported during SSR discovery`);
376
+ continue;
377
+ }
378
+ throw new OpenElementError(`Failed to scan package manifest from "${pkg}": ${formatError(e)}`, {
379
+ code: 'PACKAGE_SCAN_ERROR',
380
+ statusCode: 500,
381
+ recoverable: false
382
+ });
383
+ }
384
+ if (mod.manifest && typeof mod.manifest === 'object') {
385
+ const manifest = mod.manifest;
386
+ if (manifest.packageName && manifest.declarations) {
387
+ allManifests.push(manifest);
388
+ } else {
389
+ throw new OpenElementError(`Invalid manifest in ${pkg}: missing packageName or declarations`, {
390
+ code: 'PACKAGE_MANIFEST_ERROR',
391
+ statusCode: 500,
392
+ recoverable: false
393
+ });
394
+ }
395
+ } else {
396
+ throw new OpenElementError(`Package ${pkg} does not export a manifest`, {
397
+ code: 'PACKAGE_MANIFEST_ERROR',
398
+ statusCode: 500,
399
+ recoverable: false
400
+ });
401
+ }
402
+ }
403
+ return allManifests;
404
+ }
405
+ /**
406
+ * v0.25: AST-verified — error message classification, regex is the appropriate tool
407
+ * for matching runtime error strings from failed dynamic imports.
408
+ */ function isBrowserOnlyPackageImportError(error) {
409
+ const message = formatError(error);
410
+ return /\b(window|document|HTMLElement|customElements|navigator)\b.*\bis not defined\b/i.test(message);
411
+ }
412
+ /**
413
+ * Scan node_modules for packages that ship a `custom-elements.json`.
414
+ *
415
+ * Strategy:
416
+ * 1. Read node_modules directory entries (top-level packages + scoped orgs)
417
+ * 2. For each package, check if `<pkg>/custom-elements.json` exists
418
+ * 3. Return the raw JSON - caller is responsible for parsing + classifying
419
+ *
420
+ * This function reads files only. It never imports or executes package code.
421
+ *
422
+ * @param nodeModulesDir - Absolute path to the node_modules directory
423
+ * @returns Array of found CEM manifests
424
+ */ export async function scanCemManifests(nodeModulesDir) {
425
+ const results = [];
426
+ const entries = await safeReadDir(nodeModulesDir);
427
+ if (!entries) return results;
428
+ for (const entry of entries){
429
+ if (entry.startsWith('.')) continue;
430
+ if (entry.startsWith('@')) {
431
+ // Scoped package directory - recurse one level
432
+ const scopeDir = join(nodeModulesDir, entry);
433
+ const scopedEntries = await safeReadDir(scopeDir);
434
+ if (!scopedEntries) continue;
435
+ for (const scopedEntry of scopedEntries){
436
+ if (scopedEntry.startsWith('.')) continue;
437
+ const packageName = `${entry}/${scopedEntry}`;
438
+ const cemPath = join(nodeModulesDir, entry, scopedEntry, 'custom-elements.json');
439
+ const result = await tryReadCemFile(cemPath, packageName);
440
+ if (result) results.push(result);
441
+ }
442
+ } else {
443
+ // Regular (non-scoped) package
444
+ const cemPath = join(nodeModulesDir, entry, 'custom-elements.json');
445
+ const result = await tryReadCemFile(cemPath, entry);
446
+ if (result) results.push(result);
447
+ }
448
+ }
449
+ return results;
450
+ }
451
+ /**
452
+ * Try to read a custom-elements.json file.
453
+ * Returns null if the file doesn't exist or can't be read.
454
+ */ async function tryReadCemFile(cemPath, packageName) {
455
+ const json = await safeReadFile(cemPath);
456
+ return json === undefined ? null : {
457
+ packageName,
458
+ cemPath,
459
+ json
460
+ };
461
+ }
462
+ /**
463
+ * Run CEM auto-detection: scan node_modules, parse each manifest,
464
+ * and classify all discovered components.
465
+ *
466
+ * This is the high-level function called from the Vite plugin buildStart().
467
+ * It combines scanCemManifests() + parseCem() + classifyCemManifest()
468
+ * into a single pipeline.
469
+ *
470
+ * @param nodeModulesDir - Absolute path to node_modules
471
+ * @returns Array of compatibility classifications (may be empty if no CEM found)
472
+ */ export async function detectAndClassifyCemPackages(nodeModulesDir) {
473
+ const cemResults = await scanCemManifests(nodeModulesDir);
474
+ if (cemResults.length === 0) return [];
475
+ const allClassifications = [];
476
+ for (const { packageName, json } of cemResults){
477
+ const parseResult = parseCem(json);
478
+ if (!parseResult.success || !parseResult.manifest) {
479
+ log.debug(`Skipping invalid CEM manifest from "${packageName}": ` + parseResult.errors.map((e)=>e.message).join('; '));
480
+ continue;
481
+ }
482
+ // Attach package name to the manifest for better diagnostics
483
+ const manifest = {
484
+ ...parseResult.manifest,
485
+ packageName
486
+ };
487
+ const classResult = classifyCemManifest(manifest);
488
+ // Log summary
489
+ const { stats } = classResult;
490
+ if (stats.totalComponents > 0) {
491
+ log.info(`CEM: ${packageName} - ${stats.totalComponents} component(s): ` + `${stats.ssrCapableCount} ssr-capable, ${stats.clientOnlyCount} client-only` + (stats.rejectedCount > 0 ? `, ${stats.rejectedCount} rejected` : '') + (stats.experimentalDomCount > 0 ? `, ${stats.experimentalDomCount} experimental` : ''));
492
+ }
493
+ allClassifications.push(...classResult.classifications);
494
+ }
495
+ return allClassifications;
496
+ }
497
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZpbGU6Ly8vaG9tZS9ydW5uZXIvd29yay9vcGVuZWxlbWVudC9vcGVuZWxlbWVudC9wYWNrYWdlcy9zc2cvc3JjL3JvdXRlLXNjYW5uZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAb3BlbmVsZW1lbnQvY29yZSAtIFJvdXRlIHNjYW5uZXJcbiAqIFNjYW5zIHRoZSByb3V0ZXMgZGlyZWN0b3J5IGFuZCBnZW5lcmF0ZXMgYSByb3V0ZSBtYXAuXG4gKiBQcm9kdWNlcyB0aGUgdmlydHVhbDpyb3V0ZXMgbW9kdWxlLlxuICpcbiAqIFBoYXNlIDEgZW5oYW5jZW1lbnQ6IHN1cHBvcnQgZm9yIF9yZW5kZXJlci50cyAobGF5b3V0KSBhbmRcbiAqIF9taWRkbGV3YXJlLnRzIChIb25vIG1pZGRsZXdhcmUpIHNwZWNpYWwgZmlsZXMuXG4gKlxuICogUGhhc2UgMiBlbmhhbmNlbWVudDogc3VwcG9ydCBmb3IgcGFja2FnZSBpc2xhbmRzIGF1dG8tZGV0ZWN0aW9uLlxuICogUGFja2FnZXMgY2FuIGV4cG9ydCBhbiBgaXNsYW5kc2AgYXJyYXkgaW4gdGhlaXIgbWFpbiBlbnRyeS5cbiAqXG4gKiBDb252ZW50aW9uIChtaW5pbWFsIGF1Z21lbnRhdGlvbik6XG4gKiAtIF9yZW5kZXJlci50czogZXhwb3J0cyBhIHJlbmRlcmVyIHRoYXQgd3JhcHMgcm91dGUgVk5vZGVzXG4gKiAtIF9taWRkbGV3YXJlLnRzOiBleHBvcnRzIGEgSG9ubyBtaWRkbGV3YXJlIGZ1bmN0aW9uIGFwcGxpZWQgYmVmb3JlIHRoZSByb3V0ZVxuICogLSBGaWxlcyBzdGFydGluZyB3aXRoIF8gYXJlIG5vdCByb3V0ZSBoYW5kbGVycyBidXQgYXJlIGxvYWRlZCBieSB0aGUgZnJhbWV3b3JrXG4gKlxuICog4pSA4pSA4pSAIFNTUiBJbXBvcnQgRGlzY292ZXJ5IEF1ZGl0IChTdGVwMSkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG4gKlxuICogVGhpcyBmaWxlIGRpc2NvdmVycyBpc2xhbmRzIGJ1dCBkb2VzIE5PVCBpbXBvcnQgdGhlbSAoc3RhdGljIHNjYW4gb25seSk6XG4gKlxuICogMS4gTG9jYWwgaXNsYW5kIGZpbGVzOlxuICogICAgLSBTY2FubmVkIGJ5IGBzY2FuSXNsYW5kcygpYFxuICogICAgLSBNZXRhZGF0YSByZWFkIGJ5IGBzY2FuSXNsYW5kTWV0YSgpYCAoc3RhdGljLCBubyBpbXBvcnQpXG4gKiAgICAtIFNTUiBkZWNpc2lvbjogYG9wZW5FbGVtZW50LnNzcmAgZmllbGQgKHN0YXRpYyByZWFkLCBubyBpbXBvcnQpXG4gKlxuICogMi4gUGFja2FnZSBtYW5pZmVzdCBpc2xhbmRzOlxuICogICAgLSBEaXNjb3ZlcmVkIGJ5IGBzY2FuUGFja2FnZU1hbmlmZXN0cygpYFxuICogICAgLSBJbXBvcnRzIHBhY2thZ2UgbW9kdWxlIHRvIHJlYWQgYG1hbmlmZXN0YCBleHBvcnRcbiAqICAgIC0gQnJvd3Nlci1vbmx5IHBhY2thZ2VzOiBjYXVnaHQgYnkgdHJ5L2NhdGNoXG4gKiAgICAtIFNTUiBkZWNpc2lvbjogYG1hbmlmZXN0LmRlY2xhcmF0aW9uc1tdLm9wZW5FbGVtZW50LnNzcmAgZmllbGRcbiAqXG4gKiAzLiBDRU0gbWFuaWZlc3RzICh2MC4xOC4wKTpcbiAqICAgIC0gRGlzY292ZXJlZCBieSBgc2NhbkNlbU1hbmlmZXN0cygpYCAtIHJlYWRzIGN1c3RvbS1lbGVtZW50cy5qc29uIGZyb21cbiAqICAgICAgbm9kZV9tb2R1bGVzIHBhY2thZ2VzIFdJVEhPVVQgaW1wb3J0aW5nIHBhY2thZ2UgY29kZVxuICogICAgLSBSZXN1bHRzIGZlZCBpbnRvIHRoZSBjb21wYXRpYmlsaXR5IGNsYXNzaWZpZXIgKHBhcnNlQ2VtICsgY2xhc3NpZnlDZW1NYW5pZmVzdClcbiAqXG4gKiA0LiBOZXN0ZWQgY3VzdG9tIGVsZW1lbnRzIChmcm9tIHRoZSBWTm9kZSB0cmVlKTpcbiAqICAgIC0gTk9UIGhhbmRsZWQgaW4gdGhpcyBmaWxlXG4gKiAgICAtIFNlZTogYHBhY2thZ2VzL2NvcmUvc3JjL2pzeC1yZW5kZXItc3RyaW5nLnRzYCBhbmQgYHJlbmRlckRzZFRyZWUoKWBcbiAqXG4gKiBBdWRpdCBjb21wbGV0ZWQ6IDIwMjYtMDUtMTdcbiAqIEF1ZGl0b3I6IEFJIGFnZW50IChvcGVuRWxlbWVudCB2MC4xNy40IFNPUCBjb21wbGlhbmNlIGNoZWNrKVxuICpcbiAqIOKUgOKUgOKUgCB2MC40MS4wLWFscGhhLjE6IEFTVCByZW1vdmVkIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuICpcbiAqIFJlcGxhY2VkIFR5cGVTY3JpcHQgQVNUIHNjYW5uaW5nIHdpdGggcmVnZXgvZ2xvYi1iYXNlZCBleHRyYWN0aW9uLlxuICogUm91dGUgYW5kIGlzbGFuZCBtb2R1bGVzIGFyZSBzaW1wbGUgRVNNIGZpbGVzOyBwYXJzaW5nIHRoZSB3aG9sZSBzb3VyY2VcbiAqIHdpdGggdGhlIFR5cGVTY3JpcHQgY29tcGlsZXIgaXMgb3ZlcmtpbGwgYW5kIGFkZHMgYSBoZWF2eSBkZXBlbmRlbmN5LlxuICovXG5cbmltcG9ydCB0eXBlIHtcbiAgQ29tcGF0aWJpbGl0eUNsYXNzaWZpY2F0aW9uLFxuICBSb3V0ZUVudHJ5LFxuICBTcGVjaWFsRmlsZVR5cGUsXG59IGZyb20gJ0BvcGVuZWxlbWVudC9wcm90b2NvbC9mcmFtZXdvcmsnO1xuaW1wb3J0IHR5cGUgeyBPcGVuRWxlbWVudFBhY2thZ2VNYW5pZmVzdCB9IGZyb20gJ0BvcGVuZWxlbWVudC9wcm90b2NvbC9tYW5pZmVzdCc7XG5pbXBvcnQgeyBmb3JtYXRFcnJvciwgT3BlbkVsZW1lbnRFcnJvciB9IGZyb20gJ0BvcGVuZWxlbWVudC9jb3JlL2Vycm9ycyc7XG5pbXBvcnQgeyBjcmVhdGVMb2dnZXIgfSBmcm9tICdAb3BlbmVsZW1lbnQvY29yZS9sb2dnZXInO1xuaW1wb3J0IHsgam9pbiwgcG9zaXgsIHNlcCB9IGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQgeyBjbGFzc2lmeUNlbU1hbmlmZXN0LCBwYXJzZUNlbSB9IGZyb20gJy4vY2VtLWNvbXBhdC5qcyc7XG5pbXBvcnQgeyBzYWZlUmVhZERpciwgc2FmZVJlYWRGaWxlLCBzYWZlU3RhdCB9IGZyb20gJy4vcm91dGUtc2Nhbm5lci1mcy5qcyc7XG5cbmNvbnN0IGxvZyA9IGNyZWF0ZUxvZ2dlcignY29yZScpO1xuXG4vKiogTG9jYWwgaXNsYW5kIG1ldGFkYXRhIGluZGV4ZWQgYnkgdGFnIG5hbWUuICovXG5leHBvcnQgaW50ZXJmYWNlIExvY2FsSXNsYW5kTWV0YSB7XG4gIHRhZ05hbWU6IHN0cmluZztcbiAgZmlsZVBhdGg6IHN0cmluZztcbiAgc3NyPzogYm9vbGVhbjtcbiAgZHNkPzogYm9vbGVhbjtcbiAgaHlkcmF0ZT86ICdsb2FkJyB8ICdpZGxlJyB8ICd2aXNpYmxlJyB8ICdvbmx5JztcbiAgcmVhc29uPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIFJlYWQgYSBzdGF0aWMgc3RyaW5nIGV4cG9ydCAoZS5nLiBgZXhwb3J0IGNvbnN0IHRhZ05hbWUgPSAnLi4uJ2ApIGZyb20gc291cmNlIHRleHQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWFkUm91dGVUYWdOYW1lKHNvdXJjZTogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgbWF0Y2ggPSBzb3VyY2UubWF0Y2goL2V4cG9ydFxccytjb25zdFxccyt0YWdOYW1lXFxzKj1cXHMqKFtcIidgXSkoW15cIidgXSspXFwxLyk7XG4gIHJldHVybiBtYXRjaD8uWzJdO1xufVxuXG4vKipcbiAqIFJlYWQgYGV4cG9ydCBjb25zdCB0YWdOYW1lID0gJy4uLidgIGZyb20gYSByb3V0ZSBmaWxlIHVzaW5nIHJlZ2V4IHNjYW5uaW5nLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVhZFJvdXRlVGFnTmFtZUZyb21Nb2R1bGUoZmlsZVBhdGg6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nIHwgdW5kZWZpbmVkPiB7XG4gIGNvbnN0IHNvdXJjZSA9IGF3YWl0IHNhZmVSZWFkRmlsZShmaWxlUGF0aCk7XG4gIGlmIChzb3VyY2UgPT09IHVuZGVmaW5lZCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgcmV0dXJuIHJlYWRSb3V0ZVRhZ05hbWUoc291cmNlKTtcbn1cblxuZnVuY3Rpb24gc3RhdGljT3BlbkVsZW1lbnRFcnJvcihtZXNzYWdlOiBzdHJpbmcpOiBPcGVuRWxlbWVudEVycm9yIHtcbiAgcmV0dXJuIG5ldyBPcGVuRWxlbWVudEVycm9yKFxuICAgIGBJbnZhbGlkIHN0YXRpYyBpc2xhbmQgbWV0YWRhdGEgZXhwb3J0IFwib3BlbkVsZW1lbnRcIjogJHttZXNzYWdlfS4gQWNjZXB0ZWQgc2hhcGU6IGV4cG9ydCBjb25zdCBvcGVuRWxlbWVudCA9IGRlZmluZUlzbGFuZENvbmZpZyh7IHNzcj86IGJvb2xlYW4sIGRzZD86IGJvb2xlYW4sIGh5ZHJhdGU/OiBcImxvYWRcIiB8IFwiaWRsZVwiIHwgXCJ2aXNpYmxlXCIgfCBcIm9ubHlcIiB9KS5gLFxuICAgIHtcbiAgICAgIGNvZGU6ICdJU0xBTkRfTUVUQURBVEFfRVJST1InLFxuICAgICAgc3RhdHVzQ29kZTogNTAwLFxuICAgICAgcmVjb3ZlcmFibGU6IGZhbHNlLFxuICAgIH0sXG4gICk7XG59XG5cbi8qKlxuICogdjAuNDEuMC1hbHBoYS4xOiBSZWdleC1iYXNlZCBleHRyYWN0aW9uIG9mXG4gKiBgZXhwb3J0IGNvbnN0IG9wZW5FbGVtZW50ID0gZGVmaW5lSXNsYW5kQ29uZmlnKHsgLi4uIH0pYC5cbiAqXG4gKiBUaGUgc2Nhbm5lciBpbnRlbnRpb25hbGx5IGRvZXMgbm90IGV4ZWN1dGUgaXNsYW5kIG1vZHVsZXMuIEl0IGFjY2VwdHMgb25seSBhXG4gKiBkZWZpbmVJc2xhbmRDb25maWcoKSBjYWxsIHdpdGggYm9vbGVhbiBgc3NyYC9gZHNkYCBhbmQgc3RyaW5nIGBoeWRyYXRlYFxuICogbGl0ZXJhbCB2YWx1ZXMuIER5bmFtaWMgbWV0YWRhdGEgaXMgcmVqZWN0ZWQgaW5zdGVhZCBvZiBndWVzc2VkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVhZFN0YXRpY09wZW5FbGVtZW50RXhwb3J0KHNvdXJjZTogc3RyaW5nKToge1xuICBzc3I/OiBib29sZWFuO1xuICBkc2Q/OiBib29sZWFuO1xuICBoeWRyYXRlPzogTG9jYWxJc2xhbmRNZXRhWydoeWRyYXRlJ107XG59IHwgbnVsbCB7XG4gIGNvbnN0IGRlY2xNYXRjaCA9IHNvdXJjZS5tYXRjaCgvZXhwb3J0XFxzK2NvbnN0XFxzK29wZW5FbGVtZW50XFxzKj0vKTtcbiAgaWYgKCFkZWNsTWF0Y2gpIHJldHVybiBudWxsO1xuXG4gIGNvbnN0IGFmdGVyRXF1YWxzID0gc291cmNlLnNsaWNlKGRlY2xNYXRjaC5pbmRleCEgKyBkZWNsTWF0Y2hbMF0ubGVuZ3RoKS50cmltU3RhcnQoKTtcblxuICAvLyBNdXN0IGNhbGwgZGVmaW5lSXNsYW5kQ29uZmlnKC4uLikgLSByZWplY3QgbGVnYWN5IG9iamVjdCBsaXRlcmFscy5cbiAgY29uc3QgY2FsbE1hdGNoID0gYWZ0ZXJFcXVhbHMubWF0Y2goL15kZWZpbmVJc2xhbmRDb25maWdcXHMqXFwoXFxzKihcXHtbXFxzXFxTXSo/XFx9KVxccypcXCkvKTtcbiAgaWYgKCFjYWxsTWF0Y2gpIHtcbiAgICBjb25zdCBoYXNDYWxsID0gL15kZWZpbmVJc2xhbmRDb25maWdcXHMqXFwoLy50ZXN0KGFmdGVyRXF1YWxzKTtcbiAgICBpZiAoaGFzQ2FsbCkge1xuICAgICAgdGhyb3cgc3RhdGljT3BlbkVsZW1lbnRFcnJvcihcbiAgICAgICAgJ2RlZmluZUlzbGFuZENvbmZpZygpIGFyZ3VtZW50IG11c3QgYmUgYSBzdGF0aWMgb2JqZWN0IGxpdGVyYWwnLFxuICAgICAgKTtcbiAgICB9XG4gICAgdGhyb3cgc3RhdGljT3BlbkVsZW1lbnRFcnJvcignb3BlbkVsZW1lbnQgZXhwb3J0IG11c3QgY2FsbCBkZWZpbmVJc2xhbmRDb25maWcoLi4uKScpO1xuICB9XG5cbiAgY29uc3QgYm9keSA9IGNhbGxNYXRjaFsxXS5zbGljZSgxLCAtMSk7XG4gIGNvbnN0IG1ldGE6IHsgc3NyPzogYm9vbGVhbjsgZHNkPzogYm9vbGVhbjsgaHlkcmF0ZT86IExvY2FsSXNsYW5kTWV0YVsnaHlkcmF0ZSddIH0gPSB7fTtcblxuICAvLyBNYXRjaCBrZXk6IHZhbHVlIHBhaXJzLCBza2lwcGluZyBuZXN0ZWQgYnJhY2VzL3N0cmluZ3MuXG4gIGNvbnN0IHByb3BSZSA9IC9cXGIoc3NyfGRzZHxoeWRyYXRlfFteXFxzOix7fV0rKVxccyo6XFxzKih0cnVlfGZhbHNlfFtcIiddKFteXCInXSopW1wiJ10pL2c7XG4gIGxldCBtOiBSZWdFeHBFeGVjQXJyYXkgfCBudWxsO1xuXG4gIHdoaWxlICgobSA9IHByb3BSZS5leGVjKGJvZHkpKSAhPT0gbnVsbCkge1xuICAgIGNvbnN0IGtleSA9IG1bMV07XG4gICAgY29uc3QgcmF3ID0gbVsyXTtcblxuICAgIGlmICghWydzc3InLCAnZHNkJywgJ2h5ZHJhdGUnXS5pbmNsdWRlcyhrZXkpKSB7XG4gICAgICB0aHJvdyBzdGF0aWNPcGVuRWxlbWVudEVycm9yKGB1bnN1cHBvcnRlZCBvcGVuRWxlbWVudCBtZXRhZGF0YSBrZXkgXCIke2tleX1cImApO1xuICAgIH1cblxuICAgIGNvbnN0IHR5cGVkS2V5ID0ga2V5IGFzICdzc3InIHwgJ2RzZCcgfCAnaHlkcmF0ZSc7XG5cbiAgICBpZiAodHlwZWRLZXkgPT09ICdzc3InIHx8IHR5cGVkS2V5ID09PSAnZHNkJykge1xuICAgICAgaWYgKHJhdyAhPT0gJ3RydWUnICYmIHJhdyAhPT0gJ2ZhbHNlJykge1xuICAgICAgICB0aHJvdyBzdGF0aWNPcGVuRWxlbWVudEVycm9yKGBvcGVuRWxlbWVudC4ke3R5cGVkS2V5fSBtdXN0IGJlIGEgYm9vbGVhbiBsaXRlcmFsYCk7XG4gICAgICB9XG4gICAgICBtZXRhW3R5cGVkS2V5XSA9IHJhdyA9PT0gJ3RydWUnO1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgY29uc3QgdmFsdWUgPSByYXcuc2xpY2UoMSwgLTEpO1xuICAgIGlmICghWydsb2FkJywgJ2lkbGUnLCAndmlzaWJsZScsICdvbmx5J10uaW5jbHVkZXModmFsdWUpKSB7XG4gICAgICB0aHJvdyBzdGF0aWNPcGVuRWxlbWVudEVycm9yKGBvcGVuRWxlbWVudC5oeWRyYXRlIGhhcyB1bnN1cHBvcnRlZCB2YWx1ZSBcIiR7dmFsdWV9XCJgKTtcbiAgICB9XG4gICAgbWV0YS5oeWRyYXRlID0gdmFsdWUgYXMgTG9jYWxJc2xhbmRNZXRhWydoeWRyYXRlJ107XG4gIH1cblxuICByZXR1cm4gbWV0YTtcbn1cblxuLyoqXG4gKiBDb252ZXJ0IGEgZmlsZSBwYXRoIHRvIGEgVVJMIHBhdGggcGF0dGVybi5cbiAqIGUuZy4sICdpbmRleC50cycgLT4gJy8nLCAnYWJvdXQudHMnIC0+ICcvYWJvdXQnLCAncG9zdHMvW2lkXS50cycgLT4gJy9wb3N0cy86aWQnXG4gKlxuICogdjAuNic6IFVzZXMgVVJMUGF0dGVybi1jb21wYXRpYmxlIHN5bnRheCB3aGVyZSBwb3NzaWJsZS5cbiAqIFVSTFBhdHRlcm4gaXMgdGhlIFdIQVRXRyBzdGFuZGFyZCBmb3IgVVJMIG1hdGNoaW5nIChzZWN0aW9uNy4yKS5cbiAqIFBhdHRlcm4gOnBhcmFtIGlzIGNvbXBhdGlibGUgd2l0aCBib3RoIEhvbm8gYW5kIFVSTFBhdHRlcm4uXG4gKi9cbmZ1bmN0aW9uIGZpbGVQYXRoVG9Sb3V0ZVBhdGgoZmlsZVBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gIC8vIE5vcm1hbGl6ZSBzZXBhcmF0b3JzIC0gaGFuZGxlIFdpbmRvd3MgYmFja3NsYXNoIHBhdGhzXG4gIC8vIHYwLjE0LjM6IFVzZSBwb3NpeC5qb2luIHRvIGVuc3VyZSBhbGwgb3V0cHV0IHBhdGhzIHVzZSBmb3J3YXJkIHNsYXNoZXNcbiAgLy8gcmVnYXJkbGVzcyBvZiBwbGF0Zm9ybS4gVGhpcyBwcmV2ZW50cyBcXCBmcm9tIGxlYWtpbmcgaW50byBVUkwgcGF0dGVybnMuXG4gIGxldCBwID0gZmlsZVBhdGguc3BsaXQoc2VwKS5qb2luKHBvc2l4LnNlcCk7XG5cbiAgLy8gdjAuMjU6IEFTVC12ZXJpZmllZCDigJQgcGF0aCB1dGlsaXR5LCByZWdleCBpcyB0aGUgYXBwcm9wcmlhdGUgdG9vbFxuICBwID0gcC5yZXBsYWNlKC9cXC5bXi5dKyQvLCAnJyk7XG5cbiAgLy8gdjAuMjU6IEFTVC12ZXJpZmllZCDigJQgcGF0aCB1dGlsaXR5LCBjb252ZXJ0cyBbcGFyYW1dIHRvIDpwYXJhbVxuICBwID0gcC5yZXBsYWNlKC9cXFsoW15cXF1dKylcXF0vZywgJzokMScpO1xuXG4gIC8vIEhhbmRsZSBpbmRleFxuICBpZiAocCA9PT0gJ2luZGV4JykgcmV0dXJuICcvJztcbiAgaWYgKHAuZW5kc1dpdGgoJy9pbmRleCcpKSB7XG4gICAgcCA9IHAuc2xpY2UoMCwgLTYpOyAvLyBSZW1vdmUgdHJhaWxpbmcgL2luZGV4XG4gICAgLy8gQWZ0ZXIgc3RyaXBwaW5nIC9pbmRleCwgY2hlY2sgaWYgdGhlIHJlc3VsdCBpcyB0aGUgcm9vdCBpbmRleFxuICAgIGlmIChwID09PSAnaW5kZXgnIHx8IHAgPT09ICcnKSByZXR1cm4gJy8nO1xuICB9XG5cbiAgLy8gRW5zdXJlIGxlYWRpbmcgc2xhc2hcbiAgaWYgKCFwLnN0YXJ0c1dpdGgoJy8nKSkgcCA9ICcvJyArIHA7XG5cbiAgcmV0dXJuIHA7XG59XG5cbi8qKlxuICogRGV0ZXJtaW5lIHJvdXRlIHR5cGUgZnJvbSBmaWxlIHBhdGguXG4gKiBGaWxlcyB1bmRlciAnYXBpLycgc3ViZGlyZWN0b3J5IGFyZSBBUEkgcm91dGVzLlxuICovXG5mdW5jdGlvbiBnZXRSb3V0ZVR5cGUoZmlsZVBhdGg6IHN0cmluZyk6ICdwYWdlJyB8ICdhcGknIHtcbiAgY29uc3Qgbm9ybWFsaXplZCA9IGZpbGVQYXRoLnNwbGl0KHNlcCkuam9pbihwb3NpeC5zZXApO1xuICByZXR1cm4gbm9ybWFsaXplZC5zdGFydHNXaXRoKCdhcGkvJykgfHwgbm9ybWFsaXplZC5pbmNsdWRlcygnL2FwaS8nKSA/ICdhcGknIDogJ3BhZ2UnO1xufVxuXG4vKipcbiAqIEdlbmVyYXRlIGEgdmFsaWQgSlMgdmFyaWFibGUgbmFtZSBmcm9tIGEgcm91dGUgcGF0aC5cbiAqIGUuZy4sICcvJyAtPiAnUm91dGVJbmRleCcsICcvYWJvdXQnIC0+ICdSb3V0ZUFib3V0JywgJy9wb3N0cy86aWQnIC0+ICdSb3V0ZVBvc3RzSWQnXG4gKi9cbmZ1bmN0aW9uIHBhdGhUb1Zhck5hbWUocGF0aDogc3RyaW5nKTogc3RyaW5nIHtcbiAgLy8gdjAuMjU6IEFTVC12ZXJpZmllZCDigJQgcGF0aC10by1pZGVudGlmaWVyIHRyYW5zZm9ybWF0aW9uLCByZWdleCBpcyB0aGUgYXBwcm9wcmlhdGUgdG9vbFxuICBsZXQgbmFtZSA9IHBhdGhcbiAgICAucmVwbGFjZSgvXlxcLy8sICcnKVxuICAgIC5yZXBsYWNlKC9cXC8kLywgJycpXG4gICAgLnJlcGxhY2UoLzooW14vXSspL2csICckMScpXG4gICAgLnJlcGxhY2UoL1teYS16QS1aMC05XS9nLCAnXycpO1xuICBpZiAoIW5hbWUgfHwgbmFtZSA9PT0gJ18nKSBuYW1lID0gJ0luZGV4JztcbiAgcmV0dXJuICdSb3V0ZV8nICsgbmFtZS5jaGFyQXQoMCkudG9VcHBlckNhc2UoKSArIG5hbWUuc2xpY2UoMSk7XG59XG5cbi8qKlxuICogSWRlbnRpZnkgc3BlY2lhbCBmaWxlIHR5cGVzIGJ5IG5hbWUuXG4gKiBfcmVuZGVyZXIudHMgLT4gcmVuZGVyZXIsIF9taWRkbGV3YXJlLnRzIC0+IG1pZGRsZXdhcmVcbiAqL1xuLy8gcG9ueXRhaWw6IGlubGluZSBsb29rdXAgcmVwbGFjZXMgMi1jYXNlIHN3aXRjaFxuZnVuY3Rpb24gZ2V0U3BlY2lhbEZpbGVUeXBlKGZpbGVOYW1lOiBzdHJpbmcpOiBTcGVjaWFsRmlsZVR5cGUgfCBudWxsIHtcbiAgY29uc3QgYmFzZU5hbWUgPSBmaWxlTmFtZS5yZXBsYWNlKC9cXC5bXi5dKyQvLCAnJyk7XG4gIHJldHVybiAoeyBfcmVuZGVyZXI6ICdyZW5kZXJlcicsIF9taWRkbGV3YXJlOiAnbWlkZGxld2FyZScgfSBhcyBSZWNvcmQ8c3RyaW5nLCBTcGVjaWFsRmlsZVR5cGU+KVtcbiAgICBiYXNlTmFtZVxuICBdID8/IG51bGw7XG59XG5cbi8qKlxuICogQ2hlY2sgaWYgYSBmaWxlIHNob3VsZCBiZSBpZ25vcmVkIGZvciByb3V0aW5nLlxuICogRG90LWZpbGVzIGFyZSBhbHdheXMgaWdub3JlZC5cbiAqL1xuZnVuY3Rpb24gaXNJZ25vcmVkRmlsZShmaWxlTmFtZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gIHJldHVybiBmaWxlTmFtZS5zdGFydHNXaXRoKCcuJyk7XG59XG5cbi8qKlxuICogUmVjdXJzaXZlbHkgc2NhbiBhIGRpcmVjdG9yeSBmb3Igcm91dGUgZmlsZXMuXG4gKiBBbHNvIGNvbGxlY3RzIF9yZW5kZXJlci50cyBhbmQgX21pZGRsZXdhcmUudHMgc3BlY2lhbCBmaWxlcy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNjYW5Sb3V0ZXMoXG4gIHJvdXRlc0Rpcjogc3RyaW5nLFxuICBiYXNlRGlyOiBzdHJpbmcgPSAnJyxcbik6IFByb21pc2U8Um91dGVFbnRyeVtdPiB7XG4gIGNvbnN0IGVudHJpZXM6IFJvdXRlRW50cnlbXSA9IFtdO1xuICBjb25zdCBmaWxlcyA9IGF3YWl0IHNhZmVSZWFkRGlyKHJvdXRlc0Rpcik7XG5cbiAgaWYgKGZpbGVzID09PSB1bmRlZmluZWQpIHtcbiAgICBsb2cuZGVidWcoYFJvdXRlcyBkaXJlY3RvcnkgXCIke3JvdXRlc0Rpcn1cIiBub3QgZm91bmRgKTtcbiAgICByZXR1cm4gZW50cmllcztcbiAgfVxuXG4gIGZvciAoY29uc3QgZmlsZSBvZiBmaWxlcykge1xuICAgIGlmIChpc0lnbm9yZWRGaWxlKGZpbGUpKSBjb250aW51ZTtcblxuICAgIGNvbnN0IGZ1bGxQYXRoID0gam9pbihyb3V0ZXNEaXIsIGZpbGUpO1xuICAgIGNvbnN0IHJlbGF0aXZlUGF0aCA9IGJhc2VEaXIgPyBqb2luKGJhc2VEaXIsIGZpbGUpIDogZmlsZTtcbiAgICBjb25zdCBmaWxlU3RhdCA9IGF3YWl0IHNhZmVTdGF0KGZ1bGxQYXRoKTtcbiAgICBpZiAoIWZpbGVTdGF0KSB7XG4gICAgICBsb2cuZGVidWcoYEZpbGUgdmFuaXNoZWQgYmVmb3JlIHN0YXQ6ICR7ZnVsbFBhdGh9YCk7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICBpZiAoZmlsZVN0YXQuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgLy8gUmVjdXJzZSBpbnRvIHN1YmRpcmVjdG9yaWVzXG4gICAgICBjb25zdCBzdWJFbnRyaWVzID0gYXdhaXQgc2NhblJvdXRlcyhmdWxsUGF0aCwgcmVsYXRpdmVQYXRoKTtcbiAgICAgIGVudHJpZXMucHVzaCguLi5zdWJFbnRyaWVzKTtcbiAgICB9IGVsc2UgaWYgKC9cXC4odHN8dHN4fGpzfGpzeCkkLy50ZXN0KGZpbGUpKSB7XG4gICAgICAvLyBDaGVjayBmb3Igc3BlY2lhbCBmaWxlc1xuICAgICAgY29uc3Qgc3BlY2lhbFR5cGUgPSBnZXRTcGVjaWFsRmlsZVR5cGUoZmlsZSk7XG4gICAgICBpZiAoc3BlY2lhbFR5cGUpIHtcbiAgICAgICAgLy8gQWRkIGFzIGEgc3BlY2lhbCBlbnRyeSAtIG5vdCBhIHJvdXRlIGhhbmRsZXIsIGJ1dCBsb2FkYWJsZVxuICAgICAgICBlbnRyaWVzLnB1c2goe1xuICAgICAgICAgIHBhdGg6IGZpbGVQYXRoVG9Sb3V0ZVBhdGgocmVsYXRpdmVQYXRoKSxcbiAgICAgICAgICBmaWxlUGF0aDogcmVsYXRpdmVQYXRoLnNwbGl0KHNlcCkuam9pbihwb3NpeC5zZXApLFxuICAgICAgICAgIHR5cGU6ICdzcGVjaWFsJywgLy8gTm90IGEgcGFnZSBvciBBUEkgcm91dGUgLSByZW5kZXJlci9taWRkbGV3YXJlIG9ubHlcbiAgICAgICAgICB2YXJOYW1lOiBgU3BlY2lhbF8ke3NwZWNpYWxUeXBlfV8ke2Jhc2VEaXIucmVwbGFjZSgvW1xcXFwvXS9nLCAnXycpIHx8ICdyb290J31gLFxuICAgICAgICAgIHNwZWNpYWw6IHNwZWNpYWxUeXBlLFxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSBpZiAoIWZpbGUuc3RhcnRzV2l0aCgnXycpKSB7XG4gICAgICAgIC8vIFJlZ3VsYXIgcm91dGUgZmlsZVxuICAgICAgICBjb25zdCByb3V0ZVBhdGggPSBmaWxlUGF0aFRvUm91dGVQYXRoKHJlbGF0aXZlUGF0aCk7XG4gICAgICAgIGNvbnN0IHJvdXRlVHlwZSA9IGdldFJvdXRlVHlwZShyZWxhdGl2ZVBhdGgpO1xuICAgICAgICAvLyB2MC4yNTogQVNULXZlcmlmaWVkIOKAlCBwYXRoIHV0aWxpdHksIGV4dHJhY3RzIFtwYXJhbV0gcGF0dGVybnNcbiAgICAgICAgY29uc3QgcGFyYW1NYXRjaGVzID0gcmVsYXRpdmVQYXRoLm1hdGNoKC9cXFsoW15cXF1dKylcXF0vZyk7XG4gICAgICAgIGNvbnN0IHBhcmFtcyA9IHBhcmFtTWF0Y2hlcyA/IHBhcmFtTWF0Y2hlcy5tYXAoKG0pID0+IG0uc2xpY2UoMSwgLTEpKSA6IHVuZGVmaW5lZDtcbiAgICAgICAgbGV0IHRhZ05hbWU6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICAgICAgaWYgKHJvdXRlVHlwZSA9PT0gJ3BhZ2UnKSB7XG4gICAgICAgICAgLy8gUmVnZXgtYmFzZWQgc2Nhbm5pbmcgcmVhZHMgYGV4cG9ydCBjb25zdCB0YWdOYW1lYCB3aXRob3V0IGV4ZWN1dGluZyB0aGUgbW9kdWxlLlxuICAgICAgICAgIHRhZ05hbWUgPSBhd2FpdCByZWFkUm91dGVUYWdOYW1lRnJvbU1vZHVsZShmdWxsUGF0aCk7XG4gICAgICAgICAgaWYgKHRhZ05hbWUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgLy8gdGFnTmFtZSBub3QgZm91bmQgaXMgbm9ybWFsIOKAlCBub3QgYWxsIHBhZ2Ugcm91dGVzIGRlZmluZSBvbmVcbiAgICAgICAgICAgIGxvZy5kZWJ1ZyhgTm8gdGFnTmFtZSBleHBvcnQgZm91bmQgaW4gcm91dGUgbW9kdWxlOiAke2Z1bGxQYXRofWApO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbnRyaWVzLnB1c2goe1xuICAgICAgICAgIHBhdGg6IHJvdXRlUGF0aCxcbiAgICAgICAgICBmaWxlUGF0aDogcmVsYXRpdmVQYXRoLnNwbGl0KHNlcCkuam9pbihwb3NpeC5zZXApLFxuICAgICAgICAgIHR5cGU6IHJvdXRlVHlwZSxcbiAgICAgICAgICB2YXJOYW1lOiBwYXRoVG9WYXJOYW1lKHJvdXRlUGF0aCksXG4gICAgICAgICAgdGFnTmFtZSxcbiAgICAgICAgICBwYXJhbXMsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgLy8gT3RoZXIgXy1wcmVmaXhlZCBmaWxlcyAobm90IF9yZW5kZXJlci9fbWlkZGxld2FyZSkgYXJlIHNpbGVudGx5IHNraXBwZWRcbiAgICB9XG4gIH1cblxuICAvLyBTb3J0IHJvdXRlczogc3RhdGljIHBhdGhzIGZpcnN0LCB0aGVuIGR5bmFtaWNcbiAgZW50cmllcy5zb3J0KChhLCBiKSA9PiB7XG4gICAgLy8gU3BlY2lhbCBmaWxlcyBnbyB0byB0aGUgZW5kXG4gICAgaWYgKGEuc3BlY2lhbCB8fCBiLnNwZWNpYWwpIHtcbiAgICAgIGlmIChhLnNwZWNpYWwgJiYgIWIuc3BlY2lhbCkgcmV0dXJuIDE7XG4gICAgICBpZiAoIWEuc3BlY2lhbCAmJiBiLnNwZWNpYWwpIHJldHVybiAtMTtcbiAgICAgIHJldHVybiAwO1xuICAgIH1cbiAgICBjb25zdCBhRHluYW1pYyA9IGEucGF0aC5pbmNsdWRlcygnOicpO1xuICAgIGNvbnN0IGJEeW5hbWljID0gYi5wYXRoLmluY2x1ZGVzKCc6Jyk7XG4gICAgaWYgKGFEeW5hbWljICE9PSBiRHluYW1pYykgcmV0dXJuIGFEeW5hbWljID8gMSA6IC0xO1xuICAgIHJldHVybiBhLnBhdGgubG9jYWxlQ29tcGFyZShiLnBhdGgpO1xuICB9KTtcblxuICByZXR1cm4gZW50cmllcztcbn1cblxuLyoqXG4gKiB2MC4yNTogQVNULXZlcmlmaWVkIOKAlCBjb252ZXJ0cyBmaWxlIG5hbWUgdG8gYSB2YWxpZCBDdXN0b20gRWxlbWVudCB0YWcgbmFtZS5cbiAqIFVzZXMgcmVnZXggZm9yIHBhdGggbWFuaXB1bGF0aW9uIHNpbmNlIHRhZyBuYW1lcyBhcmUgZGVyaXZlZCBmcm9tIGZpbGUgcGF0aHMuXG4gKlxuICogRXhhbXBsZXM6XG4gKiAgICdteS1jb3VudGVyLnRzJyAgICAgICAgLT4gJ215LWNvdW50ZXInXG4gKiAgICdwb3N0cy9pbmRleC50cycgICAgICAgLT4gJ3Bvc3RzLWluZGV4J1xuICogICAnYWRtaW5cXFxcZGFzaGJvYXJkLnRzJyAgLT4gJ2FkbWluLWRhc2hib2FyZCdcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbGVUb1RhZ05hbWUoZmlsZU5hbWU6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBmaWxlTmFtZVxuICAgIC5yZXBsYWNlKC9cXC5bXi5dKyQvLCAnJykgLy8gdjAuMjU6IEFTVC12ZXJpZmllZCDigJQgcmVtb3ZlIGV4dGVuc2lvblxuICAgIC5yZXBsYWNlKC9bXFxcXC9dL2csICctJykgLy8gdjAuMjU6IEFTVC12ZXJpZmllZCDigJQgcmVwbGFjZSBwYXRoIHNlcGFyYXRvcnMgd2l0aCBoeXBoZW5zXG4gICAgLnRvTG93ZXJDYXNlKCk7XG59XG5cbi8qKlxuICogU2NhbiBpc2xhbmRzIGRpcmVjdG9yeSByZWN1cnNpdmVseSBmb3IgaXNsYW5kIGZpbGVzLlxuICogUmV0dXJucyBwYXRocyByZWxhdGl2ZSB0byBpc2xhbmRzRGlyIChlLmcuLCBbJ215LWNvdW50ZXIudHMnLCAncG9zdHMvaW5kZXgudHMnXSkuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzY2FuSXNsYW5kcyhcbiAgaXNsYW5kc0Rpcjogc3RyaW5nLFxuICByZWxhdGl2ZURpcjogc3RyaW5nID0gJycsXG4pOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gIGNvbnN0IGZpbGVzOiBzdHJpbmdbXSA9IFtdO1xuICBjb25zdCBlbnRyaWVzID0gYXdhaXQgc2FmZVJlYWREaXIoaXNsYW5kc0Rpcik7XG5cbiAgaWYgKGVudHJpZXMgPT09IHVuZGVmaW5lZCkge1xuICAgIGxvZy5kZWJ1ZyhgSXNsYW5kcyBkaXJlY3RvcnkgXCIke2lzbGFuZHNEaXJ9XCIgbm90IGZvdW5kYCk7XG4gICAgcmV0dXJuIGZpbGVzO1xuICB9XG5cbiAgZm9yIChjb25zdCBlbnRyeSBvZiBlbnRyaWVzKSB7XG4gICAgaWYgKGVudHJ5LnN0YXJ0c1dpdGgoJy4nKSkgY29udGludWU7XG5cbiAgICBjb25zdCBmdWxsUGF0aCA9IGpvaW4oaXNsYW5kc0RpciwgZW50cnkpO1xuICAgIGNvbnN0IGZpbGVTdGF0ID0gYXdhaXQgc2FmZVN0YXQoZnVsbFBhdGgpO1xuICAgIGlmICghZmlsZVN0YXQpIHtcbiAgICAgIGxvZy5kZWJ1ZyhgSXNsYW5kIGZpbGUgdmFuaXNoZWQgYmVmb3JlIHN0YXQ6ICR7ZnVsbFBhdGh9YCk7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICBjb25zdCByZWxhdGl2ZVBhdGggPSByZWxhdGl2ZURpciA/IGpvaW4ocmVsYXRpdmVEaXIsIGVudHJ5KSA6IGVudHJ5O1xuXG4gICAgaWYgKGZpbGVTdGF0LmlzRGlyZWN0b3J5KCkpIHtcbiAgICAgIGNvbnN0IHN1YkZpbGVzID0gYXdhaXQgc2NhbklzbGFuZHMoZnVsbFBhdGgsIHJlbGF0aXZlUGF0aCk7XG4gICAgICBmaWxlcy5wdXNoKC4uLnN1YkZpbGVzKTtcbiAgICB9IGVsc2UgaWYgKC9cXC4odHN8dHN4fGpzfGpzeCkkLy50ZXN0KGVudHJ5KSkge1xuICAgICAgZmlsZXMucHVzaChyZWxhdGl2ZVBhdGgpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBmaWxlcy5zb3J0KCk7XG59XG5cbi8qKlxuICogdjAuNDEuMC1hbHBoYS4xOiBSZWdleC1iYXNlZCDigJQgcmVhZHMgaXNsYW5kIG1ldGFkYXRhIGJ5IHN0YXRpY2FsbHkgc2Nhbm5pbmcgdGhlIG1vZHVsZVxuICogc291cmNlIGZvciBgZXhwb3J0IGNvbnN0IG9wZW5FbGVtZW50ID0gZGVmaW5lSXNsYW5kQ29uZmlnKHsgLi4uIH0pYC5cbiAqXG4gKiBTdXBwb3J0ZWQgZm9ybTpcbiAqICAgZXhwb3J0IGNvbnN0IG9wZW5FbGVtZW50ID0gZGVmaW5lSXNsYW5kQ29uZmlnKHsgc3NyOiBmYWxzZSwgZHNkOiBmYWxzZSwgaHlkcmF0ZTogJ29ubHknIH0pXG4gKlxuICogVGhpcyBpcyBtb3JlIHJlbGlhYmxlIHRoYW4gcmVnZXggYmVjYXVzZSBpdCBoYW5kbGVzOlxuICogLSBDb21tZW50cyBpbnNpZGUgdGhlIG9iamVjdCBsaXRlcmFsXG4gKiAtIENvbXB1dGVkIHByb3BlcnRpZXNcbiAqIC0gRGVzdHJ1Y3R1cmVkL3JlLWV4cG9ydGVkIHZhbHVlc1xuICogLSBDYW5vbmljYWwgZGVmaW5lSXNsYW5kQ29uZmlnKC4uLikgY2FsbHNcbiAqXG4gKiBJZiBhIG1vZHVsZSBjYW5ub3QgYmUgcmVhZCwgaXRzIG1ldGFkYXRhIGlzIHNpbGVudGx5IHNraXBwZWQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzY2FuSXNsYW5kTWV0YShcbiAgaXNsYW5kc0Rpcjogc3RyaW5nLFxuICBpc2xhbmRGaWxlczogc3RyaW5nW10sXG4pOiBQcm9taXNlPFJlY29yZDxzdHJpbmcsIExvY2FsSXNsYW5kTWV0YT4+IHtcbiAgY29uc3QgbWV0YTogUmVjb3JkPHN0cmluZywgTG9jYWxJc2xhbmRNZXRhPiA9IHt9O1xuXG4gIGZvciAoY29uc3QgZmlsZVBhdGggb2YgaXNsYW5kRmlsZXMpIHtcbiAgICBjb25zdCB0YWdOYW1lID0gZmlsZVRvVGFnTmFtZShmaWxlUGF0aCk7XG4gICAgY29uc3QgZnVsbFBhdGggPSBqb2luKGlzbGFuZHNEaXIsIGZpbGVQYXRoKTtcblxuICAgIGNvbnN0IHNvdXJjZSA9IGF3YWl0IHNhZmVSZWFkRmlsZShmdWxsUGF0aCk7XG4gICAgaWYgKHNvdXJjZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBsb2cuZGVidWcoYFVuYWJsZSB0byByZWFkIGlzbGFuZCBtb2R1bGUgZm9yIG1ldGFkYXRhOiAke2Z1bGxQYXRofWApO1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgLy8gUmVhZCB0aGUgYG9wZW5FbGVtZW50YCBleHBvcnQgZGlyZWN0bHk7IG5vIHJlZ2V4IG5lZWRlZC5cbiAgICBjb25zdCBvcGVuRWxlbWVudEV4cG9ydCA9IHJlYWRTdGF0aWNPcGVuRWxlbWVudEV4cG9ydChzb3VyY2UpO1xuICAgIGlmICghb3BlbkVsZW1lbnRFeHBvcnQpIGNvbnRpbnVlO1xuXG4gICAgY29uc3QgaHlkcmF0ZTogTG9jYWxJc2xhbmRNZXRhWydoeWRyYXRlJ10gPSBvcGVuRWxlbWVudEV4cG9ydC5oeWRyYXRlICYmXG4gICAgICAgIFsnbG9hZCcsICdpZGxlJywgJ3Zpc2libGUnLCAnb25seSddLmluY2x1ZGVzKG9wZW5FbGVtZW50RXhwb3J0Lmh5ZHJhdGUpXG4gICAgICA/IG9wZW5FbGVtZW50RXhwb3J0Lmh5ZHJhdGVcbiAgICAgIDogdW5kZWZpbmVkO1xuXG4gICAgbWV0YVt0YWdOYW1lXSA9IHtcbiAgICAgIHRhZ05hbWUsXG4gICAgICBmaWxlUGF0aCxcbiAgICAgIHNzcjogaHlkcmF0ZSA9PT0gJ29ubHknID8gZmFsc2UgOiBvcGVuRWxlbWVudEV4cG9ydC5zc3IsXG4gICAgICBkc2Q6IGh5ZHJhdGUgPT09ICdvbmx5JyA/IGZhbHNlIDogb3BlbkVsZW1lbnRFeHBvcnQuZHNkLFxuICAgICAgaHlkcmF0ZSxcbiAgICAgIHJlYXNvbjogaHlkcmF0ZSA9PT0gJ29ubHknXG4gICAgICAgID8gJ2xvY2FsIGlzbGFuZCBleHBvcnRzIG9wZW5FbGVtZW50Lmh5ZHJhdGU9b25seSdcbiAgICAgICAgOiBvcGVuRWxlbWVudEV4cG9ydC5zc3IgPT09IGZhbHNlXG4gICAgICAgID8gJ2xvY2FsIGlzbGFuZCBleHBvcnRzIG9wZW5FbGVtZW50LnNzcj1mYWxzZSdcbiAgICAgICAgOiB1bmRlZmluZWQsXG4gICAgfTtcbiAgfVxuXG4gIHJldHVybiBtZXRhO1xufVxuXG4vKipcbiAqIFNjYW4gcGFja2FnZSBleHBvcnRzIGZvciBPcGVuRWxlbWVudFBhY2thZ2VNYW5pZmVzdC5cbiAqIFBhY2thZ2VzIHNob3VsZCBleHBvcnQgYSBgbWFuaWZlc3RgIE9wZW5FbGVtZW50UGFja2FnZU1hbmlmZXN0IGluIHRoZWlyIG1haW4gZW50cnkuXG4gKlxuICogRXhhbXBsZSBwYWNrYWdlIGV4cG9ydDpcbiAqIGBgYHRzXG4gKiAvLyBAb3BlbmVsZW1lbnQvdWkvaW5kZXgudHNcbiAqIGV4cG9ydCB7IG1hbmlmZXN0IH0gZnJvbSAnLi9tYW5pZmVzdC5qcyc7XG4gKiBgYGBcbiAqXG4gKiBAcGFyYW0gcGFja2FnZU5hbWVzIC0gTGlzdCBvZiBwYWNrYWdlIG5hbWVzIHRvIHNjYW4gKGUuZy4sIFsnQG9wZW5lbGVtZW50L3VpJ10pXG4gKiBAcmV0dXJucyBBcnJheSBvZiBPcGVuRWxlbWVudFBhY2thZ2VNYW5pZmVzdFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2NhblBhY2thZ2VNYW5pZmVzdHMoXG4gIHBhY2thZ2VOYW1lczogc3RyaW5nW10sXG4pOiBQcm9taXNlPE9wZW5FbGVtZW50UGFja2FnZU1hbmlmZXN0W10+IHtcbiAgY29uc3QgYWxsTWFuaWZlc3RzOiBPcGVuRWxlbWVudFBhY2thZ2VNYW5pZmVzdFtdID0gW107XG5cbiAgZm9yIChjb25zdCBwa2cgb2YgcGFja2FnZU5hbWVzKSB7XG4gICAgLy8gQHZpdGUtaWdub3JlIHN1cHByZXNzZXMgdW5hbmFseXphYmxlLWR5bmFtaWMtaW1wb3J0IEpTUiB3YXJuaW5nLlxuICAgIGxldCBtb2Q6IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAgIHRyeSB7XG4gICAgICBtb2QgPSBhd2FpdCBpbXBvcnQoLyogQHZpdGUtaWdub3JlICovIHBrZykgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgaWYgKGlzQnJvd3Nlck9ubHlQYWNrYWdlSW1wb3J0RXJyb3IoZSkpIHtcbiAgICAgICAgbG9nLndhcm4oXG4gICAgICAgICAgYFNraXBwaW5nIHBhY2thZ2UgbWFuaWZlc3QgZnJvbSBcIiR7cGtnfVwiOiBicm93c2VyLW9ubHkgcGFja2FnZSBjYW5ub3QgYmUgaW1wb3J0ZWQgZHVyaW5nIFNTUiBkaXNjb3ZlcnlgLFxuICAgICAgICApO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIHRocm93IG5ldyBPcGVuRWxlbWVudEVycm9yKFxuICAgICAgICBgRmFpbGVkIHRvIHNjYW4gcGFja2FnZSBtYW5pZmVzdCBmcm9tIFwiJHtwa2d9XCI6ICR7Zm9ybWF0RXJyb3IoZSl9YCxcbiAgICAgICAge1xuICAgICAgICAgIGNvZGU6ICdQQUNLQUdFX1NDQU5fRVJST1InLFxuICAgICAgICAgIHN0YXR1c0NvZGU6IDUwMCxcbiAgICAgICAgICByZWNvdmVyYWJsZTogZmFsc2UsXG4gICAgICAgIH0sXG4gICAgICApO1xuICAgIH1cbiAgICBpZiAobW9kLm1hbmlmZXN0ICYmIHR5cGVvZiBtb2QubWFuaWZlc3QgPT09ICdvYmplY3QnKSB7XG4gICAgICBjb25zdCBtYW5pZmVzdCA9IG1vZC5tYW5pZmVzdCBhcyBPcGVuRWxlbWVudFBhY2thZ2VNYW5pZmVzdDtcbiAgICAgIGlmIChtYW5pZmVzdC5wYWNrYWdlTmFtZSAmJiBtYW5pZmVzdC5kZWNsYXJhdGlvbnMpIHtcbiAgICAgICAgYWxsTWFuaWZlc3RzLnB1c2gobWFuaWZlc3QpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IE9wZW5FbGVtZW50RXJyb3IoXG4gICAgICAgICAgYEludmFsaWQgbWFuaWZlc3QgaW4gJHtwa2d9OiBtaXNzaW5nIHBhY2thZ2VOYW1lIG9yIGRlY2xhcmF0aW9uc2AsXG4gICAgICAgICAge1xuICAgICAgICAgICAgY29kZTogJ1BBQ0tBR0VfTUFOSUZFU1RfRVJST1InLFxuICAgICAgICAgICAgc3RhdHVzQ29kZTogNTAwLFxuICAgICAgICAgICAgcmVjb3ZlcmFibGU6IGZhbHNlLFxuICAgICAgICAgIH0sXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBPcGVuRWxlbWVudEVycm9yKFxuICAgICAgICBgUGFja2FnZSAke3BrZ30gZG9lcyBub3QgZXhwb3J0IGEgbWFuaWZlc3RgLFxuICAgICAgICB7XG4gICAgICAgICAgY29kZTogJ1BBQ0tBR0VfTUFOSUZFU1RfRVJST1InLFxuICAgICAgICAgIHN0YXR1c0NvZGU6IDUwMCxcbiAgICAgICAgICByZWNvdmVyYWJsZTogZmFsc2UsXG4gICAgICAgIH0sXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBhbGxNYW5pZmVzdHM7XG59XG5cbi8qKlxuICogdjAuMjU6IEFTVC12ZXJpZmllZCDigJQgZXJyb3IgbWVzc2FnZSBjbGFzc2lmaWNhdGlvbiwgcmVnZXggaXMgdGhlIGFwcHJvcHJpYXRlIHRvb2xcbiAqIGZvciBtYXRjaGluZyBydW50aW1lIGVycm9yIHN0cmluZ3MgZnJvbSBmYWlsZWQgZHluYW1pYyBpbXBvcnRzLlxuICovXG5mdW5jdGlvbiBpc0Jyb3dzZXJPbmx5UGFja2FnZUltcG9ydEVycm9yKGVycm9yOiB1bmtub3duKTogYm9vbGVhbiB7XG4gIGNvbnN0IG1lc3NhZ2UgPSBmb3JtYXRFcnJvcihlcnJvcik7XG4gIHJldHVybiAvXFxiKHdpbmRvd3xkb2N1bWVudHxIVE1MRWxlbWVudHxjdXN0b21FbGVtZW50c3xuYXZpZ2F0b3IpXFxiLipcXGJpcyBub3QgZGVmaW5lZFxcYi9pLnRlc3QoXG4gICAgbWVzc2FnZSxcbiAgKTtcbn1cblxuLy8g4pSA4pSA4pSAIENFTSBBdXRvLURldGVjdGlvbiAodjAuMTguMCkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbi8qKiBSZXN1bHQgb2Ygc2Nhbm5pbmcgbm9kZV9tb2R1bGVzIGZvciBDRU0gbWFuaWZlc3RzICovXG5leHBvcnQgaW50ZXJmYWNlIENlbVNjYW5SZXN1bHQge1xuICAvKiogUGFja2FnZSBuYW1lIChlLmcuICdAb3BlbmVsZW1lbnQvdWknKSAqL1xuICBwYWNrYWdlTmFtZTogc3RyaW5nO1xuICAvKiogQWJzb2x1dGUgcGF0aCB0byBjdXN0b20tZWxlbWVudHMuanNvbiAqL1xuICBjZW1QYXRoOiBzdHJpbmc7XG4gIC8qKiBSYXcgSlNPTiBjb250ZW50ICovXG4gIGpzb246IHN0cmluZztcbn1cblxuLyoqXG4gKiBTY2FuIG5vZGVfbW9kdWxlcyBmb3IgcGFja2FnZXMgdGhhdCBzaGlwIGEgYGN1c3RvbS1lbGVtZW50cy5qc29uYC5cbiAqXG4gKiBTdHJhdGVneTpcbiAqICAgMS4gUmVhZCBub2RlX21vZHVsZXMgZGlyZWN0b3J5IGVudHJpZXMgKHRvcC1sZXZlbCBwYWNrYWdlcyArIHNjb3BlZCBvcmdzKVxuICogICAyLiBGb3IgZWFjaCBwYWNrYWdlLCBjaGVjayBpZiBgPHBrZz4vY3VzdG9tLWVsZW1lbnRzLmpzb25gIGV4aXN0c1xuICogICAzLiBSZXR1cm4gdGhlIHJhdyBKU09OIC0gY2FsbGVyIGlzIHJlc3BvbnNpYmxlIGZvciBwYXJzaW5nICsgY2xhc3NpZnlpbmdcbiAqXG4gKiBUaGlzIGZ1bmN0aW9uIHJlYWRzIGZpbGVzIG9ubHkuIEl0IG5ldmVyIGltcG9ydHMgb3IgZXhlY3V0ZXMgcGFja2FnZSBjb2RlLlxuICpcbiAqIEBwYXJhbSBub2RlTW9kdWxlc0RpciAtIEFic29sdXRlIHBhdGggdG8gdGhlIG5vZGVfbW9kdWxlcyBkaXJlY3RvcnlcbiAqIEByZXR1cm5zIEFycmF5IG9mIGZvdW5kIENFTSBtYW5pZmVzdHNcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNjYW5DZW1NYW5pZmVzdHMoXG4gIG5vZGVNb2R1bGVzRGlyOiBzdHJpbmcsXG4pOiBQcm9taXNlPENlbVNjYW5SZXN1bHRbXT4ge1xuICBjb25zdCByZXN1bHRzOiBDZW1TY2FuUmVzdWx0W10gPSBbXTtcblxuICBjb25zdCBlbnRyaWVzID0gYXdhaXQgc2FmZVJlYWREaXIobm9kZU1vZHVsZXNEaXIpO1xuICBpZiAoIWVudHJpZXMpIHJldHVybiByZXN1bHRzO1xuXG4gIGZvciAoY29uc3QgZW50cnkgb2YgZW50cmllcykge1xuICAgIGlmIChlbnRyeS5zdGFydHNXaXRoKCcuJykpIGNvbnRpbnVlO1xuXG4gICAgaWYgKGVudHJ5LnN0YXJ0c1dpdGgoJ0AnKSkge1xuICAgICAgLy8gU2NvcGVkIHBhY2thZ2UgZGlyZWN0b3J5IC0gcmVjdXJzZSBvbmUgbGV2ZWxcbiAgICAgIGNvbnN0IHNjb3BlRGlyID0gam9pbihub2RlTW9kdWxlc0RpciwgZW50cnkpO1xuICAgICAgY29uc3Qgc2NvcGVkRW50cmllcyA9IGF3YWl0IHNhZmVSZWFkRGlyKHNjb3BlRGlyKTtcbiAgICAgIGlmICghc2NvcGVkRW50cmllcykgY29udGludWU7XG4gICAgICBmb3IgKGNvbnN0IHNjb3BlZEVudHJ5IG9mIHNjb3BlZEVudHJpZXMpIHtcbiAgICAgICAgaWYgKHNjb3BlZEVudHJ5LnN0YXJ0c1dpdGgoJy4nKSkgY29udGludWU7XG4gICAgICAgIGNvbnN0IHBhY2thZ2VOYW1lID0gYCR7ZW50cnl9LyR7c2NvcGVkRW50cnl9YDtcbiAgICAgICAgY29uc3QgY2VtUGF0aCA9IGpvaW4obm9kZU1vZHVsZXNEaXIsIGVudHJ5LCBzY29wZWRFbnRyeSwgJ2N1c3RvbS1lbGVtZW50cy5qc29uJyk7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRyeVJlYWRDZW1GaWxlKGNlbVBhdGgsIHBhY2thZ2VOYW1lKTtcbiAgICAgICAgaWYgKHJlc3VsdCkgcmVzdWx0cy5wdXNoKHJlc3VsdCk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIFJlZ3VsYXIgKG5vbi1zY29wZWQpIHBhY2thZ2VcbiAgICAgIGNvbnN0IGNlbVBhdGggPSBqb2luKG5vZGVNb2R1bGVzRGlyLCBlbnRyeSwgJ2N1c3RvbS1lbGVtZW50cy5qc29uJyk7XG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCB0cnlSZWFkQ2VtRmlsZShjZW1QYXRoLCBlbnRyeSk7XG4gICAgICBpZiAocmVzdWx0KSByZXN1bHRzLnB1c2gocmVzdWx0KTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gcmVzdWx0cztcbn1cblxuLyoqXG4gKiBUcnkgdG8gcmVhZCBhIGN1c3RvbS1lbGVtZW50cy5qc29uIGZpbGUuXG4gKiBSZXR1cm5zIG51bGwgaWYgdGhlIGZpbGUgZG9lc24ndCBleGlzdCBvciBjYW4ndCBiZSByZWFkLlxuICovXG5hc3luYyBmdW5jdGlvbiB0cnlSZWFkQ2VtRmlsZShcbiAgY2VtUGF0aDogc3RyaW5nLFxuICBwYWNrYWdlTmFtZTogc3RyaW5nLFxuKTogUHJvbWlzZTxDZW1TY2FuUmVzdWx0IHwgbnVsbD4ge1xuICBjb25zdCBqc29uID0gYXdhaXQgc2FmZVJlYWRGaWxlKGNlbVBhdGgpO1xuICByZXR1cm4ganNvbiA9PT0gdW5kZWZpbmVkID8gbnVsbCA6IHsgcGFja2FnZU5hbWUsIGNlbVBhdGgsIGpzb24gfTtcbn1cblxuLyoqXG4gKiBSdW4gQ0VNIGF1dG8tZGV0ZWN0aW9uOiBzY2FuIG5vZGVfbW9kdWxlcywgcGFyc2UgZWFjaCBtYW5pZmVzdCxcbiAqIGFuZCBjbGFzc2lmeSBhbGwgZGlzY292ZXJlZCBjb21wb25lbnRzLlxuICpcbiAqIFRoaXMgaXMgdGhlIGhpZ2gtbGV2ZWwgZnVuY3Rpb24gY2FsbGVkIGZyb20gdGhlIFZpdGUgcGx1Z2luIGJ1aWxkU3RhcnQoKS5cbiAqIEl0IGNvbWJpbmVzIHNjYW5DZW1NYW5pZmVzdHMoKSArIHBhcnNlQ2VtKCkgKyBjbGFzc2lmeUNlbU1hbmlmZXN0KClcbiAqIGludG8gYSBzaW5nbGUgcGlwZWxpbmUuXG4gKlxuICogQHBhcmFtIG5vZGVNb2R1bGVzRGlyIC0gQWJzb2x1dGUgcGF0aCB0byBub2RlX21vZHVsZXNcbiAqIEByZXR1cm5zIEFycmF5IG9mIGNvbXBhdGliaWxpdHkgY2xhc3NpZmljYXRpb25zIChtYXkgYmUgZW1wdHkgaWYgbm8gQ0VNIGZvdW5kKVxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZGV0ZWN0QW5kQ2xhc3NpZnlDZW1QYWNrYWdlcyhcbiAgbm9kZU1vZHVsZXNEaXI6IHN0cmluZyxcbik6IFByb21pc2U8Q29tcGF0aWJpbGl0eUNsYXNzaWZpY2F0aW9uW10+IHtcbiAgY29uc3QgY2VtUmVzdWx0cyA9IGF3YWl0IHNjYW5DZW1NYW5pZmVzdHMobm9kZU1vZHVsZXNEaXIpO1xuICBpZiAoY2VtUmVzdWx0cy5sZW5ndGggPT09IDApIHJldHVybiBbXTtcblxuICBjb25zdCBhbGxDbGFzc2lmaWNhdGlvbnM6IENvbXBhdGliaWxpdHlDbGFzc2lmaWNhdGlvbltdID0gW107XG5cbiAgZm9yIChjb25zdCB7IHBhY2thZ2VOYW1lLCBqc29uIH0gb2YgY2VtUmVzdWx0cykge1xuICAgIGNvbnN0IHBhcnNlUmVzdWx0ID0gcGFyc2VDZW0oanNvbik7XG4gICAgaWYgKCFwYXJzZVJlc3VsdC5zdWNjZXNzIHx8ICFwYXJzZVJlc3VsdC5tYW5pZmVzdCkge1xuICAgICAgbG9nLmRlYnVnKFxuICAgICAgICBgU2tpcHBpbmcgaW52YWxpZCBDRU0gbWFuaWZlc3QgZnJvbSBcIiR7cGFja2FnZU5hbWV9XCI6IGAgK1xuICAgICAgICAgIHBhcnNlUmVzdWx0LmVycm9ycy5tYXAoKGUpID0+IGUubWVzc2FnZSkuam9pbignOyAnKSxcbiAgICAgICk7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICAvLyBBdHRhY2ggcGFja2FnZSBuYW1lIHRvIHRoZSBtYW5pZmVzdCBmb3IgYmV0dGVyIGRpYWdub3N0aWNzXG4gICAgY29uc3QgbWFuaWZlc3QgPSB7IC4uLnBhcnNlUmVzdWx0Lm1hbmlmZXN0LCBwYWNrYWdlTmFtZSB9O1xuICAgIGNvbnN0IGNsYXNzUmVzdWx0ID0gY2xhc3NpZnlDZW1NYW5pZmVzdChtYW5pZmVzdCk7XG5cbiAgICAvLyBMb2cgc3VtbWFyeVxuICAgIGNvbnN0IHsgc3RhdHMgfSA9IGNsYXNzUmVzdWx0O1xuICAgIGlmIChzdGF0cy50b3RhbENvbXBvbmVudHMgPiAwKSB7XG4gICAgICBsb2cuaW5mbyhcbiAgICAgICAgYENFTTogJHtwYWNrYWdlTmFtZX0gLSAke3N0YXRzLnRvdGFsQ29tcG9uZW50c30gY29tcG9uZW50KHMpOiBgICtcbiAgICAgICAgICBgJHtzdGF0cy5zc3JDYXBhYmxlQ291bnR9IHNzci1jYXBhYmxlLCAke3N0YXRzLmNsaWVudE9ubHlDb3VudH0gY2xpZW50LW9ubHlgICtcbiAgICAgICAgICAoc3RhdHMucmVqZWN0ZWRDb3VudCA+IDAgPyBgLCAke3N0YXRzLnJlamVjdGVkQ291bnR9IHJlamVjdGVkYCA6ICcnKSArXG4gICAgICAgICAgKHN0YXRzLmV4cGVyaW1lbnRhbERvbUNvdW50ID4gMCA/IGAsICR7c3RhdHMuZXhwZXJpbWVudGFsRG9tQ291bnR9IGV4cGVyaW1lbnRhbGAgOiAnJyksXG4gICAgICApO1xuICAgIH1cblxuICAgIGFsbENsYXNzaWZpY2F0aW9ucy5wdXNoKC4uLmNsYXNzUmVzdWx0LmNsYXNzaWZpY2F0aW9ucyk7XG4gIH1cblxuICByZXR1cm4gYWxsQ2xhc3NpZmljYXRpb25zO1xufVxuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Q0FnREMsR0FRRCxTQUFTLFdBQVcsRUFBRSxnQkFBZ0IsUUFBUSwyQkFBMkI7QUFDekUsU0FBUyxZQUFZLFFBQVEsMkJBQTJCO0FBQ3hELFNBQVMsSUFBSSxFQUFFLEtBQUssRUFBRSxHQUFHLFFBQVEsWUFBWTtBQUM3QyxTQUFTLG1CQUFtQixFQUFFLFFBQVEsUUFBUSxrQkFBa0I7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
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @openelement/adapter-vite - Route Type Generator
3
+ *
4
+ * Generates `.openElement/routes.d.ts` with type-safe route parameter definitions
5
+ * for the `virtual:open-routes` module. Only routes that have dynamic [param]
6
+ * segments are included in the output.
7
+ *
8
+ * v0.25.0: Initial implementation for build-time route type code generation.
9
+ */ import type { RouteEntry } from '@openelement/protocol/framework';
10
+ /**
11
+ * Generate the `.openElement/routes.d.ts` declaration file content.
12
+ *
13
+ * Only routes that have dynamic parameters (non-empty `params` array)
14
+ * are included in the generated output. Static routes with no params
15
+ * are excluded since they don't need type-safe parameter access.
16
+ *
17
+ * Example output:
18
+ * ```typescript
19
+ * declare module 'virtual:open-routes' {
20
+ * interface RouteParams {
21
+ * '/blog/[slug]': { slug: string };
22
+ * '/registry/[package]/[component]': { package: string; component: string };
23
+ * }
24
+ * }
25
+ * ```
26
+ *
27
+ * @param routes - Array of route entries from the route scanner
28
+ * @returns TypeScript declaration file content as a string
29
+ */ export declare function generateRouteTypes(routes: RouteEntry[]): string;