UNPKG

@nlabs/lex

Version:
250 lines (249 loc) 33.8 kB
import chalk from "chalk"; import { execa } from "execa"; import { existsSync } from "fs"; import { sync as globSync } from "glob"; import { resolve as pathResolve } from "path"; import { LexConfig } from "../../LexConfig.js"; import { createSpinner } from "../../utils/app.js"; import { findTailwindCssPath, resolveBinaryPath } from "../../utils/file.js"; import { log } from "../../utils/log.js"; const findStoryFiles = () => { const storyPatterns = [ "**/*.stories.{ts,tsx,js,jsx}", "**/*.story.{ts,tsx,js,jsx}", "**/stories/**/*.{ts,tsx,js,jsx}" ]; const storyFiles = []; storyPatterns.forEach((pattern) => { const files = globSync(pattern, { cwd: process.cwd(), ignore: ["**/node_modules/**", "**/dist/**", "**/lib/**", "**/build/**"] }); storyFiles.push(...files); }); return storyFiles; }; const checkStorybookInitialization = () => { const projectConfigDir = pathResolve(process.cwd(), ".storybook"); const lexConfigDir = pathResolve(LexConfig.getLexDir(), ".storybook"); return existsSync(projectConfigDir) || existsSync(lexConfigDir); }; const extractProgressPercentage = (output) => { const lines = output.split("\n"); for (const line of lines) { if (line.includes("[webpack.Progress]") && line.includes("%")) { const percentageMatch = line.match(/(\d+)%/); if (percentageMatch) { return parseInt(percentageMatch[1]); } } } return null; }; const filterAndBeautifyOutput = (output, isVerbose) => { if (isVerbose) { return output; } const lines = output.split("\n"); const filteredLines = lines.filter((line) => { if (line.includes("[webpack.Progress]")) { return false; } if (line.includes("Storybook") || line.includes("Local:") || line.includes("http://localhost") || line.includes("info =>") || line.includes("Starting") || line.includes("ready") || line.includes("error") || line.includes("warning")) { return true; } return true; }); return filteredLines.join("\n"); }; const beautifyOutput = (output) => output.replace(/Storybook v[\d.]+/g, chalk.cyan("$&")).replace(/info =>/g, chalk.blue("info =>")).replace(/Local:/g, chalk.green("Local:")).replace(/On your network:/g, chalk.green("On your network:")).replace(/Storybook.*started/g, chalk.green("$&")).replace(/Storybook.*ready/g, chalk.green("$&")).replace(/error/g, chalk.red("$&")).replace(/warning/g, chalk.yellow("$&")).replace(/(\d+)%/g, chalk.magenta("$1%")); const storybook = async (cmd, callback = () => ({})) => { const { cliName = "Lex", config, open = false, port = 6007, quiet, static: staticBuild = false, useLexConfig = false, variables, verbose = false } = cmd; const spinner = createSpinner(quiet); log(chalk.cyan(`${cliName} starting Storybook...`), "info", quiet); await LexConfig.parseConfig(cmd); let variablesObj = { NODE_ENV: "development" }; if (variables) { try { variablesObj = JSON.parse(variables); } catch (_error) { log(` ${cliName} Error: Environment variables option is not a valid JSON object.`, "error", quiet); callback(1); return 1; } } process.env = { ...process.env, ...variablesObj }; spinner.start("Finding story files..."); const storyFiles = findStoryFiles(); if (storyFiles.length === 0) { spinner.fail("No story files found in the project."); log("Please create story files with .stories.ts/.stories.js extensions or in a stories/ directory.", "info", quiet); callback(1); return 1; } spinner.succeed(`Found ${storyFiles.length} story file(s)`); const tailwindCssPath = findTailwindCssPath(); console.log({ tailwindCssPath }); if (tailwindCssPath) { if (!quiet) { log(chalk.green(`\u2713 Tailwind CSS integration detected: ${tailwindCssPath}`), "info", quiet); } } else { if (!quiet) { log(chalk.yellow("\u26A0 No Tailwind CSS file found in project"), "info", quiet); log(chalk.gray("Create a tailwind.css file with @tailwind directives for full Tailwind support"), "info", quiet); } } if (!checkStorybookInitialization()) { spinner.fail("Storybook is not initialized in this project or in Lex."); log('Please run "npx storybook@latest init" to set up Storybook in your project, or ensure Lex has a valid .storybook configuration.', "info", quiet); callback(1); return 1; } const projectConfigDir = pathResolve(process.cwd(), ".storybook"); const lexConfigDir = pathResolve(LexConfig.getLexDir(), ".storybook"); let configDir = config; if (!configDir) { configDir = lexConfigDir; if (!useLexConfig && existsSync(projectConfigDir)) { configDir = projectConfigDir; } } if (!quiet) { log(chalk.gray(`Project config dir: ${projectConfigDir} (exists: ${existsSync(projectConfigDir)})`), "info", quiet); log(chalk.gray(`Lex config dir: ${lexConfigDir} (exists: ${existsSync(lexConfigDir)})`), "info", quiet); if (useLexConfig) { log(chalk.blue("Using Lex Storybook configuration (--use-lex-config flag)"), "info", quiet); } log(chalk.gray(`Initial config dir: ${configDir}`), "info", quiet); } if (configDir === lexConfigDir) { if (!quiet) { log(chalk.blue("Using Lex config, will create temporary config in project .storybook directory"), "info", quiet); } const projectStorybookDir = pathResolve(process.cwd(), ".storybook"); const fs = await import("fs/promises"); await fs.mkdir(projectStorybookDir, { recursive: true }); const lexMainPath = pathResolve(lexConfigDir, "main.ts"); const projectMainPath = pathResolve(projectStorybookDir, "main.ts"); let mainContent = await fs.readFile(lexMainPath, "utf8"); mainContent = mainContent.replace( /stories:\s*\[.*?\]/, `stories: ['${pathResolve(process.cwd(), "src/**/*.stories.@(ts|tsx)")}', '${pathResolve(process.cwd(), "src/**/*.mdx")}']` ); const lexNodeModules = pathResolve(LexConfig.getLexDir(), "node_modules"); mainContent = mainContent.replace( /const lexModule = \(modulePath: string\) => resolve\(getLexNodeModulesPath\(\), modulePath\);/, `const lexModule = (modulePath: string) => resolve('${lexNodeModules}', modulePath);` ); await fs.writeFile(projectMainPath, mainContent); const lexPreviewPath = pathResolve(lexConfigDir, "preview.tsx"); if (existsSync(lexPreviewPath)) { const previewContent = await fs.readFile(lexPreviewPath, "utf8"); await fs.writeFile(pathResolve(projectStorybookDir, "preview.tsx"), previewContent); } configDir = projectStorybookDir; } if (!existsSync(configDir)) { spinner.fail("Storybook configuration not found."); log(`Project config: ${projectConfigDir}`, "info", quiet); log(`Lex config: ${lexConfigDir}`, "info", quiet); log('Please run "npx storybook@latest init" to set up Storybook in your project, or ensure Lex has a valid .storybook configuration.', "info", quiet); callback(1); return 1; } const storybookPath = resolveBinaryPath("storybook"); if (!storybookPath) { log(` ${cliName} Error: storybook binary not found in Lex's node_modules or monorepo root`, "error", quiet); log("Please reinstall Lex or check your Storybook installation.", "info", quiet); callback(1); return 1; } const storybookArgs = [staticBuild ? "build" : "dev"]; storybookArgs.push("--config-dir", configDir); if (port) { storybookArgs.push("--port", port.toString()); } if (open) { storybookArgs.push("--open"); } if (staticBuild) { const outputDir = pathResolve(process.cwd(), "storybook-static"); storybookArgs.push("--output-dir", outputDir); } if (!quiet) { log(chalk.gray(`Config directory: ${configDir}`), "info", quiet); } process.env.TAILWIND_CSS_PATH = tailwindCssPath; try { spinner.start(staticBuild ? "Building static Storybook..." : "Starting Storybook development server..."); const storybookProcess = execa(storybookPath, storybookArgs, { encoding: "utf8", env: { ...process.env, LEX_QUIET: quiet, LEX_VERBOSE: verbose, STORYBOOK_OPEN: open, ...tailwindCssPath && { TAILWIND_CSS_PATH: tailwindCssPath } }, stdio: "pipe" }); let urlFound = false; let lastProgressPercentage = 0; storybookProcess.stdout?.on("data", (data) => { const output = data.toString(); const progressPercentage = extractProgressPercentage(output); if (progressPercentage !== null && progressPercentage !== lastProgressPercentage) { lastProgressPercentage = progressPercentage; const action = staticBuild ? "Building" : "Starting"; spinner.text = `${action} Storybook... ${progressPercentage}%`; process.stdout.write(` Webpack Progress: ${chalk.magenta(`${progressPercentage}%`)} `); } const filteredOutput = filterAndBeautifyOutput(output, verbose); const beautifiedOutput = beautifyOutput(filteredOutput); if (!urlFound && (output.includes("Local:") || output.includes("http://localhost") || output.includes("Storybook"))) { spinner.succeed(chalk.green("Storybook development server is ready!")); urlFound = true; } if (filteredOutput.trim()) { process.stdout.write(beautifiedOutput); } }); storybookProcess.stderr?.on("data", (data) => { const output = data.toString(); const filteredOutput = filterAndBeautifyOutput(output, verbose); const beautifiedOutput = beautifyOutput(filteredOutput); if (filteredOutput.trim()) { process.stderr.write(beautifiedOutput); } }); try { await storybookProcess; if (!urlFound) { spinner.succeed(chalk.green("Storybook development server started.")); } callback(0); return 0; } catch (error) { spinner.fail(chalk.red("There was an error while running storybook.")); log(` ${cliName} Error: ${error.message}`, "error", quiet); callback(1); return 1; } } catch (error) { log(` ${cliName} Error: ${error.message}`, "error", quiet); spinner.fail("There was an error while running storybook."); callback(1); return 1; } }; export { storybook }; //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vc3JjL2NvbW1hbmRzL3N0b3J5Ym9vay9zdG9yeWJvb2sudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImltcG9ydCBjaGFsayBmcm9tICdjaGFsayc7XG5pbXBvcnQge2V4ZWNhfSBmcm9tICdleGVjYSc7XG5pbXBvcnQge2V4aXN0c1N5bmN9IGZyb20gJ2ZzJztcbmltcG9ydCB7c3luYyBhcyBnbG9iU3luY30gZnJvbSAnZ2xvYic7XG5pbXBvcnQge3Jlc29sdmUgYXMgcGF0aFJlc29sdmV9IGZyb20gJ3BhdGgnO1xuXG5pbXBvcnQge0xleENvbmZpZ30gZnJvbSAnLi4vLi4vTGV4Q29uZmlnLmpzJztcbmltcG9ydCB7Y3JlYXRlU3Bpbm5lcn0gZnJvbSAnLi4vLi4vdXRpbHMvYXBwLmpzJztcbmltcG9ydCB7ZmluZFRhaWx3aW5kQ3NzUGF0aCwgcmVzb2x2ZUJpbmFyeVBhdGh9IGZyb20gJy4uLy4uL3V0aWxzL2ZpbGUuanMnO1xuaW1wb3J0IHtsb2d9IGZyb20gJy4uLy4uL3V0aWxzL2xvZy5qcyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU3Rvcnlib29rT3B0aW9ucyB7XG4gIHJlYWRvbmx5IGNsaU5hbWU/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGNvbmZpZz86IHN0cmluZztcbiAgcmVhZG9ubHkgb3Blbj86IGJvb2xlYW47XG4gIHJlYWRvbmx5IHBvcnQ/OiBudW1iZXI7XG4gIHJlYWRvbmx5IHF1aWV0PzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgc3RhdGljPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgdXNlTGV4Q29uZmlnPzogYm9vbGVhbjtcbiAgcmVhZG9ubHkgdmFyaWFibGVzPzogc3RyaW5nO1xuICByZWFkb25seSB2ZXJib3NlPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IHR5cGUgU3Rvcnlib29rQ2FsbGJhY2sgPSAoc3RhdHVzOiBudW1iZXIpID0+IHZvaWQ7XG5cbmNvbnN0IGZpbmRTdG9yeUZpbGVzID0gKCk6IHN0cmluZ1tdID0+IHtcbiAgY29uc3Qgc3RvcnlQYXR0ZXJucyA9IFtcbiAgICAnKiovKi5zdG9yaWVzLnt0cyx0c3gsanMsanN4fScsXG4gICAgJyoqLyouc3Rvcnkue3RzLHRzeCxqcyxqc3h9JyxcbiAgICAnKiovc3Rvcmllcy8qKi8qLnt0cyx0c3gsanMsanN4fSdcbiAgXTtcblxuICBjb25zdCBzdG9yeUZpbGVzOiBzdHJpbmdbXSA9IFtdO1xuXG4gIHN0b3J5UGF0dGVybnMuZm9yRWFjaCgocGF0dGVybikgPT4ge1xuICAgIGNvbnN0IGZpbGVzID0gZ2xvYlN5bmMocGF0dGVybiwge1xuICAgICAgY3dkOiBwcm9jZXNzLmN3ZCgpLFxuICAgICAgaWdub3JlOiBbJyoqL25vZGVfbW9kdWxlcy8qKicsICcqKi9kaXN0LyoqJywgJyoqL2xpYi8qKicsICcqKi9idWlsZC8qKiddXG4gICAgfSk7XG4gICAgc3RvcnlGaWxlcy5wdXNoKC4uLmZpbGVzKTtcbiAgfSk7XG5cbiAgcmV0dXJuIHN0b3J5RmlsZXM7XG59O1xuXG5jb25zdCBjaGVja1N0b3J5Ym9va0luaXRpYWxpemF0aW9uID0gKCk6IGJvb2xlYW4gPT4ge1xuICBjb25zdCBwcm9qZWN0Q29uZmlnRGlyID0gcGF0aFJlc29sdmUocHJvY2Vzcy5jd2QoKSwgJy5zdG9yeWJvb2snKTtcbiAgY29uc3QgbGV4Q29uZmlnRGlyID0gcGF0aFJlc29sdmUoTGV4Q29uZmlnLmdldExleERpcigpLCAnLnN0b3J5Ym9vaycpO1xuXG4gIHJldHVybiBleGlzdHNTeW5jKHByb2plY3RDb25maWdEaXIpIHx8IGV4aXN0c1N5bmMobGV4Q29uZmlnRGlyKTtcbn07XG5cbmNvbnN0IGV4dHJhY3RQcm9ncmVzc1BlcmNlbnRhZ2UgPSAob3V0cHV0OiBzdHJpbmcpOiBudW1iZXIgfCBudWxsID0+IHtcbiAgY29uc3QgbGluZXMgPSBvdXRwdXQuc3BsaXQoJ1xcbicpO1xuICBmb3IoY29uc3QgbGluZSBvZiBsaW5lcykge1xuICAgIGlmKGxpbmUuaW5jbHVkZXMoJ1t3ZWJwYWNrLlByb2dyZXNzXScpICYmIGxpbmUuaW5jbHVkZXMoJyUnKSkge1xuICAgICAgY29uc3QgcGVyY2VudGFnZU1hdGNoID0gbGluZS5tYXRjaCgvKFxcZCspJS8pO1xuICAgICAgaWYocGVyY2VudGFnZU1hdGNoKSB7XG4gICAgICAgIHJldHVybiBwYXJzZUludChwZXJjZW50YWdlTWF0Y2hbMV0pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICByZXR1cm4gbnVsbDtcbn07XG5cbmNvbnN0IGZpbHRlckFuZEJlYXV0aWZ5T3V0cHV0ID0gKG91dHB1dDogc3RyaW5nLCBpc1ZlcmJvc2U6IGJvb2xlYW4pOiBzdHJpbmcgPT4ge1xuICBpZihpc1ZlcmJvc2UpIHtcbiAgICByZXR1cm4gb3V0cHV0O1xuICB9XG5cbiAgY29uc3QgbGluZXMgPSBvdXRwdXQuc3BsaXQoJ1xcbicpO1xuICBjb25zdCBmaWx0ZXJlZExpbmVzID0gbGluZXMuZmlsdGVyKChsaW5lKSA9PiB7XG4gICAgaWYobGluZS5pbmNsdWRlcygnW3dlYnBhY2suUHJvZ3Jlc3NdJykpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBpZihsaW5lLmluY2x1ZGVzKCdTdG9yeWJvb2snKSB8fFxuICAgICAgbGluZS5pbmNsdWRlcygnTG9jYWw6JykgfHxcbiAgICAgIGxpbmUuaW5jbHVkZXMoJ2h0dHA6Ly9sb2NhbGhvc3QnKSB8fFxuICAgICAgbGluZS5pbmNsdWRlcygnaW5mbyA9PicpIHx8XG4gICAgICBsaW5lLmluY2x1ZGVzKCdTdGFydGluZycpIHx8XG4gICAgICBsaW5lLmluY2x1ZGVzKCdyZWFkeScpIHx8XG4gICAgICBsaW5lLmluY2x1ZGVzKCdlcnJvcicpIHx8XG4gICAgICBsaW5lLmluY2x1ZGVzKCd3YXJuaW5nJykpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIHJldHVybiB0cnVlO1xuICB9KTtcblxuICByZXR1cm4gZmlsdGVyZWRMaW5lcy5qb2luKCdcXG4nKTtcbn07XG5cbmNvbnN0IGJlYXV0aWZ5T3V0cHV0ID0gKG91dHB1dDogc3RyaW5nKTogc3RyaW5nID0+IG91dHB1dFxuICAucmVwbGFjZSgvU3Rvcnlib29rIHZbXFxkLl0rL2csIGNoYWxrLmN5YW4oJyQmJykpXG4gIC5yZXBsYWNlKC9pbmZvID0+L2csIGNoYWxrLmJsdWUoJ2luZm8gPT4nKSlcbiAgLnJlcGxhY2UoL0xvY2FsOi9nLCBjaGFsay5ncmVlbignTG9jYWw6JykpXG4gIC5yZXBsYWNlKC9PbiB5b3VyIG5ldHdvcms6L2csIGNoYWxrLmdyZWVuKCdPbiB5b3VyIG5ldHdvcms6JykpXG4gIC5yZXBsYWNlKC9TdG9yeWJvb2suKnN0YXJ0ZWQvZywgY2hhbGsuZ3JlZW4oJyQmJykpXG4gIC5yZXBsYWNlKC9TdG9yeWJvb2suKnJlYWR5L2csIGNoYWxrLmdyZWVuKCckJicpKVxuICAucmVwbGFjZSgvZXJyb3IvZywgY2hhbGsucmVkKCckJicpKVxuICAucmVwbGFjZSgvd2FybmluZy9nLCBjaGFsay55ZWxsb3coJyQmJykpXG4gIC5yZXBsYWNlKC8oXFxkKyklL2csIGNoYWxrLm1hZ2VudGEoJyQxJScpKTtcblxuZXhwb3J0IGNvbnN0IHN0b3J5Ym9vayA9IGFzeW5jIChjbWQ6IFN0b3J5Ym9va09wdGlvbnMsIGNhbGxiYWNrOiBTdG9yeWJvb2tDYWxsYmFjayA9ICgpID0+ICh7fSkpOiBQcm9taXNlPG51bWJlcj4gPT4ge1xuICBjb25zdCB7Y2xpTmFtZSA9ICdMZXgnLCBjb25maWcsIG9wZW4gPSBmYWxzZSwgcG9ydCA9IDYwMDcsIHF1aWV0LCBzdGF0aWM6IHN0YXRpY0J1aWxkID0gZmFsc2UsIHVzZUxleENvbmZpZyA9IGZhbHNlLCB2YXJpYWJsZXMsIHZlcmJvc2UgPSBmYWxzZX0gPSBjbWQ7XG5cbiAgY29uc3Qgc3Bpbm5lciA9IGNyZWF0ZVNwaW5uZXIocXVpZXQpO1xuXG4gIGxvZyhjaGFsay5jeWFuKGAke2NsaU5hbWV9IHN0YXJ0aW5nIFN0b3J5Ym9vay4uLmApLCAnaW5mbycsIHF1aWV0KTtcblxuICBhd2FpdCBMZXhDb25maWcucGFyc2VDb25maWcoY21kKTtcblxuICBsZXQgdmFyaWFibGVzT2JqOiBvYmplY3QgPSB7Tk9ERV9FTlY6ICdkZXZlbG9wbWVudCd9O1xuXG4gIGlmKHZhcmlhYmxlcykge1xuICAgIHRyeSB7XG4gICAgICB2YXJpYWJsZXNPYmogPSBKU09OLnBhcnNlKHZhcmlhYmxlcyk7XG4gICAgfSBjYXRjaCAoX2Vycm9yKSB7XG4gICAgICBsb2coYFxcbiR7Y2xpTmFtZX0gRXJyb3I6IEVudmlyb25tZW50IHZhcmlhYmxlcyBvcHRpb24gaXMgbm90IGEgdmFsaWQgSlNPTiBvYmplY3QuYCwgJ2Vycm9yJywgcXVpZXQpO1xuICAgICAgY2FsbGJhY2soMSk7XG4gICAgICByZXR1cm4gMTtcbiAgICB9XG4gIH1cblxuICBwcm9jZXNzLmVudiA9IHsuLi5wcm9jZXNzLmVudiwgLi4udmFyaWFibGVzT2JqfTtcblxuICBzcGlubmVyLnN0YXJ0KCdGaW5kaW5nIHN0b3J5IGZpbGVzLi4uJyk7XG4gIGNvbnN0IHN0b3J5RmlsZXMgPSBmaW5kU3RvcnlGaWxlcygpO1xuXG4gIGlmKHN0b3J5RmlsZXMubGVuZ3RoID09PSAwKSB7XG4gICAgc3Bpbm5lci5mYWlsKCdObyBzdG9yeSBmaWxlcyBmb3VuZCBpbiB0aGUgcHJvamVjdC4nKTtcbiAgICBsb2coJ1BsZWFzZSBjcmVhdGUgc3RvcnkgZmlsZXMgd2l0aCAuc3Rvcmllcy50cy8uc3Rvcmllcy5qcyBleHRlbnNpb25zIG9yIGluIGEgc3Rvcmllcy8gZGlyZWN0b3J5LicsICdpbmZvJywgcXVpZXQpO1xuICAgIGNhbGxiYWNrKDEpO1xuICAgIHJldHVybiAxO1xuICB9XG5cbiAgc3Bpbm5lci5zdWNjZWVkKGBGb3VuZCAke3N0b3J5RmlsZXMubGVuZ3RofSBzdG9yeSBmaWxlKHMpYCk7XG5cbiAgY29uc3QgdGFpbHdpbmRDc3NQYXRoID0gZmluZFRhaWx3aW5kQ3NzUGF0aCgpO1xuXG4gIGNvbnNvbGUubG9nKHt0YWlsd2luZENzc1BhdGh9KTtcbiAgaWYodGFpbHdpbmRDc3NQYXRoKSB7XG4gICAgaWYoIXF1aWV0KSB7XG4gICAgICBsb2coY2hhbGsuZ3JlZW4oYFx1MjcxMyBUYWlsd2luZCBDU1MgaW50ZWdyYXRpb24gZGV0ZWN0ZWQ6ICR7dGFpbHdpbmRDc3NQYXRofWApLCAnaW5mbycsIHF1aWV0KTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgaWYoIXF1aWV0KSB7XG4gICAgICBsb2coY2hhbGsueWVsbG93KCdcdTI2QTAgTm8gVGFpbHdpbmQgQ1NTIGZpbGUgZm91bmQgaW4gcHJvamVjdCcpLCAnaW5mbycsIHF1aWV0KTtcbiAgICAgIGxvZyhjaGFsay5ncmF5KCdDcmVhdGUgYSB0YWlsd2luZC5jc3MgZmlsZSB3aXRoIEB0YWlsd2luZCBkaXJlY3RpdmVzIGZvciBmdWxsIFRhaWx3aW5kIHN1cHBvcnQnKSwgJ2luZm8nLCBxdWlldCk7XG4gICAgfVxuICB9XG5cbiAgaWYoIWNoZWNrU3Rvcnlib29rSW5pdGlhbGl6YXRpb24oKSkge1xuICAgIHNwaW5uZXIuZmFpbCgnU3Rvcnlib29rIGlzIG5vdCBpbml0aWFsaXplZCBpbiB0aGlzIHByb2plY3Qgb3IgaW4gTGV4LicpO1xuICAgIGxvZygnUGxlYXNlIHJ1biBcIm5weCBzdG9yeWJvb2tAbGF0ZXN0IGluaXRcIiB0byBzZXQgdXAgU3Rvcnlib29rIGluIHlvdXIgcHJvamVjdCwgb3IgZW5zdXJlIExleCBoYXMgYSB2YWxpZCAuc3Rvcnlib29rIGNvbmZpZ3VyYXRpb24uJywgJ2luZm8nLCBxdWlldCk7XG4gICAgY2FsbGJhY2soMSk7XG4gICAgcmV0dXJuIDE7XG4gIH1cblxuICBjb25zdCBwcm9qZWN0Q29uZmlnRGlyID0gcGF0aFJlc29sdmUocHJvY2Vzcy5jd2QoKSwgJy5zdG9yeWJvb2snKTtcbiAgY29uc3QgbGV4Q29uZmlnRGlyID0gcGF0aFJlc29sdmUoTGV4Q29uZmlnLmdldExleERpcigpLCAnLnN0b3J5Ym9vaycpO1xuXG4gIGxldCBjb25maWdEaXIgPSBjb25maWc7XG4gIGlmKCFjb25maWdEaXIpIHtcbiAgICBjb25maWdEaXIgPSBsZXhDb25maWdEaXI7XG4gICAgaWYoIXVzZUxleENvbmZpZyAmJiBleGlzdHNTeW5jKHByb2plY3RDb25maWdEaXIpKSB7XG4gICAgICBjb25maWdEaXIgPSBwcm9qZWN0Q29uZmlnRGlyO1xuICAgIH1cbiAgfVxuXG4gIGlmKCFxdWlldCkge1xuICAgIGxvZyhjaGFsay5ncmF5KGBQcm9qZWN0IGNvbmZpZyBkaXI6ICR7cHJvamVjdENvbmZpZ0Rpcn0gKGV4aXN0czogJHtleGlzdHNTeW5jKHByb2plY3RDb25maWdEaXIpfSlgKSwgJ2luZm8nLCBxdWlldCk7XG4gICAgbG9nKGNoYWxrLmdyYXkoYExleCBjb25maWcgZGlyOiAke2xleENvbmZpZ0Rpcn0gKGV4aXN0czogJHtleGlzdHNTeW5jKGxleENvbmZpZ0Rpcil9KWApLCAnaW5mbycsIHF1aWV0KTtcbiAgICBpZih1c2VMZXhDb25maWcpIHtcbiAgICAgIGxvZyhjaGFsay5ibHVlKCdVc2luZyBMZXggU3Rvcnlib29rIGNvbmZpZ3VyYXRpb24gKC0tdXNlLWxleC1jb25maWcgZmxhZyknKSwgJ2luZm8nLCBxdWlldCk7XG4gICAgfVxuICAgIGxvZyhjaGFsay5ncmF5KGBJbml0aWFsIGNvbmZpZyBkaXI6ICR7Y29uZmlnRGlyfWApLCAnaW5mbycsIHF1aWV0KTtcbiAgfVxuXG4gIGlmKGNvbmZpZ0RpciA9PT0gbGV4Q29uZmlnRGlyKSB7XG4gICAgaWYoIXF1aWV0KSB7XG4gICAgICBsb2coY2hhbGsuYmx1ZSgnVXNpbmcgTGV4IGNvbmZpZywgd2lsbCBjcmVhdGUgdGVtcG9yYXJ5IGNvbmZpZyBpbiBwcm9qZWN0IC5zdG9yeWJvb2sgZGlyZWN0b3J5JyksICdpbmZvJywgcXVpZXQpO1xuICAgIH1cbiAgICBjb25zdCBwcm9qZWN0U3Rvcnlib29rRGlyID0gcGF0aFJlc29sdmUocHJvY2Vzcy5jd2QoKSwgJy5zdG9yeWJvb2snKTtcblxuICAgIGNvbnN0IGZzID0gYXdhaXQgaW1wb3J0KCdmcy9wcm9taXNlcycpO1xuICAgIGF3YWl0IGZzLm1rZGlyKHByb2plY3RTdG9yeWJvb2tEaXIsIHtyZWN1cnNpdmU6IHRydWV9KTtcblxuICAgIGNvbnN0IGxleE1haW5QYXRoID0gcGF0aFJlc29sdmUobGV4Q29uZmlnRGlyLCAnbWFpbi50cycpO1xuICAgIGNvbnN0IHByb2plY3RNYWluUGF0aCA9IHBhdGhSZXNvbHZlKHByb2plY3RTdG9yeWJvb2tEaXIsICdtYWluLnRzJyk7XG4gICAgbGV0IG1haW5Db250ZW50ID0gYXdhaXQgZnMucmVhZEZpbGUobGV4TWFpblBhdGgsICd1dGY4Jyk7XG5cbiAgICBtYWluQ29udGVudCA9IG1haW5Db250ZW50LnJlcGxhY2UoXG4gICAgICAvc3RvcmllczpcXHMqXFxbLio/XFxdLyxcbiAgICAgIGBzdG9yaWVzOiBbJyR7cGF0aFJlc29sdmUocHJvY2Vzcy5jd2QoKSwgJ3NyYy8qKi8qLnN0b3JpZXMuQCh0c3x0c3gpJyl9JywgJyR7cGF0aFJlc29sdmUocHJvY2Vzcy5jd2QoKSwgJ3NyYy8qKi8qLm1keCcpfSddYFxuICAgICk7XG5cbiAgICBjb25zdCBsZXhOb2RlTW9kdWxlcyA9IHBhdGhSZXNvbHZlKExleENvbmZpZy5nZXRMZXhEaXIoKSwgJ25vZGVfbW9kdWxlcycpO1xuICAgIG1haW5Db250ZW50ID0gbWFpbkNvbnRlbnQucmVwbGFjZShcbiAgICAgIC9jb25zdCBsZXhNb2R1bGUgPSBcXChtb2R1bGVQYXRoOiBzdHJpbmdcXCkgPT4gcmVzb2x2ZVxcKGdldExleE5vZGVNb2R1bGVzUGF0aFxcKFxcKSwgbW9kdWxlUGF0aFxcKTsvLFxuICAgICAgYGNvbnN0IGxleE1vZHVsZSA9IChtb2R1bGVQYXRoOiBzdHJpbmcpID0+IHJlc29sdmUoJyR7bGV4Tm9kZU1vZHVsZXN9JywgbW9kdWxlUGF0aCk7YFxuICAgICk7XG5cbiAgICBhd2FpdCBmcy53cml0ZUZpbGUocHJvamVjdE1haW5QYXRoLCBtYWluQ29udGVudCk7XG5cbiAgICBjb25zdCBsZXhQcmV2aWV3UGF0aCA9IHBhdGhSZXNvbHZlKGxleENvbmZpZ0RpciwgJ3ByZXZpZXcudHN4Jyk7XG4gICAgaWYoZXhpc3RzU3luYyhsZXhQcmV2aWV3UGF0aCkpIHtcbiAgICAgIGNvbnN0IHByZXZpZXdDb250ZW50ID0gYXdhaXQgZnMucmVhZEZpbGUobGV4UHJldmlld1BhdGgsICd1dGY4Jyk7XG4gICAgICBhd2FpdCBmcy53cml0ZUZpbGUocGF0aFJlc29sdmUocHJvamVjdFN0b3J5Ym9va0RpciwgJ3ByZXZpZXcudHN4JyksIHByZXZpZXdDb250ZW50KTtcbiAgICB9XG5cbiAgICBjb25maWdEaXIgPSBwcm9qZWN0U3Rvcnlib29rRGlyO1xuICB9XG4gIGlmKCFleGlzdHNTeW5jKGNvbmZpZ0RpcikpIHtcbiAgICBzcGlubmVyLmZhaWwoJ1N0b3J5Ym9vayBjb25maWd1cmF0aW9uIG5vdCBmb3VuZC4nKTtcbiAgICBsb2coYFByb2plY3QgY29uZmlnOiAke3Byb2plY3RDb25maWdEaXJ9YCwgJ2luZm8nLCBxdWlldCk7XG4gICAgbG9nKGBMZXggY29uZmlnOiAke2xleENvbmZpZ0Rpcn1gLCAnaW5mbycsIHF1aWV0KTtcbiAgICBsb2coJ1BsZWFzZSBydW4gXCJucHggc3Rvcnlib29rQGxhdGVzdCBpbml0XCIgdG8gc2V0IHVwIFN0b3J5Ym9vayBpbiB5b3VyIHByb2plY3QsIG9yIGVuc3VyZSBMZXggaGFzIGEgdmFsaWQgLnN0b3J5Ym9vayBjb25maWd1cmF0aW9uLicsICdpbmZvJywgcXVpZXQpO1xuICAgIGNhbGxiYWNrKDEpO1xuICAgIHJldHVybiAxO1xuICB9XG5cbiAgY29uc3Qgc3Rvcnlib29rUGF0aCA9IHJlc29sdmVCaW5hcnlQYXRoKCdzdG9yeWJvb2snKTtcblxuICBpZighc3Rvcnlib29rUGF0aCkge1xuICAgIGxvZyhgXFxuJHtjbGlOYW1lfSBFcnJvcjogc3Rvcnlib29rIGJpbmFyeSBub3QgZm91bmQgaW4gTGV4J3Mgbm9kZV9tb2R1bGVzIG9yIG1vbm9yZXBvIHJvb3RgLCAnZXJyb3InLCBxdWlldCk7XG4gICAgbG9nKCdQbGVhc2UgcmVpbnN0YWxsIExleCBvciBjaGVjayB5b3VyIFN0b3J5Ym9vayBpbnN0YWxsYXRpb24uJywgJ2luZm8nLCBxdWlldCk7XG4gICAgY2FsbGJhY2soMSk7XG4gICAgcmV0dXJuIDE7XG4gIH1cblxuICBjb25zdCBzdG9yeWJvb2tBcmdzID0gW3N0YXRpY0J1aWxkID8gJ2J1aWxkJyA6ICdkZXYnXTtcbiAgc3Rvcnlib29rQXJncy5wdXNoKCctLWNvbmZpZy1kaXInLCBjb25maWdEaXIpO1xuXG4gIGlmKHBvcnQpIHtcbiAgICBzdG9yeWJvb2tBcmdzLnB1c2goJy0tcG9ydCcsIHBvcnQudG9TdHJpbmcoKSk7XG4gIH1cblxuICBpZihvcGVuKSB7XG4gICAgc3Rvcnlib29rQXJncy5wdXNoKCctLW9wZW4nKTtcbiAgfVxuXG4gIGlmKHN0YXRpY0J1aWxkKSB7XG4gICAgY29uc3Qgb3V0cHV0RGlyID0gcGF0aFJlc29sdmUocHJvY2Vzcy5jd2QoKSwgJ3N0b3J5Ym9vay1zdGF0aWMnKTtcbiAgICBzdG9yeWJvb2tBcmdzLnB1c2goJy0tb3V0cHV0LWRpcicsIG91dHB1dERpcik7XG4gIH1cblxuICBpZighcXVpZXQpIHtcbiAgICBsb2coY2hhbGsuZ3JheShgQ29uZmlnIGRpcmVjdG9yeTogJHtjb25maWdEaXJ9YCksICdpbmZvJywgcXVpZXQpO1xuICB9XG5cbiAgcHJvY2Vzcy5lbnYuVEFJTFdJTkRfQ1NTX1BBVEggPSB0YWlsd2luZENzc1BhdGg7XG5cbiAgdHJ5IHtcbiAgICBzcGlubmVyLnN0YXJ0KHN0YXRpY0J1aWxkID8gJ0J1aWxkaW5nIHN0YXRpYyBTdG9yeWJvb2suLi4nIDogJ1N0YXJ0aW5nIFN0b3J5Ym9vayBkZXZlbG9wbWVudCBzZXJ2ZXIuLi4nKTtcblxuICAgIGNvbnN0IHN0b3J5Ym9va1Byb2Nlc3MgPSBleGVjYShzdG9yeWJvb2tQYXRoIGFzIGFueSwgc3Rvcnlib29rQXJncywge1xuICAgICAgZW5jb2Rpbmc6ICd1dGY4JyxcbiAgICAgIGVudjoge1xuICAgICAgICAuLi5wcm9jZXNzLmVudixcbiAgICAgICAgTEVYX1FVSUVUOiBxdWlldCxcbiAgICAgICAgTEVYX1ZFUkJPU0U6IHZlcmJvc2UsXG4gICAgICAgIFNUT1JZQk9PS19PUEVOOiBvcGVuLFxuICAgICAgICAuLi4odGFpbHdpbmRDc3NQYXRoICYmIHtUQUlMV0lORF9DU1NfUEFUSDogdGFpbHdpbmRDc3NQYXRofSlcbiAgICAgIH0gYXMgYW55LFxuICAgICAgc3RkaW86ICdwaXBlJ1xuICAgIH0pO1xuXG4gICAgbGV0IHVybEZvdW5kID0gZmFsc2U7XG4gICAgbGV0IGxhc3RQcm9ncmVzc1BlcmNlbnRhZ2UgPSAwO1xuXG4gICAgc3Rvcnlib29rUHJvY2Vzcy5zdGRvdXQ/Lm9uKCdkYXRhJywgKGRhdGEpID0+IHtcbiAgICAgIGNvbnN0IG91dHB1dCA9IGRhdGEudG9TdHJpbmcoKTtcbiAgICAgIGNvbnN0IHByb2dyZXNzUGVyY2VudGFnZSA9IGV4dHJhY3RQcm9ncmVzc1BlcmNlbnRhZ2Uob3V0cHV0KTtcblxuICAgICAgaWYocHJvZ3Jlc3NQZXJjZW50YWdlICE9PSBudWxsICYmIHByb2dyZXNzUGVyY2VudGFnZSAhPT0gbGFzdFByb2dyZXNzUGVyY2VudGFnZSkge1xuICAgICAgICBsYXN0UHJvZ3Jlc3NQZXJjZW50YWdlID0gcHJvZ3Jlc3NQZXJjZW50YWdlO1xuICAgICAgICBjb25zdCBhY3Rpb24gPSBzdGF0aWNCdWlsZCA/ICdCdWlsZGluZycgOiAnU3RhcnRpbmcnO1xuICAgICAgICAoc3Bpbm5lciBhcyBhbnkpLnRleHQgPSBgJHthY3Rpb259IFN0b3J5Ym9vay4uLiAke3Byb2dyZXNzUGVyY2VudGFnZX0lYDtcbiAgICAgICAgcHJvY2Vzcy5zdGRvdXQud3JpdGUoYFxcbldlYnBhY2sgUHJvZ3Jlc3M6ICR7Y2hhbGsubWFnZW50YShgJHtwcm9ncmVzc1BlcmNlbnRhZ2V9JWApfVxcbmApO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBmaWx0ZXJlZE91dHB1dCA9IGZpbHRlckFuZEJlYXV0aWZ5T3V0cHV0KG91dHB1dCwgdmVyYm9zZSk7XG4gICAgICBjb25zdCBiZWF1dGlmaWVkT3V0cHV0ID0gYmVhdXRpZnlPdXRwdXQoZmlsdGVyZWRPdXRwdXQpO1xuXG4gICAgICBpZighdXJsRm91bmQgJiYgKG91dHB1dC5pbmNsdWRlcygnTG9jYWw6JykgfHwgb3V0cHV0LmluY2x1ZGVzKCdodHRwOi8vbG9jYWxob3N0JykgfHwgb3V0cHV0LmluY2x1ZGVzKCdTdG9yeWJvb2snKSkpIHtcbiAgICAgICAgc3Bpbm5lci5zdWNjZWVkKGNoYWxrLmdyZWVuKCdTdG9yeWJvb2sgZGV2ZWxvcG1lbnQgc2VydmVyIGlzIHJlYWR5IScpKTtcbiAgICAgICAgdXJsRm91bmQgPSB0cnVlO1xuICAgICAgfVxuXG4gICAgICBpZihmaWx0ZXJlZE91dHB1dC50cmltKCkpIHtcbiAgICAgICAgcHJvY2Vzcy5zdGRvdXQud3JpdGUoYmVhdXRpZmllZE91dHB1dCk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBzdG9yeWJvb2tQcm9jZXNzLnN0ZGVycj8ub24oJ2RhdGEnLCAoZGF0YSkgPT4ge1xuICAgICAgY29uc3Qgb3V0cHV0ID0gZGF0YS50b1N0cmluZygpO1xuICAgICAgY29uc3QgZmlsdGVyZWRPdXRwdXQgPSBmaWx0ZXJBbmRCZWF1dGlmeU91dHB1dChvdXRwdXQsIHZlcmJvc2UpO1xuICAgICAgY29uc3QgYmVhdXRpZmllZE91dHB1dCA9IGJlYXV0aWZ5T3V0cHV0KGZpbHRlcmVkT3V0cHV0KTtcblxuICAgICAgaWYoZmlsdGVyZWRPdXRwdXQudHJpbSgpKSB7XG4gICAgICAgIHByb2Nlc3Muc3RkZXJyLndyaXRlKGJlYXV0aWZpZWRPdXRwdXQpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHN0b3J5Ym9va1Byb2Nlc3M7XG4gICAgICBpZighdXJsRm91bmQpIHtcbiAgICAgICAgc3Bpbm5lci5zdWNjZWVkKGNoYWxrLmdyZWVuKCdTdG9yeWJvb2sgZGV2ZWxvcG1lbnQgc2VydmVyIHN0YXJ0ZWQuJykpO1xuICAgICAgfVxuICAgICAgY2FsbGJhY2soMCk7XG4gICAgICByZXR1cm4gMDtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgc3Bpbm5lci5mYWlsKGNoYWxrLnJlZCgnVGhlcmUgd2FzIGFuIGVycm9yIHdoaWxlIHJ1bm5pbmcgc3Rvcnlib29rLicpKTtcbiAgICAgIGxvZyhgXFxuJHtjbGlOYW1lfSBFcnJvcjogJHtlcnJvci5tZXNzYWdlfWAsICdlcnJvcicsIHF1aWV0KTtcbiAgICAgIGNhbGxiYWNrKDEpO1xuICAgICAgcmV0dXJuIDE7XG4gICAgfVxuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGxvZyhgXFxuJHtjbGlOYW1lfSBFcnJvcjogJHtlcnJvci5tZXNzYWdlfWAsICdlcnJvcicsIHF1aWV0KTtcbiAgICBzcGlubmVyLmZhaWwoJ1RoZXJlIHdhcyBhbiBlcnJvciB3aGlsZSBydW5uaW5nIHN0b3J5Ym9vay4nKTtcbiAgICBjYWxsYmFjaygxKTtcbiAgICByZXR1cm4gMTtcbiAgfVxufTsiXSwKICAibWFwcGluZ3MiOiAiQUFBQSxPQUFPLFdBQVc7QUFDbEIsU0FBUSxhQUFZO0FBQ3BCLFNBQVEsa0JBQWlCO0FBQ3pCLFNBQVEsUUFBUSxnQkFBZTtBQUMvQixTQUFRLFdBQVcsbUJBQWtCO0FBRXJDLFNBQVEsaUJBQWdCO0FBQ3hCLFNBQVEscUJBQW9CO0FBQzVCLFNBQVEscUJBQXFCLHlCQUF3QjtBQUNyRCxTQUFRLFdBQVU7QUFnQmxCLE1BQU0saUJBQWlCLE1BQWdCO0FBQ3JDLFFBQU0sZ0JBQWdCO0FBQUEsSUFDcEI7QUFBQSxJQUNBO0FBQUEsSUFDQTtBQUFBLEVBQ0Y7QUFFQSxRQUFNLGFBQXVCLENBQUM7QUFFOUIsZ0JBQWMsUUFBUSxDQUFDLFlBQVk7QUFDakMsVUFBTSxRQUFRLFNBQVMsU0FBUztBQUFBLE1BQzlCLEtBQUssUUFBUSxJQUFJO0FBQUEsTUFDakIsUUFBUSxD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