@neerav34/env-doctor 1.0.0

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 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/commands/check.ts","../src/core/parser.ts","../src/core/scanner.ts","../src/utils/glob.ts","../src/utils/gitignore.ts","../src/core/detector.ts","../src/core/analyzer.ts","../src/utils/logger.ts","../src/core/reporter.ts","../src/commands/init.ts","../src/commands/doctor.ts"],"sourcesContent":["import { Command, Option } from 'commander';\nimport { runCheck } from './commands/check.js';\nimport { runInit } from './commands/init.js';\nimport { runDoctor } from './commands/doctor.js';\nimport type { CheckOptions, InitOptions } from './types/index.js';\n\nconst DEFAULT_IGNORE = ['node_modules', 'dist', '.git'];\n\nconst program = new Command();\n\nprogram\n .name('env-doctor')\n .description('The eslint of environment variables — catch missing env vars before they hit production')\n .version('1.0.0');\n\n// ─── check command ────────────────────────────────────────────────────────────\n\nprogram\n .command('check')\n .description('Scan codebase and report environment variable discrepancies')\n .option('--fix', 'Auto-update .env.example to match code references', false)\n .option('--strict', 'Treat warnings as errors (exit 1)', false)\n .option('--env-file <path>', 'Path to .env file', '.env')\n .option('--example-file <path>', 'Path to .env.example file', '.env.example')\n .option('--ignore <patterns...>', 'Additional glob patterns to skip', DEFAULT_IGNORE)\n .option('--no-color', 'Disable ANSI color output')\n .option('--root <path>', 'Project root directory (default: cwd)')\n .addOption(\n new Option('--format <format>', 'Output format').choices(['pretty', 'json', 'markdown']).default('pretty')\n )\n .action(async (opts: Record<string, unknown>) => {\n const options: CheckOptions = {\n fix: Boolean(opts['fix']),\n strict: Boolean(opts['strict']),\n envFile: String(opts['envFile'] ?? '.env'),\n exampleFile: String(opts['exampleFile'] ?? '.env.example'),\n ignore: Array.isArray(opts['ignore']) ? (opts['ignore'] as string[]) : DEFAULT_IGNORE,\n format: (opts['format'] as CheckOptions['format']) ?? 'pretty',\n noColor: !opts['color'],\n root: String(opts['root'] ?? ''),\n };\n await runCheck(options).catch(fatalError);\n });\n\n// ─── init command ─────────────────────────────────────────────────────────────\n\nprogram\n .command('init')\n .description('Generate or update .env.example from code references and .env')\n .option('--env-file <path>', 'Path to .env file', '.env')\n .option('--example-file <path>', 'Path to .env.example file', '.env.example')\n .option('--ignore <patterns...>', 'Additional glob patterns to skip', DEFAULT_IGNORE)\n .option('--with-comments', 'Add source file comments to each variable', false)\n .option('--no-color', 'Disable ANSI color output')\n .option('--root <path>', 'Project root directory (default: cwd)')\n .action(async (opts: Record<string, unknown>) => {\n const options: InitOptions = {\n envFile: String(opts['envFile'] ?? '.env'),\n exampleFile: String(opts['exampleFile'] ?? '.env.example'),\n ignore: Array.isArray(opts['ignore']) ? (opts['ignore'] as string[]) : DEFAULT_IGNORE,\n withComments: Boolean(opts['withComments']),\n noColor: !opts['color'],\n root: String(opts['root'] ?? ''),\n };\n await runInit(options).catch(fatalError);\n });\n\n// ─── doctor command ───────────────────────────────────────────────────────────\n\nprogram\n .command('doctor')\n .description('Full diagnostic with health score and trend analysis')\n .option('--strict', 'Treat warnings as errors (exit 1)', false)\n .option('--env-file <path>', 'Path to .env file', '.env')\n .option('--example-file <path>', 'Path to .env.example file', '.env.example')\n .option('--ignore <patterns...>', 'Additional glob patterns to skip', DEFAULT_IGNORE)\n .option('--no-color', 'Disable ANSI color output')\n .option('--root <path>', 'Project root directory (default: cwd)')\n .addOption(\n new Option('--format <format>', 'Output format').choices(['pretty', 'json', 'markdown']).default('pretty')\n )\n .action(async (opts: Record<string, unknown>) => {\n const options = {\n fix: false,\n strict: Boolean(opts['strict']),\n envFile: String(opts['envFile'] ?? '.env'),\n exampleFile: String(opts['exampleFile'] ?? '.env.example'),\n ignore: Array.isArray(opts['ignore']) ? (opts['ignore'] as string[]) : DEFAULT_IGNORE,\n format: (opts['format'] as CheckOptions['format']) ?? 'pretty',\n noColor: !opts['color'],\n root: String(opts['root'] ?? ''),\n };\n await runDoctor(options).catch(fatalError);\n });\n\nfunction fatalError(err: unknown): never {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(`\\n Fatal error: ${message}\\n\\n`);\n process.exit(3);\n}\n\nprogram.parseAsync(process.argv).catch(fatalError);\n","import path from 'path';\nimport { writeFile, readFile } from 'fs/promises';\nimport { parseEnvFile } from '../core/parser.js';\nimport { scanProjectFiles } from '../core/scanner.js';\nimport { detectVarsInFile } from '../core/detector.js';\nimport { analyze } from '../core/analyzer.js';\nimport { reportPretty, reportJson, reportMarkdown } from '../core/reporter.js';\nimport { setColorEnabled } from '../utils/logger.js';\nimport { resolveRoot } from '../utils/glob.js';\nimport type { CheckOptions, ScanResult, EnvVarReference } from '../types/index.js';\n\nexport async function runCheck(options: CheckOptions): Promise<void> {\n const { format, noColor, strict, fix } = options;\n\n setColorEnabled(!noColor);\n\n const root = resolveRoot(options.root);\n const envFilePath = path.resolve(root, options.envFile);\n const exampleFilePath = path.resolve(root, options.exampleFile);\n\n const start = Date.now();\n\n // Step 1: Parse .env and .env.example\n const [envResult, exampleResult] = await Promise.all([\n parseEnvFile(envFilePath, false),\n parseEnvFile(exampleFilePath, true),\n ]);\n\n // Step 2: Scan source files\n const { files, skippedFiles } = await scanProjectFiles(root, {\n ignore: options.ignore,\n respectGitignore: true,\n });\n\n // Step 3: Detect env var references in all files (parallel)\n const refResults = await Promise.allSettled(\n files.map(file => detectVarsInFile(root, file))\n );\n\n // Step 4: Aggregate references\n const foundVars = new Map<string, EnvVarReference[]>();\n for (const result of refResults) {\n if (result.status !== 'fulfilled') continue;\n for (const ref of result.value) {\n const existing = foundVars.get(ref.name) ?? [];\n existing.push(ref);\n foundVars.set(ref.name, existing);\n }\n }\n\n // Step 5: Analyze\n const issues = analyze({\n foundVars,\n envVars: envResult.vars,\n exampleVars: exampleResult.vars,\n });\n\n const duration = Date.now() - start;\n\n const scanResult: ScanResult = {\n projectRoot: root,\n scannedFiles: files.length,\n skippedFiles,\n foundVars,\n envVars: envResult.vars,\n exampleVars: exampleResult.vars,\n issues,\n duration,\n };\n\n // Step 6: Auto-fix .env.example if requested\n if (fix) {\n await applyFix(scanResult, exampleFilePath);\n }\n\n // Step 7: Report output\n switch (format) {\n case 'json':\n reportJson(scanResult);\n break;\n case 'markdown':\n reportMarkdown(scanResult);\n break;\n default:\n reportPretty(scanResult);\n }\n\n // Step 8: Exit with appropriate code\n const hasErrors = issues.some(i => i.severity === 'error');\n const hasWarns = issues.some(i => i.severity === 'warn');\n\n if (hasErrors || (strict && hasWarns)) {\n process.exit(1);\n } else if (hasWarns) {\n process.exit(2);\n } else {\n process.exit(0);\n }\n}\n\nasync function applyFix(result: ScanResult, exampleFilePath: string): Promise<void> {\n const { foundVars, exampleVars } = result;\n\n // Collect vars referenced in code but missing from .env.example\n const newVars: string[] = [];\n for (const [name] of foundVars) {\n if (!exampleVars.has(name)) {\n newVars.push(name);\n }\n }\n\n if (newVars.length === 0) return;\n\n let existing = '';\n try {\n existing = await readFile(exampleFilePath, 'utf-8');\n } catch {\n // File doesn't exist yet\n }\n\n const additions = newVars\n .sort()\n .map(name => {\n const refs = result.foundVars.get(name) ?? [];\n const firstRef = refs[0];\n const comment = firstRef ? ` # referenced in ${firstRef.file}:${firstRef.line}` : '';\n return `${name}=${comment}`;\n })\n .join('\\n');\n\n const newContent = existing\n ? existing.trimEnd() + '\\n\\n# Added by env-doctor check --fix\\n' + additions + '\\n'\n : additions + '\\n';\n\n await writeFile(exampleFilePath, newContent, 'utf-8');\n console.log(`\\n Fixed: added ${newVars.length} variable(s) to ${result.exampleVars.size > 0 ? exampleFilePath : '.env.example'}`);\n}\n","import { readFile } from 'fs/promises';\nimport type { EnvVarDefinition } from '../types/index.js';\n\nexport interface ParseResult {\n vars: Map<string, EnvVarDefinition>;\n exists: boolean;\n}\n\n/**\n * Parses a .env or .env.example file and returns a map of variable definitions.\n * Handles: quoted values, export prefix, inline comments, empty values, multiline strings.\n */\nexport async function parseEnvFile(\n filePath: string,\n isExample: boolean\n): Promise<ParseResult> {\n let content: string;\n try {\n content = await readFile(filePath, 'utf-8');\n } catch {\n return { vars: new Map(), exists: false };\n }\n\n return { vars: parseEnvContent(content, filePath, isExample), exists: true };\n}\n\nexport function parseEnvContent(\n content: string,\n filePath: string,\n isExample: boolean\n): Map<string, EnvVarDefinition> {\n const vars = new Map<string, EnvVarDefinition>();\n const lines = content.split('\\n');\n\n for (let i = 0; i < lines.length; i++) {\n const rawLine = lines[i] ?? '';\n let line = rawLine.trim();\n\n // Skip empty lines and comment-only lines\n if (!line || line.startsWith('#') || line.startsWith('//')) continue;\n\n // Strip shell export prefix\n if (line.startsWith('export ')) {\n line = line.slice(7).trim();\n }\n\n const eqIndex = line.indexOf('=');\n if (eqIndex === -1) continue;\n\n const key = line.slice(0, eqIndex).trim();\n\n // Validate key format — must be a valid env var name\n if (!key || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) continue;\n\n let rawValue = line.slice(eqIndex + 1);\n\n // Handle multiline values (KEY=\"line1\\nline2\")\n // Check for unclosed quote and peek ahead\n if (\n (rawValue.startsWith('\"') && !rawValue.slice(1).includes('\"')) ||\n (rawValue.startsWith(\"'\") && !rawValue.slice(1).includes(\"'\"))\n ) {\n const quote = rawValue[0] as string;\n let combined = rawValue;\n while (i + 1 < lines.length) {\n i++;\n const nextLine = lines[i] ?? '';\n combined += '\\n' + nextLine;\n if (nextLine.includes(quote)) break;\n }\n rawValue = combined;\n }\n\n const value = extractValue(rawValue);\n\n // Display value: show first 3 chars then *** to avoid leaking secrets\n const displayValue = truncateValue(value);\n\n vars.set(key, {\n name: key,\n file: filePath,\n line: i + 1,\n ...(displayValue !== undefined ? { value: displayValue } : {}),\n isExample,\n });\n }\n\n return vars;\n}\n\nfunction extractValue(raw: string): string {\n let value = raw.trim();\n\n // Strip inline comment (KEY=value # comment) — only outside quotes\n const firstChar = value[0];\n if (firstChar !== '\"' && firstChar !== \"'\") {\n const commentIdx = value.search(/\\s+#/);\n if (commentIdx !== -1) {\n value = value.slice(0, commentIdx).trim();\n }\n }\n\n // Strip surrounding quotes\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n\n return value;\n}\n\nfunction truncateValue(value: string): string | undefined {\n if (!value) return undefined;\n if (value.length <= 3) return '***';\n return value.slice(0, 3) + '***';\n}\n","import { open } from 'fs/promises';\nimport path from 'path';\nimport { findSourceFiles, type FindFilesOptions } from '../utils/glob.js';\n\nexport interface ScannerResult {\n files: string[];\n skippedFiles: number;\n}\n\n/**\n * Discovers all text-based source files in the project root, excluding\n * binary files and configured ignore patterns.\n */\nexport async function scanProjectFiles(\n root: string,\n options: FindFilesOptions = {}\n): Promise<ScannerResult> {\n const allFiles = await findSourceFiles(root, options);\n\n // Parallel binary detection — read first 1KB to check for null bytes\n const results = await Promise.allSettled(\n allFiles.map(file => isTextFile(path.join(root, file)).then(isText => (isText ? file : null)))\n );\n\n const textFiles: string[] = [];\n let skippedFiles = 0;\n\n for (const result of results) {\n if (result.status === 'fulfilled' && result.value !== null) {\n textFiles.push(result.value);\n } else {\n skippedFiles++;\n }\n }\n\n return { files: textFiles, skippedFiles };\n}\n\nasync function isTextFile(fullPath: string): Promise<boolean> {\n let fd: Awaited<ReturnType<typeof open>> | null = null;\n try {\n fd = await open(fullPath, 'r');\n const buffer = Buffer.alloc(1024);\n const { bytesRead } = await fd.read(buffer, 0, 1024, 0);\n // Null bytes indicate binary content\n return !buffer.subarray(0, bytesRead).includes(0);\n } catch {\n return false;\n } finally {\n await fd?.close().catch(() => undefined);\n }\n}\n","import fg from 'fast-glob';\nimport path from 'path';\nimport { loadGitignorePatterns } from './gitignore.js';\n\nconst ALWAYS_IGNORE: string[] = [\n '**/node_modules/**',\n '**/.git/**',\n '**/dist/**',\n '**/build/**',\n '**/coverage/**',\n '**/.next/**',\n '**/.nuxt/**',\n '**/vendor/**',\n '**/target/**',\n '**/bin/**',\n '**/obj/**',\n '**/.cache/**',\n '**/__pycache__/**',\n '**/*.pyc',\n '**/*.min.js',\n '**/*.min.css',\n '**/*.map',\n '**/*.lock',\n '**/package-lock.json',\n '**/yarn.lock',\n '**/pnpm-lock.yaml',\n // Exclude .env files from source scanning — they're parsed separately by parser.ts\n '.env',\n '**/.env',\n '.env.*',\n '**/.env.*',\n];\n\nexport interface FindFilesOptions {\n ignore?: string[];\n respectGitignore?: boolean;\n}\n\nexport async function findSourceFiles(\n root: string,\n options: FindFilesOptions = {}\n): Promise<string[]> {\n const { ignore = [], respectGitignore = true } = options;\n\n const gitignorePatterns = respectGitignore\n ? await loadGitignorePatterns(root)\n : [];\n\n const allIgnore = [...ALWAYS_IGNORE, ...gitignorePatterns, ...ignore];\n\n const files = await fg('**/*', {\n cwd: root,\n ignore: allIgnore,\n absolute: false,\n dot: true,\n onlyFiles: true,\n followSymbolicLinks: false,\n });\n\n return files.sort();\n}\n\nexport function resolveRoot(providedRoot?: string): string {\n if (providedRoot) {\n return path.resolve(providedRoot);\n }\n return process.cwd();\n}\n","import { readFile } from 'fs/promises';\nimport path from 'path';\n\n/**\n * Loads .gitignore patterns from the project root and converts them to\n * fast-glob compatible ignore patterns.\n */\nexport async function loadGitignorePatterns(root: string): Promise<string[]> {\n const gitignorePath = path.join(root, '.gitignore');\n try {\n const content = await readFile(gitignorePath, 'utf-8');\n return parseGitignorePatterns(content);\n } catch {\n return [];\n }\n}\n\nexport function parseGitignorePatterns(content: string): string[] {\n return content\n .split('\\n')\n .map(line => line.trim())\n .filter(line => line.length > 0 && !line.startsWith('#'))\n .flatMap(pattern => {\n // Negated patterns (!) are not supported in fast-glob ignore\n if (pattern.startsWith('!')) return [];\n\n // Directory-only pattern (ends with /)\n if (pattern.endsWith('/')) {\n const dir = pattern.slice(0, -1);\n return [`**/${dir}/**`, `${dir}/**`];\n }\n\n // Rooted pattern (starts with /)\n if (pattern.startsWith('/')) {\n return [pattern.slice(1), `${pattern.slice(1)}/**`];\n }\n\n // Pattern with directory separator in middle — keep as-is\n if (pattern.includes('/')) {\n return [pattern];\n }\n\n // Simple filename/glob — match anywhere\n return [`**/${pattern}`, `**/${pattern}/**`];\n });\n}\n","import { readFile } from 'fs/promises';\nimport path from 'path';\nimport type { EnvVarReference } from '../types/index.js';\n\ninterface PatternDef {\n lang: string;\n source: string;\n /** If set, only apply this pattern to files with these extensions or basenames */\n extensions?: string[];\n}\n\nconst PATTERN_DEFS: PatternDef[] = [\n // JavaScript / TypeScript — process.env.VAR (dot notation)\n {\n lang: 'js',\n source: String.raw`process\\.env\\.([A-Z_][A-Z0-9_]*)`,\n },\n // JavaScript / TypeScript — process.env['VAR'] or process.env[\"VAR\"] (bracket notation)\n {\n lang: 'js',\n source: String.raw`process\\.env\\[['\"]([A-Z_][A-Z0-9_]*)['\"]\\]`,\n },\n // Vite / import.meta.env.VAR\n {\n lang: 'js',\n source: String.raw`import\\.meta\\.env\\.([A-Z_][A-Z0-9_]*)`,\n },\n // Python — os.environ.get('VAR') and os.getenv('VAR') (function call)\n {\n lang: 'py',\n source: String.raw`os\\.(?:environ\\.get|getenv)\\(\\s*['\"]([A-Z_][A-Z0-9_]*)['\"]\\s*`,\n extensions: ['.py'],\n },\n // Python — os.environ['VAR'] (direct subscript)\n {\n lang: 'py',\n source: String.raw`os\\.environ\\[['\"]([A-Z_][A-Z0-9_]*)['\"]\\]`,\n extensions: ['.py'],\n },\n // Go — os.Getenv(\"VAR\")\n {\n lang: 'go',\n source: String.raw`os\\.Getenv\\(\\s*\"([A-Z_][A-Z0-9_]*)\"\\s*\\)`,\n extensions: ['.go'],\n },\n // Rust — env::var(\"VAR\") or std::env::var(\"VAR\")\n {\n lang: 'rs',\n source: String.raw`env::var\\(\\s*\"([A-Z_][A-Z0-9_]*)\"\\s*\\)`,\n extensions: ['.rs'],\n },\n // Ruby — ENV['VAR'] or ENV[\"VAR\"]\n {\n lang: 'rb',\n source: String.raw`ENV\\[['\"]([A-Z_][A-Z0-9_]*)['\"]\\]`,\n extensions: ['.rb'],\n },\n // PHP — $_ENV['VAR'] or $_ENV[\"VAR\"] (array subscript)\n {\n lang: 'php',\n source: String.raw`\\$_ENV\\[['\"]([A-Z_][A-Z0-9_]*)['\"]\\]`,\n extensions: ['.php'],\n },\n // PHP — getenv('VAR') (function call)\n {\n lang: 'php',\n source: String.raw`getenv\\(\\s*['\"]([A-Z_][A-Z0-9_]*)['\"]\\s*\\)`,\n extensions: ['.php'],\n },\n // Docker Compose / Shell — ${VAR} syntax (restrict to avoid false positives)\n {\n lang: 'sh',\n source: String.raw`\\$\\{([A-Z_][A-Z0-9_]*)\\}`,\n extensions: [\n '.sh', '.bash', '.zsh', '.fish',\n 'Dockerfile', '.dockerfile',\n 'docker-compose.yml', 'docker-compose.yaml',\n '.env.example',\n ],\n },\n // Shell — $VAR syntax (only in shell scripts)\n {\n lang: 'sh',\n source: String.raw`(?<![A-Za-z0-9_])\\$([A-Z_][A-Z0-9_]*)(?![A-Za-z0-9_({])`,\n extensions: ['.sh', '.bash', '.zsh'],\n },\n];\n\nfunction getLineColumn(content: string, index: number): { line: number; column: number } {\n const before = content.slice(0, index);\n const lines = before.split('\\n');\n const lastLine = lines[lines.length - 1] ?? '';\n return {\n line: lines.length,\n column: lastLine.length + 1,\n };\n}\n\nfunction isCommentedLine(line: string): boolean {\n const trimmed = line.trimStart();\n return (\n trimmed.startsWith('//') ||\n trimmed.startsWith('#') ||\n trimmed.startsWith('*') ||\n trimmed.startsWith('/*') ||\n trimmed.startsWith('--') ||\n trimmed.startsWith('<!--')\n );\n}\n\nfunction fileMatchesPattern(filePath: string, extensions: string[]): boolean {\n const ext = path.extname(filePath).toLowerCase();\n const basename = path.basename(filePath);\n return extensions.some(e => ext === e || basename === e || basename.endsWith(e));\n}\n\nexport function detectVarsInContent(content: string, filePath: string): EnvVarReference[] {\n const lines = content.split('\\n');\n const seen = new Set<string>();\n const refs: EnvVarReference[] = [];\n\n for (const def of PATTERN_DEFS) {\n if (def.extensions && !fileMatchesPattern(filePath, def.extensions)) continue;\n\n // Create a fresh RegExp per call to avoid lastIndex state issues with /g\n const regex = new RegExp(def.source, 'g');\n let match: RegExpExecArray | null;\n\n while ((match = regex.exec(content)) !== null) {\n const varName = match[1];\n if (!varName) continue;\n\n const pos = getLineColumn(content, match.index);\n const lineContent = lines[pos.line - 1] ?? '';\n\n if (isCommentedLine(lineContent)) continue;\n\n // Deduplicate by variable + location\n const key = `${varName}:${pos.line}:${pos.column}`;\n if (seen.has(key)) continue;\n seen.add(key);\n\n refs.push({\n name: varName,\n file: filePath,\n line: pos.line,\n column: pos.column,\n pattern: def.lang,\n context: lineContent.trim(),\n });\n }\n }\n\n return refs;\n}\n\nexport async function detectVarsInFile(\n root: string,\n relativePath: string\n): Promise<EnvVarReference[]> {\n const fullPath = path.join(root, relativePath);\n const content = await readFile(fullPath, 'utf-8');\n return detectVarsInContent(content, relativePath);\n}\n","import type { EnvVarReference, EnvVarDefinition, Issue } from '../types/index.js';\n\nexport interface AnalyzerInput {\n foundVars: Map<string, EnvVarReference[]>;\n envVars: Map<string, EnvVarDefinition>;\n exampleVars: Map<string, EnvVarDefinition>;\n}\n\n/**\n * Cross-references code references against .env and .env.example definitions\n * to produce a list of issues.\n */\nexport function analyze(input: AnalyzerInput): Issue[] {\n const { foundVars, envVars, exampleVars } = input;\n const issues: Issue[] = [];\n\n // Check each variable referenced in source code\n for (const [name, refs] of foundVars) {\n const inEnv = envVars.has(name);\n const inExample = exampleVars.has(name);\n\n if (!inEnv && !inExample) {\n // Not anywhere — hard error\n issues.push({\n severity: 'error',\n type: 'missing',\n variable: name,\n message: `${name} is referenced in ${refs.length} location(s) but not defined in .env or .env.example`,\n references: refs,\n suggestion: `Add ${name} to .env.example`,\n });\n } else if (!inEnv && inExample) {\n // Documented but not configured locally\n const def = exampleVars.get(name);\n issues.push({\n severity: 'warn',\n type: 'missing',\n variable: name,\n message: `${name} is referenced but missing from .env (documented in .env.example)`,\n references: refs,\n ...(def !== undefined ? { definition: def } : {}),\n suggestion: `Copy ${name} from .env.example to .env and set a real value`,\n });\n }\n }\n\n // Check each variable defined in .env\n for (const [name, def] of envVars) {\n if (!foundVars.has(name)) {\n issues.push({\n severity: 'warn',\n type: 'unused',\n variable: name,\n message: `${name} is defined in .env but never referenced in source code`,\n definition: def,\n suggestion: `Remove ${name} from .env, or check for typos in variable name`,\n });\n }\n\n if (!exampleVars.has(name)) {\n issues.push({\n severity: 'warn',\n type: 'example-drift',\n variable: name,\n message: `${name} exists in .env but is missing from .env.example`,\n definition: def,\n suggestion: `Run \\`env-doctor check --fix\\` to sync .env.example`,\n });\n }\n }\n\n // Check vars only in .env.example that have no corresponding code reference or .env entry\n for (const [name, def] of exampleVars) {\n if (!foundVars.has(name) && !envVars.has(name)) {\n issues.push({\n severity: 'warn',\n type: 'example-drift',\n variable: name,\n message: `${name} is in .env.example but not referenced in code or .env`,\n definition: def,\n suggestion: `Remove ${name} from .env.example if it is no longer needed`,\n });\n }\n }\n\n // Sort: errors first, then warns, then by variable name\n return issues.sort((a, b) => {\n if (a.severity !== b.severity) {\n return a.severity === 'error' ? -1 : 1;\n }\n return a.variable.localeCompare(b.variable);\n });\n}\n","import chalk from 'chalk';\n\nlet colorEnabled = true;\n\nexport function setColorEnabled(enabled: boolean): void {\n colorEnabled = enabled;\n}\n\nfunction c(colorFn: (s: string) => string, msg: string): string {\n return colorEnabled ? colorFn(msg) : msg;\n}\n\nexport const logger = {\n error: (msg: string): void => { process.stderr.write(c(chalk.red, msg) + '\\n'); },\n warn: (msg: string): void => { process.stderr.write(c(chalk.yellow, msg) + '\\n'); },\n info: (msg: string): void => { console.log(c(chalk.blue, msg)); },\n success: (msg: string): void => { console.log(c(chalk.green, msg)); },\n header: (msg: string): void => { console.log(c(chalk.bold.white, msg)); },\n dim: (msg: string): void => { console.log(c(chalk.dim, msg)); },\n log: (msg: string): void => { console.log(msg); },\n\n red: (msg: string): string => c(chalk.red, msg),\n yellow: (msg: string): string => c(chalk.yellow, msg),\n green: (msg: string): string => c(chalk.green, msg),\n blue: (msg: string): string => c(chalk.blue, msg),\n cyan: (msg: string): string => c(chalk.cyan, msg),\n bold: (msg: string): string => c(chalk.bold, msg),\n dim_: (msg: string): string => c(chalk.dim, msg),\n gray: (msg: string): string => c(chalk.gray, msg),\n};\n","import type { Issue, ScanResult, HealthReport } from '../types/index.js';\nimport { logger } from '../utils/logger.js';\n\n// ─── Pretty Format ────────────────────────────────────────────────────────────\n\nexport function reportPretty(result: ScanResult): void {\n const { issues, scannedFiles, skippedFiles, duration } = result;\n const errors = issues.filter(i => i.severity === 'error');\n const warns = issues.filter(i => i.severity === 'warn');\n\n console.log('');\n\n if (errors.length === 0 && warns.length === 0) {\n logger.success(` ✓ All environment variables are properly configured`);\n printStats(scannedFiles, skippedFiles, duration);\n return;\n }\n\n if (errors.length > 0) {\n console.log(logger.bold(logger.red(` ERRORS (${errors.length})`)));\n console.log('');\n for (const issue of errors) {\n printIssuePretty(issue, 'error');\n }\n }\n\n if (warns.length > 0) {\n console.log(logger.bold(logger.yellow(` WARNINGS (${warns.length})`)));\n console.log('');\n for (const issue of warns) {\n printIssuePretty(issue, 'warn');\n }\n }\n\n printStats(scannedFiles, skippedFiles, duration);\n}\n\nfunction printIssuePretty(issue: Issue, level: 'error' | 'warn'): void {\n const icon = level === 'error' ? logger.red(' ✗') : logger.yellow(' ⚠');\n const typeLbl = formatIssueType(issue.type);\n const varName = level === 'error'\n ? logger.bold(logger.red(issue.variable))\n : logger.bold(logger.yellow(issue.variable));\n\n console.log(`${icon} ${varName} ${logger.gray(`[${typeLbl}]`)}`);\n console.log(` ${logger.gray(issue.message)}`);\n\n if (issue.references) {\n for (const ref of issue.references.slice(0, 3)) {\n console.log(` ${logger.dim_('└─')} ${logger.cyan(`${ref.file}:${ref.line}`)} ${logger.dim_(ref.context)}`);\n }\n if (issue.references.length > 3) {\n console.log(` ${logger.dim_(` ... and ${issue.references.length - 3} more`)}`);\n }\n }\n\n if (issue.definition) {\n const loc = `${issue.definition.file}:${issue.definition.line}`;\n console.log(` ${logger.dim_('└─')} ${logger.cyan(loc)}`);\n }\n\n if (issue.suggestion) {\n console.log(` ${logger.green('→')} ${issue.suggestion}`);\n }\n\n console.log('');\n}\n\nfunction printStats(scannedFiles: number, skippedFiles: number, duration: number): void {\n console.log('');\n console.log(\n logger.dim_(\n ` Scanned ${scannedFiles} files` +\n (skippedFiles > 0 ? ` (${skippedFiles} skipped)` : '') +\n ` in ${duration}ms`\n )\n );\n console.log('');\n}\n\nfunction formatIssueType(type: string): string {\n const labels: Record<string, string> = {\n missing: 'Missing Required',\n unused: 'Unused Variable',\n 'example-drift': 'Example Drift',\n 'type-mismatch': 'Type Mismatch',\n };\n return labels[type] ?? type;\n}\n\n// ─── JSON Format ──────────────────────────────────────────────────────────────\n\nexport interface JsonOutput {\n success: boolean;\n summary: {\n errors: number;\n warnings: number;\n scannedFiles: number;\n skippedFiles: number;\n duration: number;\n };\n issues: Array<{\n severity: string;\n type: string;\n variable: string;\n message: string;\n references?: Array<{ file: string; line: number; column: number; context: string }>;\n definition?: { file: string; line: number };\n suggestion?: string;\n }>;\n}\n\nexport function buildJsonOutput(result: ScanResult): JsonOutput {\n return {\n success: result.issues.filter(i => i.severity === 'error').length === 0,\n summary: {\n errors: result.issues.filter(i => i.severity === 'error').length,\n warnings: result.issues.filter(i => i.severity === 'warn').length,\n scannedFiles: result.scannedFiles,\n skippedFiles: result.skippedFiles,\n duration: result.duration,\n },\n issues: result.issues.map(issue => ({\n severity: issue.severity,\n type: issue.type,\n variable: issue.variable,\n message: issue.message,\n ...(issue.references !== undefined\n ? { references: issue.references.map(r => ({ file: r.file, line: r.line, column: r.column, context: r.context })) }\n : {}),\n ...(issue.definition !== undefined\n ? { definition: { file: issue.definition.file, line: issue.definition.line } }\n : {}),\n ...(issue.suggestion !== undefined ? { suggestion: issue.suggestion } : {}),\n })),\n };\n}\n\nexport function reportJson(result: ScanResult): void {\n console.log(JSON.stringify(buildJsonOutput(result), null, 2));\n}\n\n// ─── Markdown Format ─────────────────────────────────────────────────────────\n\nexport function reportMarkdown(result: ScanResult): void {\n const { issues, scannedFiles, duration } = result;\n const errors = issues.filter(i => i.severity === 'error');\n const warns = issues.filter(i => i.severity === 'warn');\n const lines: string[] = [];\n\n lines.push('## Environment Variable Report');\n lines.push('');\n\n if (errors.length === 0 && warns.length === 0) {\n lines.push('✅ All environment variables are properly configured.');\n } else {\n const badge = errors.length > 0 ? '🔴' : '🟡';\n lines.push(`${badge} **${errors.length} error(s), ${warns.length} warning(s)**`);\n lines.push('');\n\n if (errors.length > 0) {\n lines.push('### Errors');\n lines.push('');\n for (const issue of errors) {\n lines.push(issueToMarkdown(issue));\n }\n }\n\n if (warns.length > 0) {\n lines.push('### Warnings');\n lines.push('');\n for (const issue of warns) {\n lines.push(issueToMarkdown(issue));\n }\n }\n }\n\n lines.push('---');\n lines.push(`_Scanned ${scannedFiles} files in ${duration}ms_`);\n\n console.log(lines.join('\\n'));\n}\n\nfunction issueToMarkdown(issue: Issue): string {\n const parts: string[] = [];\n const icon = issue.severity === 'error' ? '❌' : '⚠️';\n parts.push(`#### ${icon} \\`${issue.variable}\\``);\n parts.push('');\n parts.push(issue.message);\n\n if (issue.references && issue.references.length > 0) {\n parts.push('');\n parts.push('**References:**');\n for (const ref of issue.references) {\n parts.push(`- \\`${ref.file}:${ref.line}\\` — \\`${ref.context}\\``);\n }\n }\n\n if (issue.suggestion) {\n parts.push('');\n parts.push(`> 💡 ${issue.suggestion}`);\n }\n\n parts.push('');\n return parts.join('\\n');\n}\n\n// ─── Doctor Format ────────────────────────────────────────────────────────────\n\nexport function reportDoctor(result: ScanResult, health: HealthReport): void {\n const scoreColor = health.score >= 80 ? logger.green : health.score >= 50 ? logger.yellow : logger.red;\n const scoreIcon = health.score >= 80 ? '✓' : health.score >= 50 ? '⚠' : '✗';\n\n console.log('');\n console.log(logger.bold(' ENVIRONMENT HEALTH REPORT'));\n console.log('');\n console.log(` Health Score: ${scoreColor(`${health.score}/100`)} ${scoreIcon}`);\n console.log('');\n\n if (health.breakdown.length > 0) {\n console.log(logger.bold(' Breakdown:'));\n for (const item of health.breakdown) {\n const pts = item.points > 0 ? logger.red(`-${item.points} pts`) : logger.green('0 pts');\n console.log(` ${item.label.padEnd(25)} ${String(item.count).padStart(3)} (${pts})`);\n }\n console.log('');\n }\n\n if (health.mostProblematicFiles.length > 0) {\n console.log(logger.bold(' Most Problematic Files:'));\n health.mostProblematicFiles.forEach((f, idx) => {\n console.log(` ${idx + 1}. ${logger.cyan(f.file)} ${logger.gray(`(${f.issueCount} issue${f.issueCount === 1 ? '' : 's'})`)}`);\n });\n console.log('');\n }\n\n if (health.recommendations.length > 0) {\n console.log(logger.bold(' Recommendations:'));\n for (const rec of health.recommendations) {\n console.log(` ${logger.green('→')} ${rec}`);\n }\n console.log('');\n }\n\n // Also show all issues\n reportPretty(result);\n}\n","import path from 'path';\nimport { writeFile, readFile } from 'fs/promises';\nimport { parseEnvFile } from '../core/parser.js';\nimport { scanProjectFiles } from '../core/scanner.js';\nimport { detectVarsInFile } from '../core/detector.js';\nimport { setColorEnabled, logger } from '../utils/logger.js';\nimport { resolveRoot } from '../utils/glob.js';\nimport type { InitOptions, EnvVarReference } from '../types/index.js';\n\nexport async function runInit(options: InitOptions): Promise<void> {\n setColorEnabled(!options.noColor);\n\n const root = resolveRoot(options.root);\n const envFilePath = path.resolve(root, options.envFile);\n const exampleFilePath = path.resolve(root, options.exampleFile);\n\n logger.header('\\n Generating .env.example...\\n');\n\n const start = Date.now();\n\n // Parse existing files\n const [envResult, existingExampleResult] = await Promise.all([\n parseEnvFile(envFilePath, false),\n parseEnvFile(exampleFilePath, true),\n ]);\n\n // Scan and detect all env var references\n const { files } = await scanProjectFiles(root, {\n ignore: options.ignore,\n respectGitignore: true,\n });\n\n const refResults = await Promise.allSettled(\n files.map(file => detectVarsInFile(root, file))\n );\n\n // Collect unique variable names and their first references\n const foundVarsMap = new Map<string, EnvVarReference>();\n for (const result of refResults) {\n if (result.status !== 'fulfilled') continue;\n for (const ref of result.value) {\n if (!foundVarsMap.has(ref.name)) {\n foundVarsMap.set(ref.name, ref);\n }\n }\n }\n\n const allVarNames = new Set([\n ...foundVarsMap.keys(),\n ...envResult.vars.keys(),\n ]);\n\n // Determine what's new vs already present\n const existingNames = new Set(existingExampleResult.vars.keys());\n const newVars: string[] = [];\n const presentVars: string[] = [];\n\n for (const name of allVarNames) {\n if (existingNames.has(name)) {\n presentVars.push(name);\n } else {\n newVars.push(name);\n }\n }\n\n if (newVars.length === 0 && existingExampleResult.exists) {\n logger.success(` ✓ .env.example is already up to date (${presentVars.length} variable${presentVars.length === 1 ? '' : 's'})\\n`);\n return;\n }\n\n const content = buildExampleContent({\n existingContent: existingExampleResult.exists\n ? await readFile(exampleFilePath, 'utf-8').catch(() => '')\n : null,\n newVars,\n presentVars,\n foundVarsMap,\n envVars: envResult.vars,\n withComments: options.withComments,\n });\n\n await writeFile(exampleFilePath, content, 'utf-8');\n\n const duration = Date.now() - start;\n\n logger.success(\n ` ✓ ${existingExampleResult.exists ? 'Updated' : 'Created'} ${options.exampleFile}` +\n ` with ${allVarNames.size} variable${allVarNames.size === 1 ? '' : 's'}` +\n ` (${newVars.length} new, ${presentVars.length} already present)\\n`\n );\n\n if (newVars.length > 0) {\n logger.bold(' New variables added:');\n for (const name of newVars.sort()) {\n const ref = foundVarsMap.get(name);\n const loc = ref ? logger.dim_(` # from ${ref.file}:${ref.line}`) : '';\n logger.log(` ${logger.cyan(name)}${loc}`);\n }\n }\n\n logger.dim_(`\\n Completed in ${duration}ms\\n`);\n}\n\ninterface BuildContentOptions {\n existingContent: string | null;\n newVars: string[];\n presentVars: string[];\n foundVarsMap: Map<string, EnvVarReference>;\n envVars: Map<string, import('../types/index.js').EnvVarDefinition>;\n withComments: boolean;\n}\n\nfunction buildExampleContent(opts: BuildContentOptions): string {\n const { existingContent, newVars, foundVarsMap, envVars, withComments } = opts;\n\n // If we're appending to existing file\n if (existingContent !== null && newVars.length > 0) {\n const additions = newVars\n .sort()\n .map(name => formatVar(name, foundVarsMap.get(name), envVars, withComments))\n .join('\\n');\n\n return existingContent.trimEnd() + '\\n\\n# Added by env-doctor init\\n' + additions + '\\n';\n }\n\n // Building fresh file\n const allNames = [...new Set([...foundVarsMap.keys(), ...envVars.keys()])].sort();\n const lines: string[] = [\n '# Environment Variables',\n '# Generated by env-doctor init — do not commit real values',\n '',\n ];\n\n for (const name of allNames) {\n lines.push(formatVar(name, foundVarsMap.get(name), envVars, withComments));\n }\n\n return lines.join('\\n') + '\\n';\n}\n\nfunction formatVar(\n name: string,\n ref: EnvVarReference | undefined,\n envVars: Map<string, import('../types/index.js').EnvVarDefinition>,\n withComments: boolean\n): string {\n // Use placeholder from .env value (with redaction) if available\n const def = envVars.get(name);\n const placeholder = def?.value ? `# ${def.value}` : '';\n\n const comment = withComments && ref\n ? ` # referenced in ${ref.file}:${ref.line}`\n : '';\n\n return `${name}=${placeholder}${comment}`;\n}\n","import path from 'path';\nimport { readFile, writeFile, mkdir } from 'fs/promises';\nimport { parseEnvFile } from '../core/parser.js';\nimport { scanProjectFiles } from '../core/scanner.js';\nimport { detectVarsInFile } from '../core/detector.js';\nimport { analyze } from '../core/analyzer.js';\nimport { reportDoctor } from '../core/reporter.js';\nimport { setColorEnabled } from '../utils/logger.js';\nimport { resolveRoot } from '../utils/glob.js';\nimport type { DoctorOptions, ScanResult, EnvVarReference, HealthReport } from '../types/index.js';\n\nconst SEVERITY_POINTS = { error: 10, warn: 3, info: 0 } as const;\nconst CACHE_DIR = '.env-doctor';\nconst CACHE_FILE = 'cache.json';\n\ninterface CacheEntry {\n timestamp: string;\n healthScore: number;\n errorCount: number;\n warnCount: number;\n}\n\nexport async function runDoctor(options: DoctorOptions): Promise<void> {\n setColorEnabled(!options.noColor);\n\n const root = resolveRoot(options.root);\n const envFilePath = path.resolve(root, options.envFile);\n const exampleFilePath = path.resolve(root, options.exampleFile);\n\n const start = Date.now();\n\n const [envResult, exampleResult] = await Promise.all([\n parseEnvFile(envFilePath, false),\n parseEnvFile(exampleFilePath, true),\n ]);\n\n const { files, skippedFiles } = await scanProjectFiles(root, {\n ignore: options.ignore,\n respectGitignore: true,\n });\n\n const refResults = await Promise.allSettled(\n files.map(file => detectVarsInFile(root, file))\n );\n\n const foundVars = new Map<string, EnvVarReference[]>();\n for (const result of refResults) {\n if (result.status !== 'fulfilled') continue;\n for (const ref of result.value) {\n const existing = foundVars.get(ref.name) ?? [];\n existing.push(ref);\n foundVars.set(ref.name, existing);\n }\n }\n\n const issues = analyze({\n foundVars,\n envVars: envResult.vars,\n exampleVars: exampleResult.vars,\n });\n\n const duration = Date.now() - start;\n\n const scanResult: ScanResult = {\n projectRoot: root,\n scannedFiles: files.length,\n skippedFiles,\n foundVars,\n envVars: envResult.vars,\n exampleVars: exampleResult.vars,\n issues,\n duration,\n };\n\n const health = buildHealthReport(scanResult);\n\n // Load and compare previous scan if available\n const previous = await loadCache(root);\n if (previous) {\n const delta = health.score - previous.healthScore;\n const trend = delta > 0 ? `+${delta}` : String(delta);\n const arrow = delta > 0 ? '↑' : delta < 0 ? '↓' : '→';\n console.log(`\\n Trend: ${arrow} ${trend} pts from last scan (${previous.timestamp})`);\n }\n\n await saveCache(root, health);\n\n reportDoctor(scanResult, health);\n\n const hasErrors = issues.some(i => i.severity === 'error');\n const hasWarns = issues.some(i => i.severity === 'warn');\n\n if (hasErrors || (options.strict && hasWarns)) {\n process.exit(1);\n } else if (hasWarns) {\n process.exit(2);\n }\n}\n\nfunction buildHealthReport(result: ScanResult): HealthReport {\n const { issues } = result;\n\n const errorCount = issues.filter(i => i.severity === 'error').length;\n const warnCount = issues.filter(i => i.severity === 'warn').length;\n\n const totalPoints =\n errorCount * SEVERITY_POINTS.error + warnCount * SEVERITY_POINTS.warn;\n\n const score = Math.max(0, 100 - totalPoints);\n\n // Breakdown by issue type\n const typeCounts: Record<string, number> = {};\n for (const issue of issues) {\n typeCounts[issue.type] = (typeCounts[issue.type] ?? 0) + 1;\n }\n\n const breakdown = Object.entries(typeCounts).map(([type, count]) => {\n const pts = issues\n .filter(i => i.type === type)\n .reduce((sum, i) => sum + SEVERITY_POINTS[i.severity], 0);\n return {\n label: formatTypeLabel(type),\n count,\n points: pts,\n };\n });\n\n // Most problematic files\n const fileCounts = new Map<string, number>();\n for (const issue of issues) {\n for (const ref of issue.references ?? []) {\n fileCounts.set(ref.file, (fileCounts.get(ref.file) ?? 0) + 1);\n }\n }\n\n const mostProblematicFiles = [...fileCounts.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, 5)\n .map(([file, issueCount]) => ({ file, issueCount }));\n\n // Recommendations\n const recommendations: string[] = [];\n if (issues.some(i => i.type === 'missing' && i.severity === 'error')) {\n recommendations.push('Run `env-doctor check --fix` to update .env.example');\n }\n const unusedVars = issues.filter(i => i.type === 'unused').map(i => i.variable);\n if (unusedVars.length > 0) {\n const list = unusedVars.slice(0, 3).join(', ');\n const more = unusedVars.length > 3 ? ` (+${unusedVars.length - 3} more)` : '';\n recommendations.push(`Review unused variables: ${list}${more}`);\n }\n if (issues.some(i => i.type === 'example-drift')) {\n recommendations.push('Run `env-doctor init` to regenerate .env.example from current code');\n }\n\n return {\n score,\n errorCount,\n warnCount,\n breakdown,\n mostProblematicFiles,\n recommendations,\n };\n}\n\nfunction formatTypeLabel(type: string): string {\n const labels: Record<string, string> = {\n missing: 'Missing Required',\n unused: 'Unused Variables',\n 'example-drift': 'Example Drift',\n 'type-mismatch': 'Type Mismatches',\n };\n return labels[type] ?? type;\n}\n\nasync function loadCache(root: string): Promise<CacheEntry | null> {\n const cachePath = path.join(root, CACHE_DIR, CACHE_FILE);\n try {\n const raw = await readFile(cachePath, 'utf-8');\n return JSON.parse(raw) as CacheEntry;\n } catch {\n return null;\n }\n}\n\nasync function saveCache(root: string, health: HealthReport): Promise<void> {\n const cacheDir = path.join(root, CACHE_DIR);\n const cachePath = path.join(cacheDir, CACHE_FILE);\n\n try {\n await mkdir(cacheDir, { recursive: true });\n const entry: CacheEntry = {\n timestamp: new Date().toISOString(),\n healthScore: health.score,\n errorCount: health.errorCount,\n warnCount: health.warnCount,\n };\n await writeFile(cachePath, JSON.stringify(entry, null, 2), 'utf-8');\n } catch {\n // Non-fatal — cache failure shouldn't break the command\n }\n}\n"],"mappings":";;;AAAA,SAAS,SAAS,cAAc;;;ACAhC,OAAOA,WAAU;AACjB,SAAS,WAAW,YAAAC,iBAAgB;;;ACDpC,SAAS,gBAAgB;AAYzB,eAAsB,aACpB,UACA,WACsB;AACtB,MAAI;AACJ,MAAI;AACF,cAAU,MAAM,SAAS,UAAU,OAAO;AAAA,EAC5C,QAAQ;AACN,WAAO,EAAE,MAAM,oBAAI,IAAI,GAAG,QAAQ,MAAM;AAAA,EAC1C;AAEA,SAAO,EAAE,MAAM,gBAAgB,SAAS,UAAU,SAAS,GAAG,QAAQ,KAAK;AAC7E;AAEO,SAAS,gBACd,SACA,UACA,WAC+B;AAC/B,QAAM,OAAO,oBAAI,IAA8B;AAC/C,QAAM,QAAQ,QAAQ,MAAM,IAAI;AAEhC,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,UAAU,MAAM,CAAC,KAAK;AAC5B,QAAI,OAAO,QAAQ,KAAK;AAGxB,QAAI,CAAC,QAAQ,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,IAAI,EAAG;AAG5D,QAAI,KAAK,WAAW,SAAS,GAAG;AAC9B,aAAO,KAAK,MAAM,CAAC,EAAE,KAAK;AAAA,IAC5B;AAEA,UAAM,UAAU,KAAK,QAAQ,GAAG;AAChC,QAAI,YAAY,GAAI;AAEpB,UAAM,MAAM,KAAK,MAAM,GAAG,OAAO,EAAE,KAAK;AAGxC,QAAI,CAAC,OAAO,CAAC,2BAA2B,KAAK,GAAG,EAAG;AAEnD,QAAI,WAAW,KAAK,MAAM,UAAU,CAAC;AAIrC,QACG,SAAS,WAAW,GAAG,KAAK,CAAC,SAAS,MAAM,CAAC,EAAE,SAAS,GAAG,KAC3D,SAAS,WAAW,GAAG,KAAK,CAAC,SAAS,MAAM,CAAC,EAAE,SAAS,GAAG,GAC5D;AACA,YAAM,QAAQ,SAAS,CAAC;AACxB,UAAI,WAAW;AACf,aAAO,IAAI,IAAI,MAAM,QAAQ;AAC3B;AACA,cAAM,WAAW,MAAM,CAAC,KAAK;AAC7B,oBAAY,OAAO;AACnB,YAAI,SAAS,SAAS,KAAK,EAAG;AAAA,MAChC;AACA,iBAAW;AAAA,IACb;AAEA,UAAM,QAAQ,aAAa,QAAQ;AAGnC,UAAM,eAAe,cAAc,KAAK;AAExC,SAAK,IAAI,KAAK;AAAA,MACZ,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM,IAAI;AAAA,MACV,GAAI,iBAAiB,SAAY,EAAE,OAAO,aAAa,IAAI,CAAC;AAAA,MAC5D;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEA,SAAS,aAAa,KAAqB;AACzC,MAAI,QAAQ,IAAI,KAAK;AAGrB,QAAM,YAAY,MAAM,CAAC;AACzB,MAAI,cAAc,OAAO,cAAc,KAAK;AAC1C,UAAM,aAAa,MAAM,OAAO,MAAM;AACtC,QAAI,eAAe,IAAI;AACrB,cAAQ,MAAM,MAAM,GAAG,UAAU,EAAE,KAAK;AAAA,IAC1C;AAAA,EACF;AAGA,MACG,MAAM,WAAW,GAAG,KAAK,MAAM,SAAS,GAAG,KAC3C,MAAM,WAAW,GAAG,KAAK,MAAM,SAAS,GAAG,GAC5C;AACA,YAAQ,MAAM,MAAM,GAAG,EAAE;AAAA,EAC3B;AAEA,SAAO;AACT;AAEA,SAAS,cAAc,OAAmC;AACxD,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,MAAM,UAAU,EAAG,QAAO;AAC9B,SAAO,MAAM,MAAM,GAAG,CAAC,IAAI;AAC7B;;;ACrHA,SAAS,YAAY;AACrB,OAAOC,WAAU;;;ACDjB,OAAO,QAAQ;AACf,OAAOC,WAAU;;;ACDjB,SAAS,YAAAC,iBAAgB;AACzB,OAAO,UAAU;AAMjB,eAAsB,sBAAsB,MAAiC;AAC3E,QAAM,gBAAgB,KAAK,KAAK,MAAM,YAAY;AAClD,MAAI;AACF,UAAM,UAAU,MAAMA,UAAS,eAAe,OAAO;AACrD,WAAO,uBAAuB,OAAO;AAAA,EACvC,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEO,SAAS,uBAAuB,SAA2B;AAChE,SAAO,QACJ,MAAM,IAAI,EACV,IAAI,UAAQ,KAAK,KAAK,CAAC,EACvB,OAAO,UAAQ,KAAK,SAAS,KAAK,CAAC,KAAK,WAAW,GAAG,CAAC,EACvD,QAAQ,aAAW;AAElB,QAAI,QAAQ,WAAW,GAAG,EAAG,QAAO,CAAC;AAGrC,QAAI,QAAQ,SAAS,GAAG,GAAG;AACzB,YAAM,MAAM,QAAQ,MAAM,GAAG,EAAE;AAC/B,aAAO,CAAC,MAAM,GAAG,OAAO,GAAG,GAAG,KAAK;AAAA,IACrC;AAGA,QAAI,QAAQ,WAAW,GAAG,GAAG;AAC3B,aAAO,CAAC,QAAQ,MAAM,CAAC,GAAG,GAAG,QAAQ,MAAM,CAAC,CAAC,KAAK;AAAA,IACpD;AAGA,QAAI,QAAQ,SAAS,GAAG,GAAG;AACzB,aAAO,CAAC,OAAO;AAAA,IACjB;AAGA,WAAO,CAAC,MAAM,OAAO,IAAI,MAAM,OAAO,KAAK;AAAA,EAC7C,CAAC;AACL;;;ADzCA,IAAM,gBAA0B;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAOA,eAAsB,gBACpB,MACA,UAA4B,CAAC,GACV;AACnB,QAAM,EAAE,SAAS,CAAC,GAAG,mBAAmB,KAAK,IAAI;AAEjD,QAAM,oBAAoB,mBACtB,MAAM,sBAAsB,IAAI,IAChC,CAAC;AAEL,QAAM,YAAY,CAAC,GAAG,eAAe,GAAG,mBAAmB,GAAG,MAAM;AAEpE,QAAM,QAAQ,MAAM,GAAG,QAAQ;AAAA,IAC7B,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,KAAK;AAAA,IACL,WAAW;AAAA,IACX,qBAAqB;AAAA,EACvB,CAAC;AAED,SAAO,MAAM,KAAK;AACpB;AAEO,SAAS,YAAY,cAA+B;AACzD,MAAI,cAAc;AAChB,WAAOC,MAAK,QAAQ,YAAY;AAAA,EAClC;AACA,SAAO,QAAQ,IAAI;AACrB;;;ADtDA,eAAsB,iBACpB,MACA,UAA4B,CAAC,GACL;AACxB,QAAM,WAAW,MAAM,gBAAgB,MAAM,OAAO;AAGpD,QAAM,UAAU,MAAM,QAAQ;AAAA,IAC5B,SAAS,IAAI,UAAQ,WAAWC,MAAK,KAAK,MAAM,IAAI,CAAC,EAAE,KAAK,YAAW,SAAS,OAAO,IAAK,CAAC;AAAA,EAC/F;AAEA,QAAM,YAAsB,CAAC;AAC7B,MAAI,eAAe;AAEnB,aAAW,UAAU,SAAS;AAC5B,QAAI,OAAO,WAAW,eAAe,OAAO,UAAU,MAAM;AAC1D,gBAAU,KAAK,OAAO,KAAK;AAAA,IAC7B,OAAO;AACL;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,OAAO,WAAW,aAAa;AAC1C;AAEA,eAAe,WAAW,UAAoC;AAC5D,MAAI,KAA8C;AAClD,MAAI;AACF,SAAK,MAAM,KAAK,UAAU,GAAG;AAC7B,UAAM,SAAS,OAAO,MAAM,IAAI;AAChC,UAAM,EAAE,UAAU,IAAI,MAAM,GAAG,KAAK,QAAQ,GAAG,MAAM,CAAC;AAEtD,WAAO,CAAC,OAAO,SAAS,GAAG,SAAS,EAAE,SAAS,CAAC;AAAA,EAClD,QAAQ;AACN,WAAO;AAAA,EACT,UAAE;AACA,UAAM,IAAI,MAAM,EAAE,MAAM,MAAM,MAAS;AAAA,EACzC;AACF;;;AGnDA,SAAS,YAAAC,iBAAgB;AACzB,OAAOC,WAAU;AAUjB,IAAM,eAA6B;AAAA;AAAA,EAEjC;AAAA,IACE,MAAM;AAAA,IACN,QAAQ,OAAO;AAAA,EACjB;AAAA;AAAA,EAEA;AAAA,IACE,MAAM;AAAA,IACN,QAAQ,OAAO;AAAA,EACjB;AAAA;AAAA,EAEA;AAAA,IACE,MAAM;AAAA,IACN,QAAQ,OAAO;AAAA,EACjB;AAAA;AAAA,EAEA;AAAA,IACE,MAAM;AAAA,IACN,QAAQ,OAAO;AAAA,IACf,YAAY,CAAC,KAAK;AAAA,EACpB;AAAA;AAAA,EAEA;AAAA,IACE,MAAM;AAAA,IACN,QAAQ,OAAO;AAAA,IACf,YAAY,CAAC,KAAK;AAAA,EACpB;AAAA;AAAA,EAEA;AAAA,IACE,MAAM;AAAA,IACN,QAAQ,OAAO;AAAA,IACf,YAAY,CAAC,KAAK;AAAA,EACpB;AAAA;AAAA,EAEA;AAAA,IACE,MAAM;AAAA,IACN,QAAQ,OAAO;AAAA,IACf,YAAY,CAAC,KAAK;AAAA,EACpB;AAAA;AAAA,EAEA;AAAA,IACE,MAAM;AAAA,IACN,QAAQ,OAAO;AAAA,IACf,YAAY,CAAC,KAAK;AAAA,EACpB;AAAA;AAAA,EAEA;AAAA,IACE,MAAM;AAAA,IACN,QAAQ,OAAO;AAAA,IACf,YAAY,CAAC,MAAM;AAAA,EACrB;AAAA;AAAA,EAEA;AAAA,IACE,MAAM;AAAA,IACN,QAAQ,OAAO;AAAA,IACf,YAAY,CAAC,MAAM;AAAA,EACrB;AAAA;AAAA,EAEA;AAAA,IACE,MAAM;AAAA,IACN,QAAQ,OAAO;AAAA,IACf,YAAY;AAAA,MACV;AAAA,MAAO;AAAA,MAAS;AAAA,MAAQ;AAAA,MACxB;AAAA,MAAc;AAAA,MACd;AAAA,MAAsB;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAEA;AAAA,IACE,MAAM;AAAA,IACN,QAAQ,OAAO;AAAA,IACf,YAAY,CAAC,OAAO,SAAS,MAAM;AAAA,EACrC;AACF;AAEA,SAAS,cAAc,SAAiB,OAAiD;AACvF,QAAM,SAAS,QAAQ,MAAM,GAAG,KAAK;AACrC,QAAM,QAAQ,OAAO,MAAM,IAAI;AAC/B,QAAM,WAAW,MAAM,MAAM,SAAS,CAAC,KAAK;AAC5C,SAAO;AAAA,IACL,MAAM,MAAM;AAAA,IACZ,QAAQ,SAAS,SAAS;AAAA,EAC5B;AACF;AAEA,SAAS,gBAAgB,MAAuB;AAC9C,QAAM,UAAU,KAAK,UAAU;AAC/B,SACE,QAAQ,WAAW,IAAI,KACvB,QAAQ,WAAW,GAAG,KACtB,QAAQ,WAAW,GAAG,KACtB,QAAQ,WAAW,IAAI,KACvB,QAAQ,WAAW,IAAI,KACvB,QAAQ,WAAW,MAAM;AAE7B;AAEA,SAAS,mBAAmB,UAAkB,YAA+B;AAC3E,QAAM,MAAMA,MAAK,QAAQ,QAAQ,EAAE,YAAY;AAC/C,QAAM,WAAWA,MAAK,SAAS,QAAQ;AACvC,SAAO,WAAW,KAAK,OAAK,QAAQ,KAAK,aAAa,KAAK,SAAS,SAAS,CAAC,CAAC;AACjF;AAEO,SAAS,oBAAoB,SAAiB,UAAqC;AACxF,QAAM,QAAQ,QAAQ,MAAM,IAAI;AAChC,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,OAA0B,CAAC;AAEjC,aAAW,OAAO,cAAc;AAC9B,QAAI,IAAI,cAAc,CAAC,mBAAmB,UAAU,IAAI,UAAU,EAAG;AAGrE,UAAM,QAAQ,IAAI,OAAO,IAAI,QAAQ,GAAG;AACxC,QAAI;AAEJ,YAAQ,QAAQ,MAAM,KAAK,OAAO,OAAO,MAAM;AAC7C,YAAM,UAAU,MAAM,CAAC;AACvB,UAAI,CAAC,QAAS;AAEd,YAAM,MAAM,cAAc,SAAS,MAAM,KAAK;AAC9C,YAAM,cAAc,MAAM,IAAI,OAAO,CAAC,KAAK;AAE3C,UAAI,gBAAgB,WAAW,EAAG;AAGlC,YAAM,MAAM,GAAG,OAAO,IAAI,IAAI,IAAI,IAAI,IAAI,MAAM;AAChD,UAAI,KAAK,IAAI,GAAG,EAAG;AACnB,WAAK,IAAI,GAAG;AAEZ,WAAK,KAAK;AAAA,QACR,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM,IAAI;AAAA,QACV,QAAQ,IAAI;AAAA,QACZ,SAAS,IAAI;AAAA,QACb,SAAS,YAAY,KAAK;AAAA,MAC5B,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AACT;AAEA,eAAsB,iBACpB,MACA,cAC4B;AAC5B,QAAM,WAAWA,MAAK,KAAK,MAAM,YAAY;AAC7C,QAAM,UAAU,MAAMD,UAAS,UAAU,OAAO;AAChD,SAAO,oBAAoB,SAAS,YAAY;AAClD;;;ACvJO,SAAS,QAAQ,OAA+B;AACrD,QAAM,EAAE,WAAW,SAAS,YAAY,IAAI;AAC5C,QAAM,SAAkB,CAAC;AAGzB,aAAW,CAAC,MAAM,IAAI,KAAK,WAAW;AACpC,UAAM,QAAQ,QAAQ,IAAI,IAAI;AAC9B,UAAM,YAAY,YAAY,IAAI,IAAI;AAEtC,QAAI,CAAC,SAAS,CAAC,WAAW;AAExB,aAAO,KAAK;AAAA,QACV,UAAU;AAAA,QACV,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS,GAAG,IAAI,qBAAqB,KAAK,MAAM;AAAA,QAChD,YAAY;AAAA,QACZ,YAAY,OAAO,IAAI;AAAA,MACzB,CAAC;AAAA,IACH,WAAW,CAAC,SAAS,WAAW;AAE9B,YAAM,MAAM,YAAY,IAAI,IAAI;AAChC,aAAO,KAAK;AAAA,QACV,UAAU;AAAA,QACV,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS,GAAG,IAAI;AAAA,QAChB,YAAY;AAAA,QACZ,GAAI,QAAQ,SAAY,EAAE,YAAY,IAAI,IAAI,CAAC;AAAA,QAC/C,YAAY,QAAQ,IAAI;AAAA,MAC1B,CAAC;AAAA,IACH;AAAA,EACF;AAGA,aAAW,CAAC,MAAM,GAAG,KAAK,SAAS;AACjC,QAAI,CAAC,UAAU,IAAI,IAAI,GAAG;AACxB,aAAO,KAAK;AAAA,QACV,UAAU;AAAA,QACV,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS,GAAG,IAAI;AAAA,QAChB,YAAY;AAAA,QACZ,YAAY,UAAU,IAAI;AAAA,MAC5B,CAAC;AAAA,IACH;AAEA,QAAI,CAAC,YAAY,IAAI,IAAI,GAAG;AAC1B,aAAO,KAAK;AAAA,QACV,UAAU;AAAA,QACV,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS,GAAG,IAAI;AAAA,QAChB,YAAY;AAAA,QACZ,YAAY;AAAA,MACd,CAAC;AAAA,IACH;AAAA,EACF;AAGA,aAAW,CAAC,MAAM,GAAG,KAAK,aAAa;AACrC,QAAI,CAAC,UAAU,IAAI,IAAI,KAAK,CAAC,QAAQ,IAAI,IAAI,GAAG;AAC9C,aAAO,KAAK;AAAA,QACV,UAAU;AAAA,QACV,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS,GAAG,IAAI;AAAA,QAChB,YAAY;AAAA,QACZ,YAAY,UAAU,IAAI;AAAA,MAC5B,CAAC;AAAA,IACH;AAAA,EACF;AAGA,SAAO,OAAO,KAAK,CAAC,GAAG,MAAM;AAC3B,QAAI,EAAE,aAAa,EAAE,UAAU;AAC7B,aAAO,EAAE,aAAa,UAAU,KAAK;AAAA,IACvC;AACA,WAAO,EAAE,SAAS,cAAc,EAAE,QAAQ;AAAA,EAC5C,CAAC;AACH;;;AC5FA,OAAO,WAAW;AAElB,IAAI,eAAe;AAEZ,SAAS,gBAAgB,SAAwB;AACtD,iBAAe;AACjB;AAEA,SAAS,EAAE,SAAgC,KAAqB;AAC9D,SAAO,eAAe,QAAQ,GAAG,IAAI;AACvC;AAEO,IAAM,SAAS;AAAA,EACpB,OAAO,CAAC,QAAsB;AAAE,YAAQ,OAAO,MAAM,EAAE,MAAM,KAAK,GAAG,IAAI,IAAI;AAAA,EAAG;AAAA,EAChF,MAAM,CAAC,QAAsB;AAAE,YAAQ,OAAO,MAAM,EAAE,MAAM,QAAQ,GAAG,IAAI,IAAI;AAAA,EAAG;AAAA,EAClF,MAAM,CAAC,QAAsB;AAAE,YAAQ,IAAI,EAAE,MAAM,MAAM,GAAG,CAAC;AAAA,EAAG;AAAA,EAChE,SAAS,CAAC,QAAsB;AAAE,YAAQ,IAAI,EAAE,MAAM,OAAO,GAAG,CAAC;AAAA,EAAG;AAAA,EACpE,QAAQ,CAAC,QAAsB;AAAE,YAAQ,IAAI,EAAE,MAAM,KAAK,OAAO,GAAG,CAAC;AAAA,EAAG;AAAA,EACxE,KAAK,CAAC,QAAsB;AAAE,YAAQ,IAAI,EAAE,MAAM,KAAK,GAAG,CAAC;AAAA,EAAG;AAAA,EAC9D,KAAK,CAAC,QAAsB;AAAE,YAAQ,IAAI,GAAG;AAAA,EAAG;AAAA,EAEhD,KAAK,CAAC,QAAwB,EAAE,MAAM,KAAK,GAAG;AAAA,EAC9C,QAAQ,CAAC,QAAwB,EAAE,MAAM,QAAQ,GAAG;AAAA,EACpD,OAAO,CAAC,QAAwB,EAAE,MAAM,OAAO,GAAG;AAAA,EAClD,MAAM,CAAC,QAAwB,EAAE,MAAM,MAAM,GAAG;AAAA,EAChD,MAAM,CAAC,QAAwB,EAAE,MAAM,MAAM,GAAG;AAAA,EAChD,MAAM,CAAC,QAAwB,EAAE,MAAM,MAAM,GAAG;AAAA,EAChD,MAAM,CAAC,QAAwB,EAAE,MAAM,KAAK,GAAG;AAAA,EAC/C,MAAM,CAAC,QAAwB,EAAE,MAAM,MAAM,GAAG;AAClD;;;ACxBO,SAAS,aAAa,QAA0B;AACrD,QAAM,EAAE,QAAQ,cAAc,cAAc,SAAS,IAAI;AACzD,QAAM,SAAS,OAAO,OAAO,OAAK,EAAE,aAAa,OAAO;AACxD,QAAM,QAAQ,OAAO,OAAO,OAAK,EAAE,aAAa,MAAM;AAEtD,UAAQ,IAAI,EAAE;AAEd,MAAI,OAAO,WAAW,KAAK,MAAM,WAAW,GAAG;AAC7C,WAAO,QAAQ,6DAAwD;AACvE,eAAW,cAAc,cAAc,QAAQ;AAC/C;AAAA,EACF;AAEA,MAAI,OAAO,SAAS,GAAG;AACrB,YAAQ,IAAI,OAAO,KAAK,OAAO,IAAI,aAAa,OAAO,MAAM,GAAG,CAAC,CAAC;AAClE,YAAQ,IAAI,EAAE;AACd,eAAW,SAAS,QAAQ;AAC1B,uBAAiB,OAAO,OAAO;AAAA,IACjC;AAAA,EACF;AAEA,MAAI,MAAM,SAAS,GAAG;AACpB,YAAQ,IAAI,OAAO,KAAK,OAAO,OAAO,eAAe,MAAM,MAAM,GAAG,CAAC,CAAC;AACtE,YAAQ,IAAI,EAAE;AACd,eAAW,SAAS,OAAO;AACzB,uBAAiB,OAAO,MAAM;AAAA,IAChC;AAAA,EACF;AAEA,aAAW,cAAc,cAAc,QAAQ;AACjD;AAEA,SAAS,iBAAiB,OAAc,OAA+B;AACrE,QAAM,OAAO,UAAU,UAAU,OAAO,IAAI,UAAK,IAAI,OAAO,OAAO,UAAK;AACxE,QAAM,UAAU,gBAAgB,MAAM,IAAI;AAC1C,QAAM,UAAU,UAAU,UACtB,OAAO,KAAK,OAAO,IAAI,MAAM,QAAQ,CAAC,IACtC,OAAO,KAAK,OAAO,OAAO,MAAM,QAAQ,CAAC;AAE7C,UAAQ,IAAI,GAAG,IAAI,KAAK,OAAO,KAAK,OAAO,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE;AACjE,UAAQ,IAAI,QAAQ,OAAO,KAAK,MAAM,OAAO,CAAC,EAAE;AAEhD,MAAI,MAAM,YAAY;AACpB,eAAW,OAAO,MAAM,WAAW,MAAM,GAAG,CAAC,GAAG;AAC9C,cAAQ,IAAI,QAAQ,OAAO,KAAK,cAAI,CAAC,IAAI,OAAO,KAAK,GAAG,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC,KAAK,OAAO,KAAK,IAAI,OAAO,CAAC,EAAE;AAAA,IAChH;AACA,QAAI,MAAM,WAAW,SAAS,GAAG;AAC/B,cAAQ,IAAI,QAAQ,OAAO,KAAK,cAAc,MAAM,WAAW,SAAS,CAAC,OAAO,CAAC,EAAE;AAAA,IACrF;AAAA,EACF;AAEA,MAAI,MAAM,YAAY;AACpB,UAAM,MAAM,GAAG,MAAM,WAAW,IAAI,IAAI,MAAM,WAAW,IAAI;AAC7D,YAAQ,IAAI,QAAQ,OAAO,KAAK,cAAI,CAAC,IAAI,OAAO,KAAK,GAAG,CAAC,EAAE;AAAA,EAC7D;AAEA,MAAI,MAAM,YAAY;AACpB,YAAQ,IAAI,QAAQ,OAAO,MAAM,QAAG,CAAC,IAAI,MAAM,UAAU,EAAE;AAAA,EAC7D;AAEA,UAAQ,IAAI,EAAE;AAChB;AAEA,SAAS,WAAW,cAAsB,cAAsB,UAAwB;AACtF,UAAQ,IAAI,EAAE;AACd,UAAQ;AAAA,IACN,OAAO;AAAA,MACL,aAAa,YAAY,YACxB,eAAe,IAAI,KAAK,YAAY,cAAc,MACnD,OAAO,QAAQ;AAAA,IACjB;AAAA,EACF;AACA,UAAQ,IAAI,EAAE;AAChB;AAEA,SAAS,gBAAgB,MAAsB;AAC7C,QAAM,SAAiC;AAAA,IACrC,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,EACnB;AACA,SAAO,OAAO,IAAI,KAAK;AACzB;AAwBO,SAAS,gBAAgB,QAAgC;AAC9D,SAAO;AAAA,IACL,SAAS,OAAO,OAAO,OAAO,OAAK,EAAE,aAAa,OAAO,EAAE,WAAW;AAAA,IACtE,SAAS;AAAA,MACP,QAAQ,OAAO,OAAO,OAAO,OAAK,EAAE,aAAa,OAAO,EAAE;AAAA,MAC1D,UAAU,OAAO,OAAO,OAAO,OAAK,EAAE,aAAa,MAAM,EAAE;AAAA,MAC3D,cAAc,OAAO;AAAA,MACrB,cAAc,OAAO;AAAA,MACrB,UAAU,OAAO;AAAA,IACnB;AAAA,IACA,QAAQ,OAAO,OAAO,IAAI,YAAU;AAAA,MAClC,UAAU,MAAM;AAAA,MAChB,MAAM,MAAM;AAAA,MACZ,UAAU,MAAM;AAAA,MAChB,SAAS,MAAM;AAAA,MACf,GAAI,MAAM,eAAe,SACrB,EAAE,YAAY,MAAM,WAAW,IAAI,QAAM,EAAE,MAAM,EAAE,MAAM,MAAM,EAAE,MAAM,QAAQ,EAAE,QAAQ,SAAS,EAAE,QAAQ,EAAE,EAAE,IAChH,CAAC;AAAA,MACL,GAAI,MAAM,eAAe,SACrB,EAAE,YAAY,EAAE,MAAM,MAAM,WAAW,MAAM,MAAM,MAAM,WAAW,KAAK,EAAE,IAC3E,CAAC;AAAA,MACL,GAAI,MAAM,eAAe,SAAY,EAAE,YAAY,MAAM,WAAW,IAAI,CAAC;AAAA,IAC3E,EAAE;AAAA,EACJ;AACF;AAEO,SAAS,WAAW,QAA0B;AACnD,UAAQ,IAAI,KAAK,UAAU,gBAAgB,MAAM,GAAG,MAAM,CAAC,CAAC;AAC9D;AAIO,SAAS,eAAe,QAA0B;AACvD,QAAM,EAAE,QAAQ,cAAc,SAAS,IAAI;AAC3C,QAAM,SAAS,OAAO,OAAO,OAAK,EAAE,aAAa,OAAO;AACxD,QAAM,QAAQ,OAAO,OAAO,OAAK,EAAE,aAAa,MAAM;AACtD,QAAM,QAAkB,CAAC;AAEzB,QAAM,KAAK,gCAAgC;AAC3C,QAAM,KAAK,EAAE;AAEb,MAAI,OAAO,WAAW,KAAK,MAAM,WAAW,GAAG;AAC7C,UAAM,KAAK,2DAAsD;AAAA,EACnE,OAAO;AACL,UAAM,QAAQ,OAAO,SAAS,IAAI,cAAO;AACzC,UAAM,KAAK,GAAG,KAAK,MAAM,OAAO,MAAM,cAAc,MAAM,MAAM,eAAe;AAC/E,UAAM,KAAK,EAAE;AAEb,QAAI,OAAO,SAAS,GAAG;AACrB,YAAM,KAAK,YAAY;AACvB,YAAM,KAAK,EAAE;AACb,iBAAW,SAAS,QAAQ;AAC1B,cAAM,KAAK,gBAAgB,KAAK,CAAC;AAAA,MACnC;AAAA,IACF;AAEA,QAAI,MAAM,SAAS,GAAG;AACpB,YAAM,KAAK,cAAc;AACzB,YAAM,KAAK,EAAE;AACb,iBAAW,SAAS,OAAO;AACzB,cAAM,KAAK,gBAAgB,KAAK,CAAC;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAEA,QAAM,KAAK,KAAK;AAChB,QAAM,KAAK,YAAY,YAAY,aAAa,QAAQ,KAAK;AAE7D,UAAQ,IAAI,MAAM,KAAK,IAAI,CAAC;AAC9B;AAEA,SAAS,gBAAgB,OAAsB;AAC7C,QAAM,QAAkB,CAAC;AACzB,QAAM,OAAO,MAAM,aAAa,UAAU,WAAM;AAChD,QAAM,KAAK,QAAQ,IAAI,MAAM,MAAM,QAAQ,IAAI;AAC/C,QAAM,KAAK,EAAE;AACb,QAAM,KAAK,MAAM,OAAO;AAExB,MAAI,MAAM,cAAc,MAAM,WAAW,SAAS,GAAG;AACnD,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,iBAAiB;AAC5B,eAAW,OAAO,MAAM,YAAY;AAClC,YAAM,KAAK,OAAO,IAAI,IAAI,IAAI,IAAI,IAAI,eAAU,IAAI,OAAO,IAAI;AAAA,IACjE;AAAA,EACF;AAEA,MAAI,MAAM,YAAY;AACpB,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,eAAQ,MAAM,UAAU,EAAE;AAAA,EACvC;AAEA,QAAM,KAAK,EAAE;AACb,SAAO,MAAM,KAAK,IAAI;AACxB;AAIO,SAAS,aAAa,QAAoB,QAA4B;AAC3E,QAAM,aAAa,OAAO,SAAS,KAAK,OAAO,QAAQ,OAAO,SAAS,KAAK,OAAO,SAAS,OAAO;AACnG,QAAM,YAAY,OAAO,SAAS,KAAK,WAAM,OAAO,SAAS,KAAK,WAAM;AAExE,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,OAAO,KAAK,6BAA6B,CAAC;AACtD,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,mBAAmB,WAAW,GAAG,OAAO,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE;AAC/E,UAAQ,IAAI,EAAE;AAEd,MAAI,OAAO,UAAU,SAAS,GAAG;AAC/B,YAAQ,IAAI,OAAO,KAAK,cAAc,CAAC;AACvC,eAAW,QAAQ,OAAO,WAAW;AACnC,YAAM,MAAM,KAAK,SAAS,IAAI,OAAO,IAAI,IAAI,KAAK,MAAM,MAAM,IAAI,OAAO,MAAM,OAAO;AACtF,cAAQ,IAAI,OAAO,KAAK,MAAM,OAAO,EAAE,CAAC,IAAI,OAAO,KAAK,KAAK,EAAE,SAAS,CAAC,CAAC,MAAM,GAAG,GAAG;AAAA,IACxF;AACA,YAAQ,IAAI,EAAE;AAAA,EAChB;AAEA,MAAI,OAAO,qBAAqB,SAAS,GAAG;AAC1C,YAAQ,IAAI,OAAO,KAAK,2BAA2B,CAAC;AACpD,WAAO,qBAAqB,QAAQ,CAAC,GAAG,QAAQ;AAC9C,cAAQ,IAAI,OAAO,MAAM,CAAC,KAAK,OAAO,KAAK,EAAE,IAAI,CAAC,KAAK,OAAO,KAAK,IAAI,EAAE,UAAU,SAAS,EAAE,eAAe,IAAI,KAAK,GAAG,GAAG,CAAC,EAAE;AAAA,IACjI,CAAC;AACD,YAAQ,IAAI,EAAE;AAAA,EAChB;AAEA,MAAI,OAAO,gBAAgB,SAAS,GAAG;AACrC,YAAQ,IAAI,OAAO,KAAK,oBAAoB,CAAC;AAC7C,eAAW,OAAO,OAAO,iBAAiB;AACxC,cAAQ,IAAI,OAAO,OAAO,MAAM,QAAG,CAAC,IAAI,GAAG,EAAE;AAAA,IAC/C;AACA,YAAQ,IAAI,EAAE;AAAA,EAChB;AAGA,eAAa,MAAM;AACrB;;;AR3OA,eAAsB,SAAS,SAAsC;AACnE,QAAM,EAAE,QAAQ,SAAS,QAAQ,IAAI,IAAI;AAEzC,kBAAgB,CAAC,OAAO;AAExB,QAAM,OAAO,YAAY,QAAQ,IAAI;AACrC,QAAM,cAAcE,MAAK,QAAQ,MAAM,QAAQ,OAAO;AACtD,QAAM,kBAAkBA,MAAK,QAAQ,MAAM,QAAQ,WAAW;AAE9D,QAAM,QAAQ,KAAK,IAAI;AAGvB,QAAM,CAAC,WAAW,aAAa,IAAI,MAAM,QAAQ,IAAI;AAAA,IACnD,aAAa,aAAa,KAAK;AAAA,IAC/B,aAAa,iBAAiB,IAAI;AAAA,EACpC,CAAC;AAGD,QAAM,EAAE,OAAO,aAAa,IAAI,MAAM,iBAAiB,MAAM;AAAA,IAC3D,QAAQ,QAAQ;AAAA,IAChB,kBAAkB;AAAA,EACpB,CAAC;AAGD,QAAM,aAAa,MAAM,QAAQ;AAAA,IAC/B,MAAM,IAAI,UAAQ,iBAAiB,MAAM,IAAI,CAAC;AAAA,EAChD;AAGA,QAAM,YAAY,oBAAI,IAA+B;AACrD,aAAW,UAAU,YAAY;AAC/B,QAAI,OAAO,WAAW,YAAa;AACnC,eAAW,OAAO,OAAO,OAAO;AAC9B,YAAM,WAAW,UAAU,IAAI,IAAI,IAAI,KAAK,CAAC;AAC7C,eAAS,KAAK,GAAG;AACjB,gBAAU,IAAI,IAAI,MAAM,QAAQ;AAAA,IAClC;AAAA,EACF;AAGA,QAAM,SAAS,QAAQ;AAAA,IACrB;AAAA,IACA,SAAS,UAAU;AAAA,IACnB,aAAa,cAAc;AAAA,EAC7B,CAAC;AAED,QAAM,WAAW,KAAK,IAAI,IAAI;AAE9B,QAAM,aAAyB;AAAA,IAC7B,aAAa;AAAA,IACb,cAAc,MAAM;AAAA,IACpB;AAAA,IACA;AAAA,IACA,SAAS,UAAU;AAAA,IACnB,aAAa,cAAc;AAAA,IAC3B;AAAA,IACA;AAAA,EACF;AAGA,MAAI,KAAK;AACP,UAAM,SAAS,YAAY,eAAe;AAAA,EAC5C;AAGA,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,iBAAW,UAAU;AACrB;AAAA,IACF,KAAK;AACH,qBAAe,UAAU;AACzB;AAAA,IACF;AACE,mBAAa,UAAU;AAAA,EAC3B;AAGA,QAAM,YAAY,OAAO,KAAK,OAAK,EAAE,aAAa,OAAO;AACzD,QAAM,WAAW,OAAO,KAAK,OAAK,EAAE,aAAa,MAAM;AAEvD,MAAI,aAAc,UAAU,UAAW;AACrC,YAAQ,KAAK,CAAC;AAAA,EAChB,WAAW,UAAU;AACnB,YAAQ,KAAK,CAAC;AAAA,EAChB,OAAO;AACL,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,eAAe,SAAS,QAAoB,iBAAwC;AAClF,QAAM,EAAE,WAAW,YAAY,IAAI;AAGnC,QAAM,UAAoB,CAAC;AAC3B,aAAW,CAAC,IAAI,KAAK,WAAW;AAC9B,QAAI,CAAC,YAAY,IAAI,IAAI,GAAG;AAC1B,cAAQ,KAAK,IAAI;AAAA,IACnB;AAAA,EACF;AAEA,MAAI,QAAQ,WAAW,EAAG;AAE1B,MAAI,WAAW;AACf,MAAI;AACF,eAAW,MAAMC,UAAS,iBAAiB,OAAO;AAAA,EACpD,QAAQ;AAAA,EAER;AAEA,QAAM,YAAY,QACf,KAAK,EACL,IAAI,UAAQ;AACX,UAAM,OAAO,OAAO,UAAU,IAAI,IAAI,KAAK,CAAC;AAC5C,UAAM,WAAW,KAAK,CAAC;AACvB,UAAM,UAAU,WAAW,oBAAoB,SAAS,IAAI,IAAI,SAAS,IAAI,KAAK;AAClF,WAAO,GAAG,IAAI,IAAI,OAAO;AAAA,EAC3B,CAAC,EACA,KAAK,IAAI;AAEZ,QAAM,aAAa,WACf,SAAS,QAAQ,IAAI,4CAA4C,YAAY,OAC7E,YAAY;AAEhB,QAAM,UAAU,iBAAiB,YAAY,OAAO;AACpD,UAAQ,IAAI;AAAA,iBAAoB,QAAQ,MAAM,mBAAmB,OAAO,YAAY,OAAO,IAAI,kBAAkB,cAAc,EAAE;AACnI;;;ASxIA,OAAOC,WAAU;AACjB,SAAS,aAAAC,YAAW,YAAAC,iBAAgB;AAQpC,eAAsB,QAAQ,SAAqC;AACjE,kBAAgB,CAAC,QAAQ,OAAO;AAEhC,QAAM,OAAO,YAAY,QAAQ,IAAI;AACrC,QAAM,cAAcC,MAAK,QAAQ,MAAM,QAAQ,OAAO;AACtD,QAAM,kBAAkBA,MAAK,QAAQ,MAAM,QAAQ,WAAW;AAE9D,SAAO,OAAO,kCAAkC;AAEhD,QAAM,QAAQ,KAAK,IAAI;AAGvB,QAAM,CAAC,WAAW,qBAAqB,IAAI,MAAM,QAAQ,IAAI;AAAA,IAC3D,aAAa,aAAa,KAAK;AAAA,IAC/B,aAAa,iBAAiB,IAAI;AAAA,EACpC,CAAC;AAGD,QAAM,EAAE,MAAM,IAAI,MAAM,iBAAiB,MAAM;AAAA,IAC7C,QAAQ,QAAQ;AAAA,IAChB,kBAAkB;AAAA,EACpB,CAAC;AAED,QAAM,aAAa,MAAM,QAAQ;AAAA,IAC/B,MAAM,IAAI,UAAQ,iBAAiB,MAAM,IAAI,CAAC;AAAA,EAChD;AAGA,QAAM,eAAe,oBAAI,IAA6B;AACtD,aAAW,UAAU,YAAY;AAC/B,QAAI,OAAO,WAAW,YAAa;AACnC,eAAW,OAAO,OAAO,OAAO;AAC9B,UAAI,CAAC,aAAa,IAAI,IAAI,IAAI,GAAG;AAC/B,qBAAa,IAAI,IAAI,MAAM,GAAG;AAAA,MAChC;AAAA,IACF;AAAA,EACF;AAEA,QAAM,cAAc,oBAAI,IAAI;AAAA,IAC1B,GAAG,aAAa,KAAK;AAAA,IACrB,GAAG,UAAU,KAAK,KAAK;AAAA,EACzB,CAAC;AAGD,QAAM,gBAAgB,IAAI,IAAI,sBAAsB,KAAK,KAAK,CAAC;AAC/D,QAAM,UAAoB,CAAC;AAC3B,QAAM,cAAwB,CAAC;AAE/B,aAAW,QAAQ,aAAa;AAC9B,QAAI,cAAc,IAAI,IAAI,GAAG;AAC3B,kBAAY,KAAK,IAAI;AAAA,IACvB,OAAO;AACL,cAAQ,KAAK,IAAI;AAAA,IACnB;AAAA,EACF;AAEA,MAAI,QAAQ,WAAW,KAAK,sBAAsB,QAAQ;AACxD,WAAO,QAAQ,iDAA4C,YAAY,MAAM,YAAY,YAAY,WAAW,IAAI,KAAK,GAAG;AAAA,CAAK;AACjI;AAAA,EACF;AAEA,QAAM,UAAU,oBAAoB;AAAA,IAClC,iBAAiB,sBAAsB,SACnC,MAAMC,UAAS,iBAAiB,OAAO,EAAE,MAAM,MAAM,EAAE,IACvD;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,UAAU;AAAA,IACnB,cAAc,QAAQ;AAAA,EACxB,CAAC;AAED,QAAMC,WAAU,iBAAiB,SAAS,OAAO;AAEjD,QAAM,WAAW,KAAK,IAAI,IAAI;AAE9B,SAAO;AAAA,IACL,aAAQ,sBAAsB,SAAS,YAAY,SAAS,IAAI,QAAQ,WAAW,SAC1E,YAAY,IAAI,YAAY,YAAY,SAAS,IAAI,KAAK,GAAG,KACjE,QAAQ,MAAM,SAAS,YAAY,MAAM;AAAA;AAAA,EAChD;AAEA,MAAI,QAAQ,SAAS,GAAG;AACtB,WAAO,KAAK,wBAAwB;AACpC,eAAW,QAAQ,QAAQ,KAAK,GAAG;AACjC,YAAM,MAAM,aAAa,IAAI,IAAI;AACjC,YAAM,MAAM,MAAM,OAAO,KAAK,YAAY,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE,IAAI;AACpE,aAAO,IAAI,OAAO,OAAO,KAAK,IAAI,CAAC,GAAG,GAAG,EAAE;AAAA,IAC7C;AAAA,EACF;AAEA,SAAO,KAAK;AAAA,iBAAoB,QAAQ;AAAA,CAAM;AAChD;AAWA,SAAS,oBAAoB,MAAmC;AAC9D,QAAM,EAAE,iBAAiB,SAAS,cAAc,SAAS,aAAa,IAAI;AAG1E,MAAI,oBAAoB,QAAQ,QAAQ,SAAS,GAAG;AAClD,UAAM,YAAY,QACf,KAAK,EACL,IAAI,UAAQ,UAAU,MAAM,aAAa,IAAI,IAAI,GAAG,SAAS,YAAY,CAAC,EAC1E,KAAK,IAAI;AAEZ,WAAO,gBAAgB,QAAQ,IAAI,qCAAqC,YAAY;AAAA,EACtF;AAGA,QAAM,WAAW,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAG,aAAa,KAAK,GAAG,GAAG,QAAQ,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK;AAChF,QAAM,QAAkB;AAAA,IACtB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,aAAW,QAAQ,UAAU;AAC3B,UAAM,KAAK,UAAU,MAAM,aAAa,IAAI,IAAI,GAAG,SAAS,YAAY,CAAC;AAAA,EAC3E;AAEA,SAAO,MAAM,KAAK,IAAI,IAAI;AAC5B;AAEA,SAAS,UACP,MACA,KACA,SACA,cACQ;AAER,QAAM,MAAM,QAAQ,IAAI,IAAI;AAC5B,QAAM,cAAc,KAAK,QAAQ,KAAK,IAAI,KAAK,KAAK;AAEpD,QAAM,UAAU,gBAAgB,MAC5B,qBAAqB,IAAI,IAAI,IAAI,IAAI,IAAI,KACzC;AAEJ,SAAO,GAAG,IAAI,IAAI,WAAW,GAAG,OAAO;AACzC;;;AC3JA,OAAOC,WAAU;AACjB,SAAS,YAAAC,WAAU,aAAAC,YAAW,aAAa;AAU3C,IAAM,kBAAkB,EAAE,OAAO,IAAI,MAAM,GAAG,MAAM,EAAE;AACtD,IAAM,YAAY;AAClB,IAAM,aAAa;AASnB,eAAsB,UAAU,SAAuC;AACrE,kBAAgB,CAAC,QAAQ,OAAO;AAEhC,QAAM,OAAO,YAAY,QAAQ,IAAI;AACrC,QAAM,cAAcC,MAAK,QAAQ,MAAM,QAAQ,OAAO;AACtD,QAAM,kBAAkBA,MAAK,QAAQ,MAAM,QAAQ,WAAW;AAE9D,QAAM,QAAQ,KAAK,IAAI;AAEvB,QAAM,CAAC,WAAW,aAAa,IAAI,MAAM,QAAQ,IAAI;AAAA,IACnD,aAAa,aAAa,KAAK;AAAA,IAC/B,aAAa,iBAAiB,IAAI;AAAA,EACpC,CAAC;AAED,QAAM,EAAE,OAAO,aAAa,IAAI,MAAM,iBAAiB,MAAM;AAAA,IAC3D,QAAQ,QAAQ;AAAA,IAChB,kBAAkB;AAAA,EACpB,CAAC;AAED,QAAM,aAAa,MAAM,QAAQ;AAAA,IAC/B,MAAM,IAAI,UAAQ,iBAAiB,MAAM,IAAI,CAAC;AAAA,EAChD;AAEA,QAAM,YAAY,oBAAI,IAA+B;AACrD,aAAW,UAAU,YAAY;AAC/B,QAAI,OAAO,WAAW,YAAa;AACnC,eAAW,OAAO,OAAO,OAAO;AAC9B,YAAM,WAAW,UAAU,IAAI,IAAI,IAAI,KAAK,CAAC;AAC7C,eAAS,KAAK,GAAG;AACjB,gBAAU,IAAI,IAAI,MAAM,QAAQ;AAAA,IAClC;AAAA,EACF;AAEA,QAAM,SAAS,QAAQ;AAAA,IACrB;AAAA,IACA,SAAS,UAAU;AAAA,IACnB,aAAa,cAAc;AAAA,EAC7B,CAAC;AAED,QAAM,WAAW,KAAK,IAAI,IAAI;AAE9B,QAAM,aAAyB;AAAA,IAC7B,aAAa;AAAA,IACb,cAAc,MAAM;AAAA,IACpB;AAAA,IACA;AAAA,IACA,SAAS,UAAU;AAAA,IACnB,aAAa,cAAc;AAAA,IAC3B;AAAA,IACA;AAAA,EACF;AAEA,QAAM,SAAS,kBAAkB,UAAU;AAG3C,QAAM,WAAW,MAAM,UAAU,IAAI;AACrC,MAAI,UAAU;AACZ,UAAM,QAAQ,OAAO,QAAQ,SAAS;AACtC,UAAM,QAAQ,QAAQ,IAAI,IAAI,KAAK,KAAK,OAAO,KAAK;AACpD,UAAM,QAAQ,QAAQ,IAAI,WAAM,QAAQ,IAAI,WAAM;AAClD,YAAQ,IAAI;AAAA,WAAc,KAAK,IAAI,KAAK,wBAAwB,SAAS,SAAS,GAAG;AAAA,EACvF;AAEA,QAAM,UAAU,MAAM,MAAM;AAE5B,eAAa,YAAY,MAAM;AAE/B,QAAM,YAAY,OAAO,KAAK,OAAK,EAAE,aAAa,OAAO;AACzD,QAAM,WAAW,OAAO,KAAK,OAAK,EAAE,aAAa,MAAM;AAEvD,MAAI,aAAc,QAAQ,UAAU,UAAW;AAC7C,YAAQ,KAAK,CAAC;AAAA,EAChB,WAAW,UAAU;AACnB,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;AAEA,SAAS,kBAAkB,QAAkC;AAC3D,QAAM,EAAE,OAAO,IAAI;AAEnB,QAAM,aAAa,OAAO,OAAO,OAAK,EAAE,aAAa,OAAO,EAAE;AAC9D,QAAM,YAAY,OAAO,OAAO,OAAK,EAAE,aAAa,MAAM,EAAE;AAE5D,QAAM,cACJ,aAAa,gBAAgB,QAAQ,YAAY,gBAAgB;AAEnE,QAAM,QAAQ,KAAK,IAAI,GAAG,MAAM,WAAW;AAG3C,QAAM,aAAqC,CAAC;AAC5C,aAAW,SAAS,QAAQ;AAC1B,eAAW,MAAM,IAAI,KAAK,WAAW,MAAM,IAAI,KAAK,KAAK;AAAA,EAC3D;AAEA,QAAM,YAAY,OAAO,QAAQ,UAAU,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM;AAClE,UAAM,MAAM,OACT,OAAO,OAAK,EAAE,SAAS,IAAI,EAC3B,OAAO,CAAC,KAAK,MAAM,MAAM,gBAAgB,EAAE,QAAQ,GAAG,CAAC;AAC1D,WAAO;AAAA,MACL,OAAO,gBAAgB,IAAI;AAAA,MAC3B;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,EACF,CAAC;AAGD,QAAM,aAAa,oBAAI,IAAoB;AAC3C,aAAW,SAAS,QAAQ;AAC1B,eAAW,OAAO,MAAM,cAAc,CAAC,GAAG;AACxC,iBAAW,IAAI,IAAI,OAAO,WAAW,IAAI,IAAI,IAAI,KAAK,KAAK,CAAC;AAAA,IAC9D;AAAA,EACF;AAEA,QAAM,uBAAuB,CAAC,GAAG,WAAW,QAAQ,CAAC,EAClD,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,EAC1B,MAAM,GAAG,CAAC,EACV,IAAI,CAAC,CAAC,MAAM,UAAU,OAAO,EAAE,MAAM,WAAW,EAAE;AAGrD,QAAM,kBAA4B,CAAC;AACnC,MAAI,OAAO,KAAK,OAAK,EAAE,SAAS,aAAa,EAAE,aAAa,OAAO,GAAG;AACpE,oBAAgB,KAAK,qDAAqD;AAAA,EAC5E;AACA,QAAM,aAAa,OAAO,OAAO,OAAK,EAAE,SAAS,QAAQ,EAAE,IAAI,OAAK,EAAE,QAAQ;AAC9E,MAAI,WAAW,SAAS,GAAG;AACzB,UAAM,OAAO,WAAW,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI;AAC7C,UAAM,OAAO,WAAW,SAAS,IAAI,MAAM,WAAW,SAAS,CAAC,WAAW;AAC3E,oBAAgB,KAAK,4BAA4B,IAAI,GAAG,IAAI,EAAE;AAAA,EAChE;AACA,MAAI,OAAO,KAAK,OAAK,EAAE,SAAS,eAAe,GAAG;AAChD,oBAAgB,KAAK,oEAAoE;AAAA,EAC3F;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,MAAsB;AAC7C,QAAM,SAAiC;AAAA,IACrC,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,EACnB;AACA,SAAO,OAAO,IAAI,KAAK;AACzB;AAEA,eAAe,UAAU,MAA0C;AACjE,QAAM,YAAYA,MAAK,KAAK,MAAM,WAAW,UAAU;AACvD,MAAI;AACF,UAAM,MAAM,MAAMC,UAAS,WAAW,OAAO;AAC7C,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,UAAU,MAAc,QAAqC;AAC1E,QAAM,WAAWD,MAAK,KAAK,MAAM,SAAS;AAC1C,QAAM,YAAYA,MAAK,KAAK,UAAU,UAAU;AAEhD,MAAI;AACF,UAAM,MAAM,UAAU,EAAE,WAAW,KAAK,CAAC;AACzC,UAAM,QAAoB;AAAA,MACxB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,aAAa,OAAO;AAAA,MACpB,YAAY,OAAO;AAAA,MACnB,WAAW,OAAO;AAAA,IACpB;AACA,UAAME,WAAU,WAAW,KAAK,UAAU,OAAO,MAAM,CAAC,GAAG,OAAO;AAAA,EACpE,QAAQ;AAAA,EAER;AACF;;;AXnMA,IAAM,iBAAiB,CAAC,gBAAgB,QAAQ,MAAM;AAEtD,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,YAAY,EACjB,YAAY,8FAAyF,EACrG,QAAQ,OAAO;AAIlB,QACG,QAAQ,OAAO,EACf,YAAY,6DAA6D,EACzE,OAAO,SAAS,qDAAqD,KAAK,EAC1E,OAAO,YAAY,qCAAqC,KAAK,EAC7D,OAAO,qBAAqB,qBAAqB,MAAM,EACvD,OAAO,yBAAyB,6BAA6B,cAAc,EAC3E,OAAO,0BAA0B,oCAAoC,cAAc,EACnF,OAAO,cAAc,2BAA2B,EAChD,OAAO,iBAAiB,uCAAuC,EAC/D;AAAA,EACC,IAAI,OAAO,qBAAqB,eAAe,EAAE,QAAQ,CAAC,UAAU,QAAQ,UAAU,CAAC,EAAE,QAAQ,QAAQ;AAC3G,EACC,OAAO,OAAO,SAAkC;AAC/C,QAAM,UAAwB;AAAA,IAC5B,KAAK,QAAQ,KAAK,KAAK,CAAC;AAAA,IACxB,QAAQ,QAAQ,KAAK,QAAQ,CAAC;AAAA,IAC9B,SAAS,OAAO,KAAK,SAAS,KAAK,MAAM;AAAA,IACzC,aAAa,OAAO,KAAK,aAAa,KAAK,cAAc;AAAA,IACzD,QAAQ,MAAM,QAAQ,KAAK,QAAQ,CAAC,IAAK,KAAK,QAAQ,IAAiB;AAAA,IACvE,QAAS,KAAK,QAAQ,KAAgC;AAAA,IACtD,SAAS,CAAC,KAAK,OAAO;AAAA,IACtB,MAAM,OAAO,KAAK,MAAM,KAAK,EAAE;AAAA,EACjC;AACA,QAAM,SAAS,OAAO,EAAE,MAAM,UAAU;AAC1C,CAAC;AAIH,QACG,QAAQ,MAAM,EACd,YAAY,+DAA+D,EAC3E,OAAO,qBAAqB,qBAAqB,MAAM,EACvD,OAAO,yBAAyB,6BAA6B,cAAc,EAC3E,OAAO,0BAA0B,oCAAoC,cAAc,EACnF,OAAO,mBAAmB,6CAA6C,KAAK,EAC5E,OAAO,cAAc,2BAA2B,EAChD,OAAO,iBAAiB,uCAAuC,EAC/D,OAAO,OAAO,SAAkC;AAC/C,QAAM,UAAuB;AAAA,IAC3B,SAAS,OAAO,KAAK,SAAS,KAAK,MAAM;AAAA,IACzC,aAAa,OAAO,KAAK,aAAa,KAAK,cAAc;AAAA,IACzD,QAAQ,MAAM,QAAQ,KAAK,QAAQ,CAAC,IAAK,KAAK,QAAQ,IAAiB;AAAA,IACvE,cAAc,QAAQ,KAAK,cAAc,CAAC;AAAA,IAC1C,SAAS,CAAC,KAAK,OAAO;AAAA,IACtB,MAAM,OAAO,KAAK,MAAM,KAAK,EAAE;AAAA,EACjC;AACA,QAAM,QAAQ,OAAO,EAAE,MAAM,UAAU;AACzC,CAAC;AAIH,QACG,QAAQ,QAAQ,EAChB,YAAY,sDAAsD,EAClE,OAAO,YAAY,qCAAqC,KAAK,EAC7D,OAAO,qBAAqB,qBAAqB,MAAM,EACvD,OAAO,yBAAyB,6BAA6B,cAAc,EAC3E,OAAO,0BAA0B,oCAAoC,cAAc,EACnF,OAAO,cAAc,2BAA2B,EAChD,OAAO,iBAAiB,uCAAuC,EAC/D;AAAA,EACC,IAAI,OAAO,qBAAqB,eAAe,EAAE,QAAQ,CAAC,UAAU,QAAQ,UAAU,CAAC,EAAE,QAAQ,QAAQ;AAC3G,EACC,OAAO,OAAO,SAAkC;AAC/C,QAAM,UAAU;AAAA,IACd,KAAK;AAAA,IACL,QAAQ,QAAQ,KAAK,QAAQ,CAAC;AAAA,IAC9B,SAAS,OAAO,KAAK,SAAS,KAAK,MAAM;AAAA,IACzC,aAAa,OAAO,KAAK,aAAa,KAAK,cAAc;AAAA,IACzD,QAAQ,MAAM,QAAQ,KAAK,QAAQ,CAAC,IAAK,KAAK,QAAQ,IAAiB;AAAA,IACvE,QAAS,KAAK,QAAQ,KAAgC;AAAA,IACtD,SAAS,CAAC,KAAK,OAAO;AAAA,IACtB,MAAM,OAAO,KAAK,MAAM,KAAK,EAAE;AAAA,EACjC;AACA,QAAM,UAAU,OAAO,EAAE,MAAM,UAAU;AAC3C,CAAC;AAEH,SAAS,WAAW,KAAqB;AACvC,QAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,UAAQ,OAAO,MAAM;AAAA,iBAAoB,OAAO;AAAA;AAAA,CAAM;AACtD,UAAQ,KAAK,CAAC;AAChB;AAEA,QAAQ,WAAW,QAAQ,IAAI,EAAE,MAAM,UAAU;","names":["path","readFile","path","path","readFile","path","path","readFile","path","path","readFile","path","writeFile","readFile","path","readFile","writeFile","path","readFile","writeFile","path","readFile","writeFile"]}
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@neerav34/env-doctor",
3
+ "version": "1.0.0",
4
+ "description": "The eslint of environment variables — catch missing env vars before they hit production",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "bin": {
8
+ "env-doctor": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist/",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsup",
17
+ "dev": "tsx src/index.ts",
18
+ "test": "vitest run",
19
+ "test:watch": "vitest",
20
+ "test:coverage": "vitest run --coverage",
21
+ "lint": "eslint src tests --ext .ts",
22
+ "lint:fix": "eslint src tests --ext .ts --fix",
23
+ "typecheck": "tsc --noEmit",
24
+ "dogfood": "node ./dist/index.js check --strict --ignore 'tests/**' '**/*.md' '**/*.d.ts'",
25
+ "prepublishOnly": "npm run typecheck && npm run test && npm run build"
26
+ },
27
+ "dependencies": {
28
+ "chalk": "^5.3.0",
29
+ "commander": "^12.0.0",
30
+ "fast-glob": "^3.3.2"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^20.0.0",
34
+ "@typescript-eslint/eslint-plugin": "^7.0.0",
35
+ "@typescript-eslint/parser": "^7.0.0",
36
+ "@vitest/coverage-v8": "^1.6.0",
37
+ "eslint": "^8.57.0",
38
+ "tsx": "^4.0.0",
39
+ "tsup": "^8.0.0",
40
+ "typescript": "^5.4.0",
41
+ "vitest": "^1.6.0"
42
+ },
43
+ "engines": {
44
+ "node": ">=18.0.0"
45
+ },
46
+ "keywords": [
47
+ "env",
48
+ "environment",
49
+ "variables",
50
+ "dotenv",
51
+ "cli",
52
+ "developer-tools",
53
+ "ci",
54
+ "devops",
55
+ "lint",
56
+ "security"
57
+ ],
58
+ "license": "MIT",
59
+ "author": "Neerav Jha",
60
+ "repository": {
61
+ "type": "git",
62
+ "url": "git+https://github.com/neerav34/env-doctor.git"
63
+ },
64
+ "homepage": "https://github.com/neerav34/env-doctor#readme",
65
+ "bugs": {
66
+ "url": "https://github.com/neerav34/env-doctor/issues"
67
+ },
68
+ "type": "module"
69
+ }