uilint 0.2.30 → 0.2.31

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.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/utils/package-manager.ts
4
- import { existsSync } from "fs";
4
+ import { existsSync, readFileSync } from "fs";
5
5
  import { spawn } from "child_process";
6
6
  import { dirname, join } from "path";
7
7
  function detectPackageManager(projectPath) {
@@ -65,28 +65,73 @@ ${snippet}
65
65
  });
66
66
  });
67
67
  }
68
+ function getInstalledPackages(projectPath) {
69
+ const pkgJsonPath = join(projectPath, "package.json");
70
+ if (!existsSync(pkgJsonPath)) {
71
+ return /* @__PURE__ */ new Set();
72
+ }
73
+ try {
74
+ const pkgJson = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
75
+ const installed = /* @__PURE__ */ new Set();
76
+ if (pkgJson.dependencies) {
77
+ for (const name of Object.keys(pkgJson.dependencies)) {
78
+ installed.add(name);
79
+ }
80
+ }
81
+ if (pkgJson.devDependencies) {
82
+ for (const name of Object.keys(pkgJson.devDependencies)) {
83
+ installed.add(name);
84
+ }
85
+ }
86
+ return installed;
87
+ } catch {
88
+ return /* @__PURE__ */ new Set();
89
+ }
90
+ }
91
+ function getPackageName(specifier) {
92
+ if (specifier.startsWith("@")) {
93
+ const slashIndex = specifier.indexOf("/");
94
+ if (slashIndex === -1) return specifier;
95
+ const afterSlash = specifier.slice(slashIndex + 1);
96
+ const atIndex2 = afterSlash.indexOf("@");
97
+ if (atIndex2 === -1) return specifier;
98
+ return specifier.slice(0, slashIndex + 1 + atIndex2);
99
+ }
100
+ const atIndex = specifier.indexOf("@");
101
+ if (atIndex === -1) return specifier;
102
+ return specifier.slice(0, atIndex);
103
+ }
104
+ function filterAlreadyInstalled(packages, projectPath) {
105
+ const installed = getInstalledPackages(projectPath);
106
+ return packages.filter((pkg) => {
107
+ const name = getPackageName(pkg);
108
+ return !installed.has(name);
109
+ });
110
+ }
68
111
  async function installDependencies(pm, projectPath, packages, options = { dev: true }) {
69
112
  if (!packages.length) return;
113
+ const packagesToInstall = filterAlreadyInstalled(packages, projectPath);
114
+ if (!packagesToInstall.length) return;
70
115
  const isDev = options.dev ?? true;
71
116
  switch (pm) {
72
117
  case "pnpm":
73
118
  await spawnAsync(
74
119
  "pnpm",
75
- ["add", ...isDev ? ["-D"] : [], ...packages],
120
+ ["add", ...isDev ? ["-D"] : [], ...packagesToInstall],
76
121
  projectPath
77
122
  );
78
123
  return;
79
124
  case "yarn":
80
125
  await spawnAsync(
81
126
  "yarn",
82
- ["add", ...isDev ? ["-D"] : [], ...packages],
127
+ ["add", ...isDev ? ["-D"] : [], ...packagesToInstall],
83
128
  projectPath
84
129
  );
85
130
  return;
86
131
  case "bun":
87
132
  await spawnAsync(
88
133
  "bun",
89
- ["add", ...isDev ? ["-d"] : [], ...packages],
134
+ ["add", ...isDev ? ["-d"] : [], ...packagesToInstall],
90
135
  projectPath
91
136
  );
92
137
  return;
@@ -94,7 +139,7 @@ async function installDependencies(pm, projectPath, packages, options = { dev: t
94
139
  default:
95
140
  await spawnAsync(
96
141
  "npm",
97
- ["install", isDev ? "--save-dev" : "--save", ...packages],
142
+ ["install", isDev ? "--save-dev" : "--save", ...packagesToInstall],
98
143
  projectPath
99
144
  );
100
145
  return;
@@ -123,4 +168,4 @@ export {
123
168
  installDependencies,
124
169
  runTestsWithCoverage
125
170
  };
126
- //# sourceMappingURL=chunk-P4I4RKBY.js.map
171
+ //# sourceMappingURL=chunk-OTU5FY6B.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/package-manager.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"fs\";\nimport { spawn } from \"child_process\";\nimport { dirname, join } from \"path\";\n\nexport type PackageManager = \"pnpm\" | \"yarn\" | \"npm\" | \"bun\";\n\n/**\n * Detect which package manager a project uses by looking for lockfiles.\n * Walks up the directory tree to support monorepos.\n */\nexport function detectPackageManager(projectPath: string): PackageManager {\n // Monorepo-friendly detection: walk up to find the lockfile/workspace marker.\n let dir = projectPath;\n for (;;) {\n // pnpm\n if (existsSync(join(dir, \"pnpm-lock.yaml\"))) return \"pnpm\";\n if (existsSync(join(dir, \"pnpm-workspace.yaml\"))) return \"pnpm\";\n\n // yarn\n if (existsSync(join(dir, \"yarn.lock\"))) return \"yarn\";\n\n // bun\n if (existsSync(join(dir, \"bun.lockb\"))) return \"bun\";\n if (existsSync(join(dir, \"bun.lock\"))) return \"bun\";\n\n // npm\n if (existsSync(join(dir, \"package-lock.json\"))) return \"npm\";\n\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n\n // Default: npm (best-effort)\n return \"npm\";\n}\n\nfunction spawnAsync(\n command: string,\n args: string[],\n cwd: string\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n cwd,\n // Capture output so we can surface it in installer summaries, while still\n // streaming to the user for a good UX.\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n shell: process.platform === \"win32\",\n });\n\n const stdoutChunks: Buffer[] = [];\n const stderrChunks: Buffer[] = [];\n const MAX_CAPTURE = 64 * 1024; // keep last 64KB per stream\n\n child.stdout?.on(\"data\", (chunk: Buffer) => {\n process.stdout.write(chunk);\n stdoutChunks.push(chunk);\n // keep bounded\n while (Buffer.concat(stdoutChunks).length > MAX_CAPTURE) stdoutChunks.shift();\n });\n child.stderr?.on(\"data\", (chunk: Buffer) => {\n process.stderr.write(chunk);\n stderrChunks.push(chunk);\n while (Buffer.concat(stderrChunks).length > MAX_CAPTURE) stderrChunks.shift();\n });\n\n child.on(\"error\", (err) => {\n reject(err);\n });\n\n child.on(\"close\", (code) => {\n if (code === 0) {\n resolve();\n return;\n }\n\n const cmd = `${command} ${args.join(\" \")}`.trim();\n const stdout = Buffer.concat(stdoutChunks).toString(\"utf-8\").trim();\n const stderr = Buffer.concat(stderrChunks).toString(\"utf-8\").trim();\n const snippet = (stderr || stdout).trim();\n\n reject(\n new Error(\n `${cmd} exited with ${code}${\n snippet ? `\\n\\n--- output ---\\n${snippet}\\n--- end output ---` : \"\"\n }`\n )\n );\n });\n });\n}\n\n/**\n * Get the set of packages already installed in a project\n * (both dependencies and devDependencies)\n */\nfunction getInstalledPackages(projectPath: string): Set<string> {\n const pkgJsonPath = join(projectPath, \"package.json\");\n if (!existsSync(pkgJsonPath)) {\n return new Set();\n }\n\n try {\n const pkgJson = JSON.parse(readFileSync(pkgJsonPath, \"utf-8\")) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n\n const installed = new Set<string>();\n if (pkgJson.dependencies) {\n for (const name of Object.keys(pkgJson.dependencies)) {\n installed.add(name);\n }\n }\n if (pkgJson.devDependencies) {\n for (const name of Object.keys(pkgJson.devDependencies)) {\n installed.add(name);\n }\n }\n return installed;\n } catch {\n return new Set();\n }\n}\n\n/**\n * Extract package name from a package specifier (e.g., \"foo@^1.0.0\" -> \"foo\")\n */\nfunction getPackageName(specifier: string): string {\n // Handle scoped packages like @scope/pkg@version\n if (specifier.startsWith(\"@\")) {\n const slashIndex = specifier.indexOf(\"/\");\n if (slashIndex === -1) return specifier;\n\n const afterSlash = specifier.slice(slashIndex + 1);\n const atIndex = afterSlash.indexOf(\"@\");\n if (atIndex === -1) return specifier;\n return specifier.slice(0, slashIndex + 1 + atIndex);\n }\n\n // Handle unscoped packages like pkg@version\n const atIndex = specifier.indexOf(\"@\");\n if (atIndex === -1) return specifier;\n return specifier.slice(0, atIndex);\n}\n\n/**\n * Filter out packages that are already installed\n */\nfunction filterAlreadyInstalled(\n packages: string[],\n projectPath: string\n): string[] {\n const installed = getInstalledPackages(projectPath);\n return packages.filter((pkg) => {\n const name = getPackageName(pkg);\n return !installed.has(name);\n });\n}\n\nexport async function installDependencies(\n pm: PackageManager,\n projectPath: string,\n packages: string[],\n options: { dev?: boolean } = { dev: true }\n): Promise<void> {\n if (!packages.length) return;\n\n // Filter out packages that are already installed to avoid yarn/npm errors\n // when trying to add a regular dependency as a dev dependency or vice versa\n const packagesToInstall = filterAlreadyInstalled(packages, projectPath);\n if (!packagesToInstall.length) return;\n\n const isDev = options.dev ?? true;\n\n switch (pm) {\n case \"pnpm\":\n await spawnAsync(\n \"pnpm\",\n [\"add\", ...(isDev ? [\"-D\"] : []), ...packagesToInstall],\n projectPath\n );\n return;\n case \"yarn\":\n await spawnAsync(\n \"yarn\",\n [\"add\", ...(isDev ? [\"-D\"] : []), ...packagesToInstall],\n projectPath\n );\n return;\n case \"bun\":\n await spawnAsync(\n \"bun\",\n [\"add\", ...(isDev ? [\"-d\"] : []), ...packagesToInstall],\n projectPath\n );\n return;\n case \"npm\":\n default:\n await spawnAsync(\n \"npm\",\n [\"install\", isDev ? \"--save-dev\" : \"--save\", ...packagesToInstall],\n projectPath\n );\n return;\n }\n}\n\n/**\n * Get the command and arguments to run tests with coverage\n */\nexport function getTestCoverageCommand(pm: PackageManager): {\n command: string;\n args: string[];\n} {\n switch (pm) {\n case \"pnpm\":\n return { command: \"pnpm\", args: [\"test\", \"--\", \"--coverage\"] };\n case \"yarn\":\n return { command: \"yarn\", args: [\"test\", \"--coverage\"] };\n case \"bun\":\n return { command: \"bun\", args: [\"test\", \"--coverage\"] };\n case \"npm\":\n default:\n return { command: \"npm\", args: [\"test\", \"--\", \"--coverage\"] };\n }\n}\n\n/**\n * Run tests with coverage for a project\n */\nexport async function runTestsWithCoverage(\n pm: PackageManager,\n projectPath: string\n): Promise<void> {\n const { command, args } = getTestCoverageCommand(pm);\n await spawnAsync(command, args, projectPath);\n}\n"],"mappings":"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","names":["atIndex"]}
@@ -3,7 +3,7 @@ import {
3
3
  detectPackageManager,
4
4
  installDependencies,
5
5
  runTestsWithCoverage
6
- } from "./chunk-P4I4RKBY.js";
6
+ } from "./chunk-OTU5FY6B.js";
7
7
 
8
8
  // src/utils/prompts.ts
9
9
  import * as p from "@clack/prompts";
@@ -1225,4 +1225,4 @@ export {
1225
1225
  prepareCoverage,
1226
1226
  needsCoveragePreparation
1227
1227
  };
1228
- //# sourceMappingURL=chunk-NAO64XXO.js.map
1228
+ //# sourceMappingURL=chunk-W6X3RNOE.js.map
package/dist/index.js CHANGED
@@ -19,8 +19,8 @@ import {
19
19
  updateRuleConfigInConfig,
20
20
  updateRuleSeverityInConfig,
21
21
  withSpinner
22
- } from "./chunk-NAO64XXO.js";
23
- import "./chunk-P4I4RKBY.js";
22
+ } from "./chunk-W6X3RNOE.js";
23
+ import "./chunk-OTU5FY6B.js";
24
24
 
25
25
  // src/index.ts
26
26
  import { Command as Command6 } from "commander";
@@ -3643,7 +3643,7 @@ program.command("update").description("Update existing style guide with new styl
3643
3643
  });
3644
3644
  });
3645
3645
  program.command("install").description("Install UILint integration").option("--force", "Overwrite existing configuration files").action(async (options) => {
3646
- const { installUI } = await import("./install-ui-UPHDMZWG.js");
3646
+ const { installUI } = await import("./install-ui-ZXMZNRU2.js");
3647
3647
  await installUI({ force: options.force });
3648
3648
  });
3649
3649
  program.command("serve").description("Start WebSocket server for real-time UI linting").option("-p, --port <number>", "Port to listen on", "9234").action(async (options) => {
@@ -15,7 +15,7 @@ import {
15
15
  pc,
16
16
  select,
17
17
  uninstallEslintPlugin
18
- } from "./chunk-NAO64XXO.js";
18
+ } from "./chunk-W6X3RNOE.js";
19
19
  import {
20
20
  GENSTYLEGUIDE_COMMAND_MD,
21
21
  loadSkill,
@@ -25,7 +25,7 @@ import {
25
25
  detectPackageManager,
26
26
  installDependencies,
27
27
  runTestsWithCoverage
28
- } from "./chunk-P4I4RKBY.js";
28
+ } from "./chunk-OTU5FY6B.js";
29
29
 
30
30
  // src/commands/install-ui.tsx
31
31
  import { render } from "ink";
@@ -4750,7 +4750,7 @@ async function installUI(options = {}, executeOptions = {}) {
4750
4750
  console.log("\nNo changes selected");
4751
4751
  process.exit(0);
4752
4752
  }
4753
- const { createPlan } = await import("./plan-QAONO66T.js");
4753
+ const { createPlan } = await import("./plan-E7ZMQPPE.js");
4754
4754
  const plan = createPlan(project, choices, { force: options.force });
4755
4755
  if (hasUninstalls && uninstallSelections) {
4756
4756
  for (const selection of uninstallSelections) {
@@ -4802,4 +4802,4 @@ ${pc.blue("Running tests with coverage...")}`);
4802
4802
  export {
4803
4803
  installUI
4804
4804
  };
4805
- //# sourceMappingURL=install-ui-UPHDMZWG.js.map
4805
+ //# sourceMappingURL=install-ui-ZXMZNRU2.js.map
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-TWUDB36F.js";
7
7
  import {
8
8
  detectPackageManager
9
- } from "./chunk-P4I4RKBY.js";
9
+ } from "./chunk-OTU5FY6B.js";
10
10
 
11
11
  // src/commands/install/plan.ts
12
12
  import { join as join2 } from "path";
@@ -478,4 +478,4 @@ export {
478
478
  createPlan,
479
479
  getMissingRules
480
480
  };
481
- //# sourceMappingURL=plan-QAONO66T.js.map
481
+ //# sourceMappingURL=plan-E7ZMQPPE.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uilint",
3
- "version": "0.2.30",
3
+ "version": "0.2.31",
4
4
  "description": "CLI for UILint - AI-powered UI consistency checking",
5
5
  "author": "Peter Suggate",
6
6
  "repository": {
@@ -48,9 +48,9 @@
48
48
  "react": "^19.2.3",
49
49
  "typescript": "^5.9.3",
50
50
  "ws": "^8.19.0",
51
- "uilint-core": "0.2.30",
52
- "uilint-eslint": "0.2.30",
53
- "uilint-duplicates": "0.2.30"
51
+ "uilint-core": "0.2.31",
52
+ "uilint-duplicates": "0.2.31",
53
+ "uilint-eslint": "0.2.31"
54
54
  },
55
55
  "optionalDependencies": {
56
56
  "@langfuse/client": "^4.5.1",
@@ -66,7 +66,7 @@
66
66
  "ink-testing-library": "^4.0.0",
67
67
  "tsup": "^8.5.1",
68
68
  "vitest": "^4.0.17",
69
- "uilint-react": "0.2.30"
69
+ "uilint-react": "0.2.31"
70
70
  },
71
71
  "keywords": [
72
72
  "cli",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/package-manager.ts"],"sourcesContent":["import { existsSync } from \"fs\";\nimport { spawn } from \"child_process\";\nimport { dirname, join } from \"path\";\n\nexport type PackageManager = \"pnpm\" | \"yarn\" | \"npm\" | \"bun\";\n\n/**\n * Detect which package manager a project uses by looking for lockfiles.\n * Walks up the directory tree to support monorepos.\n */\nexport function detectPackageManager(projectPath: string): PackageManager {\n // Monorepo-friendly detection: walk up to find the lockfile/workspace marker.\n let dir = projectPath;\n for (;;) {\n // pnpm\n if (existsSync(join(dir, \"pnpm-lock.yaml\"))) return \"pnpm\";\n if (existsSync(join(dir, \"pnpm-workspace.yaml\"))) return \"pnpm\";\n\n // yarn\n if (existsSync(join(dir, \"yarn.lock\"))) return \"yarn\";\n\n // bun\n if (existsSync(join(dir, \"bun.lockb\"))) return \"bun\";\n if (existsSync(join(dir, \"bun.lock\"))) return \"bun\";\n\n // npm\n if (existsSync(join(dir, \"package-lock.json\"))) return \"npm\";\n\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n\n // Default: npm (best-effort)\n return \"npm\";\n}\n\nfunction spawnAsync(\n command: string,\n args: string[],\n cwd: string\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n cwd,\n // Capture output so we can surface it in installer summaries, while still\n // streaming to the user for a good UX.\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n shell: process.platform === \"win32\",\n });\n\n const stdoutChunks: Buffer[] = [];\n const stderrChunks: Buffer[] = [];\n const MAX_CAPTURE = 64 * 1024; // keep last 64KB per stream\n\n child.stdout?.on(\"data\", (chunk: Buffer) => {\n process.stdout.write(chunk);\n stdoutChunks.push(chunk);\n // keep bounded\n while (Buffer.concat(stdoutChunks).length > MAX_CAPTURE) stdoutChunks.shift();\n });\n child.stderr?.on(\"data\", (chunk: Buffer) => {\n process.stderr.write(chunk);\n stderrChunks.push(chunk);\n while (Buffer.concat(stderrChunks).length > MAX_CAPTURE) stderrChunks.shift();\n });\n\n child.on(\"error\", (err) => {\n reject(err);\n });\n\n child.on(\"close\", (code) => {\n if (code === 0) {\n resolve();\n return;\n }\n\n const cmd = `${command} ${args.join(\" \")}`.trim();\n const stdout = Buffer.concat(stdoutChunks).toString(\"utf-8\").trim();\n const stderr = Buffer.concat(stderrChunks).toString(\"utf-8\").trim();\n const snippet = (stderr || stdout).trim();\n\n reject(\n new Error(\n `${cmd} exited with ${code}${\n snippet ? `\\n\\n--- output ---\\n${snippet}\\n--- end output ---` : \"\"\n }`\n )\n );\n });\n });\n}\n\nexport async function installDependencies(\n pm: PackageManager,\n projectPath: string,\n packages: string[],\n options: { dev?: boolean } = { dev: true }\n): Promise<void> {\n if (!packages.length) return;\n\n const isDev = options.dev ?? true;\n\n switch (pm) {\n case \"pnpm\":\n await spawnAsync(\n \"pnpm\",\n [\"add\", ...(isDev ? [\"-D\"] : []), ...packages],\n projectPath\n );\n return;\n case \"yarn\":\n await spawnAsync(\n \"yarn\",\n [\"add\", ...(isDev ? [\"-D\"] : []), ...packages],\n projectPath\n );\n return;\n case \"bun\":\n await spawnAsync(\n \"bun\",\n [\"add\", ...(isDev ? [\"-d\"] : []), ...packages],\n projectPath\n );\n return;\n case \"npm\":\n default:\n await spawnAsync(\n \"npm\",\n [\"install\", isDev ? \"--save-dev\" : \"--save\", ...packages],\n projectPath\n );\n return;\n }\n}\n\n/**\n * Get the command and arguments to run tests with coverage\n */\nexport function getTestCoverageCommand(pm: PackageManager): {\n command: string;\n args: string[];\n} {\n switch (pm) {\n case \"pnpm\":\n return { command: \"pnpm\", args: [\"test\", \"--\", \"--coverage\"] };\n case \"yarn\":\n return { command: \"yarn\", args: [\"test\", \"--coverage\"] };\n case \"bun\":\n return { command: \"bun\", args: [\"test\", \"--coverage\"] };\n case \"npm\":\n default:\n return { command: \"npm\", args: [\"test\", \"--\", \"--coverage\"] };\n }\n}\n\n/**\n * Run tests with coverage for a project\n */\nexport async function runTestsWithCoverage(\n pm: PackageManager,\n projectPath: string\n): Promise<void> {\n const { command, args } = getTestCoverageCommand(pm);\n await spawnAsync(command, args, projectPath);\n}\n"],"mappings":";;;AAAA,SAAS,kBAAkB;AAC3B,SAAS,aAAa;AACtB,SAAS,SAAS,YAAY;AAQvB,SAAS,qBAAqB,aAAqC;AAExE,MAAI,MAAM;AACV,aAAS;AAEP,QAAI,WAAW,KAAK,KAAK,gBAAgB,CAAC,EAAG,QAAO;AACpD,QAAI,WAAW,KAAK,KAAK,qBAAqB,CAAC,EAAG,QAAO;AAGzD,QAAI,WAAW,KAAK,KAAK,WAAW,CAAC,EAAG,QAAO;AAG/C,QAAI,WAAW,KAAK,KAAK,WAAW,CAAC,EAAG,QAAO;AAC/C,QAAI,WAAW,KAAK,KAAK,UAAU,CAAC,EAAG,QAAO;AAG9C,QAAI,WAAW,KAAK,KAAK,mBAAmB,CAAC,EAAG,QAAO;AAEvD,UAAM,SAAS,QAAQ,GAAG;AAC1B,QAAI,WAAW,IAAK;AACpB,UAAM;AAAA,EACR;AAGA,SAAO;AACT;AAEA,SAAS,WACP,SACA,MACA,KACe;AACf,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,QAAQ,MAAM,SAAS,MAAM;AAAA,MACjC;AAAA;AAAA;AAAA,MAGA,OAAO,CAAC,UAAU,QAAQ,MAAM;AAAA,MAChC,OAAO,QAAQ,aAAa;AAAA,IAC9B,CAAC;AAED,UAAM,eAAyB,CAAC;AAChC,UAAM,eAAyB,CAAC;AAChC,UAAM,cAAc,KAAK;AAEzB,UAAM,QAAQ,GAAG,QAAQ,CAAC,UAAkB;AAC1C,cAAQ,OAAO,MAAM,KAAK;AAC1B,mBAAa,KAAK,KAAK;AAEvB,aAAO,OAAO,OAAO,YAAY,EAAE,SAAS,YAAa,cAAa,MAAM;AAAA,IAC9E,CAAC;AACD,UAAM,QAAQ,GAAG,QAAQ,CAAC,UAAkB;AAC1C,cAAQ,OAAO,MAAM,KAAK;AAC1B,mBAAa,KAAK,KAAK;AACvB,aAAO,OAAO,OAAO,YAAY,EAAE,SAAS,YAAa,cAAa,MAAM;AAAA,IAC9E,CAAC;AAED,UAAM,GAAG,SAAS,CAAC,QAAQ;AACzB,aAAO,GAAG;AAAA,IACZ,CAAC;AAED,UAAM,GAAG,SAAS,CAAC,SAAS;AAC1B,UAAI,SAAS,GAAG;AACd,gBAAQ;AACR;AAAA,MACF;AAEA,YAAM,MAAM,GAAG,OAAO,IAAI,KAAK,KAAK,GAAG,CAAC,GAAG,KAAK;AAChD,YAAM,SAAS,OAAO,OAAO,YAAY,EAAE,SAAS,OAAO,EAAE,KAAK;AAClE,YAAM,SAAS,OAAO,OAAO,YAAY,EAAE,SAAS,OAAO,EAAE,KAAK;AAClE,YAAM,WAAW,UAAU,QAAQ,KAAK;AAExC;AAAA,QACE,IAAI;AAAA,UACF,GAAG,GAAG,gBAAgB,IAAI,GACxB,UAAU;AAAA;AAAA;AAAA,EAAuB,OAAO;AAAA,sBAAyB,EACnE;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;AAEA,eAAsB,oBACpB,IACA,aACA,UACA,UAA6B,EAAE,KAAK,KAAK,GAC1B;AACf,MAAI,CAAC,SAAS,OAAQ;AAEtB,QAAM,QAAQ,QAAQ,OAAO;AAE7B,UAAQ,IAAI;AAAA,IACV,KAAK;AACH,YAAM;AAAA,QACJ;AAAA,QACA,CAAC,OAAO,GAAI,QAAQ,CAAC,IAAI,IAAI,CAAC,GAAI,GAAG,QAAQ;AAAA,QAC7C;AAAA,MACF;AACA;AAAA,IACF,KAAK;AACH,YAAM;AAAA,QACJ;AAAA,QACA,CAAC,OAAO,GAAI,QAAQ,CAAC,IAAI,IAAI,CAAC,GAAI,GAAG,QAAQ;AAAA,QAC7C;AAAA,MACF;AACA;AAAA,IACF,KAAK;AACH,YAAM;AAAA,QACJ;AAAA,QACA,CAAC,OAAO,GAAI,QAAQ,CAAC,IAAI,IAAI,CAAC,GAAI,GAAG,QAAQ;AAAA,QAC7C;AAAA,MACF;AACA;AAAA,IACF,KAAK;AAAA,IACL;AACE,YAAM;AAAA,QACJ;AAAA,QACA,CAAC,WAAW,QAAQ,eAAe,UAAU,GAAG,QAAQ;AAAA,QACxD;AAAA,MACF;AACA;AAAA,EACJ;AACF;AAKO,SAAS,uBAAuB,IAGrC;AACA,UAAQ,IAAI;AAAA,IACV,KAAK;AACH,aAAO,EAAE,SAAS,QAAQ,MAAM,CAAC,QAAQ,MAAM,YAAY,EAAE;AAAA,IAC/D,KAAK;AACH,aAAO,EAAE,SAAS,QAAQ,MAAM,CAAC,QAAQ,YAAY,EAAE;AAAA,IACzD,KAAK;AACH,aAAO,EAAE,SAAS,OAAO,MAAM,CAAC,QAAQ,YAAY,EAAE;AAAA,IACxD,KAAK;AAAA,IACL;AACE,aAAO,EAAE,SAAS,OAAO,MAAM,CAAC,QAAQ,MAAM,YAAY,EAAE;AAAA,EAChE;AACF;AAKA,eAAsB,qBACpB,IACA,aACe;AACf,QAAM,EAAE,SAAS,KAAK,IAAI,uBAAuB,EAAE;AACnD,QAAM,WAAW,SAAS,MAAM,WAAW;AAC7C;","names":[]}