{"version":3,"sources":["/Users/jeff/code/oss/logsdx/dist/chunk-QBEC4U26.cjs","../src/cli/index.ts","../src/parsers/regex/line.ts","../src/parsers/json/index.ts","../src/parsers/default.ts","../src/parsers/registry.ts"],"names":[],"mappings":"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","file":"/Users/jeff/code/oss/logsdx/dist/chunk-QBEC4U26.cjs","sourcesContent":[null,"#!/usr/bin/env node\n\nimport { Command } from \"commander\";\nimport fs from \"fs\";\nimport { styleManager, setTheme } from \"@/src/themes/asci/styles\";\nimport { logger } from \"@/src/utils/logger\";\nimport type { LogLevel, CliOptions } from \"@/src/types\";\nimport { getParser, getRegisteredParsers } from \"@/src/parsers/registry\";\nimport { loadConfig } from \"@/src/themes/asci/loader\";\n\nconst program = new Command();\n\nprogram\n  .name(\"logsdx\")\n  .description(\"A powerful log parsing and formatting tool\")\n  .version(\"0.0.1\");\n\nprogram\n  .option(\"-q, --quiet\", \"Suppress all output except errors\")\n  .option(\"-d, --debug\", \"Enable debug mode\")\n  .option(\"-l, --level <level>\", \"Minimum log level to display\", \"info\")\n  .option(\"-p, --parser <parser>\", \"Parser to use for log parsing\", \"default\")\n  .option(\"-r, --rules <file>\", \"Path to custom rules file\")\n  .option(\"-o, --output <file>\", \"Path to output file\")\n  .option(\"--list-parsers\", \"List available parsers\")\n  .option(\n    \"-t, --theme <theme>\",\n    \"Theme to use (default, dark, light, minimal, or custom theme name)\",\n  )\n  .option(\"--list-themes\", \"List available themes\")\n  .argument(\"[input]\", \"Input file to process (defaults to stdin)\")\n  .action(async (input: string, options: CliOptions) => {\n    try {\n      // Handle list parsers command\n      if (options.listParsers) {\n        const parsers = getRegisteredParsers();\n        logger.info(\"Available parsers:\");\n        parsers.forEach((parser) => logger.info(`  - ${parser}`));\n        process.exit(0);\n      }\n\n      // Handle list themes command\n      if (options.listThemes) {\n        const config = loadConfig();\n        const themes = config ? Object.keys(config.customThemes || {}) : [];\n        logger.info(\"Available themes:\");\n        logger.info(\"Built-in themes:\");\n        logger.info(\"  - default\");\n        logger.info(\"  - dark\");\n        logger.info(\"  - light\");\n        logger.info(\"  - minimal\");\n        if (themes.length > 0) {\n          logger.info(\"Custom themes:\");\n          themes.forEach((theme) => logger.info(`  - ${theme}`));\n        }\n        process.exit(0);\n      }\n\n      // Set up debug logging\n      if (options.debug) {\n        logger\n          .withConfig({ level: \"debug\", prefix: \"CLI\" })\n          .debug(\"Debug mode enabled\");\n      }\n\n      // Load and apply theme\n      const config = loadConfig();\n      if (options.theme) {\n        if (options.debug) {\n          logger\n            .withConfig({ level: \"debug\", prefix: \"CLI\" })\n            .debug(`Using theme: ${options.theme}`);\n        }\n        setTheme(options.theme);\n      } else if (config?.theme) {\n        if (options.debug) {\n          logger\n            .withConfig({ level: \"debug\", prefix: \"CLI\" })\n            .debug(`Using theme from config: ${config.theme}`);\n        }\n        setTheme(config.theme);\n      }\n\n      // Validate log level\n      if (\n        options.level &&\n        ![\"debug\", \"info\", \"warn\", \"error\"].includes(options.level)\n      ) {\n        throw new Error(`Invalid log level: ${options.level}`);\n      }\n\n      // Create input stream\n      const inputStream = input ? fs.createReadStream(input) : process.stdin;\n      if (input && options.debug) {\n        logger\n          .withConfig({ level: \"debug\", prefix: \"CLI\" })\n          .debug(`Input file set to: ${input}`);\n      }\n\n      // Create output stream\n      const outputStream = options.output\n        ? fs.createWriteStream(options.output)\n        : process.stdout;\n      if (options.output && options.debug) {\n        logger\n          .withConfig({ level: \"debug\", prefix: \"CLI\" })\n          .debug(`Output file set to: ${options.output}`);\n      }\n\n      // Get parser\n      const parser = await getParserForOptions(options);\n\n      // Process input\n      let buffer = \"\";\n      inputStream.on(\"data\", (chunk: Buffer | string) => {\n        buffer += chunk.toString();\n        const lines = buffer.split(\"\\n\");\n        buffer = lines.pop() || \"\";\n\n        for (const line of lines) {\n          if (!line.trim()) continue;\n\n          const parsed = parser(line);\n\n          // Determine the level for filtering, even if parsing failed\n          const level = parsed?.level || \"info\"; // Default to 'info' if undefined\n\n          // Check if the line should be rendered based on level\n          if (shouldRender(level, options.level as LogLevel)) {\n            // Always call styleLine, passing the original line, parsed result (can be undefined), and parser name\n            const formattedLine = styleManager.styleLine(\n              line,\n              parsed,\n              options.parser || \"default\",\n            );\n\n            // Use process.stdout.write for stdout, write for file streams\n            if (outputStream === process.stdout) {\n              process.stdout.write(formattedLine + \"\\n\");\n            } else {\n              (outputStream as fs.WriteStream).write(formattedLine + \"\\n\");\n            }\n          }\n        }\n      });\n\n      inputStream.on(\"end\", () => {\n        if (buffer.trim()) {\n          const parsed = parser(buffer);\n          const level = parsed?.level || \"info\";\n\n          if (shouldRender(level, options.level as LogLevel)) {\n            // Always call styleLine for the remaining buffer\n            const formattedLine = styleManager.styleLine(\n              buffer,\n              parsed,\n              options.parser || \"default\",\n            );\n\n            // Use process.stdout.write for stdout, write for file streams\n            if (outputStream === process.stdout) {\n              process.stdout.write(formattedLine + \"\\n\");\n            } else {\n              (outputStream as fs.WriteStream).write(formattedLine + \"\\n\");\n            }\n          }\n        }\n        if (options.output) {\n          (outputStream as fs.WriteStream).end();\n        }\n      });\n\n      inputStream.on(\"error\", (error: Error) => {\n        logger.error(\"Error reading input:\", error);\n        process.exit(1);\n      });\n    } catch (error) {\n      logger.error(\"Error:\", error as Error);\n      process.exit(1);\n    }\n  });\n\nprogram.parse();\n\n// Helper function to get parser for options\nasync function getParserForOptions(options: CliOptions) {\n  const parserName = options.parser || \"default\";\n\n  try {\n    if (options.debug) {\n      logger\n        .withConfig({ level: \"debug\", prefix: \"CLI\" })\n        .debug(`Using parser: ${parserName}`);\n    }\n\n    return await getParser(parserName, {\n      rulesFile: options.rules,\n    });\n  } catch (error) {\n    logger.error(`Error loading parser '${parserName}':`, error as Error);\n    logger.info(`Available parsers: ${getRegisteredParsers().join(\", \")}`);\n    process.exit(1);\n  }\n}\n\nfunction shouldRender(\n  level: string | undefined,\n  minLevel: LogLevel | undefined,\n): boolean {\n  if (!minLevel || !level) return true;\n\n  // Define log level priorities\n  const levelPriorities: Record<string, number> = {\n    debug: 0,\n    info: 1,\n    warn: 2,\n    error: 3,\n    success: 1,\n    trace: 0,\n  };\n\n  const current = levelPriorities[level] ?? 0;\n  const min = levelPriorities[minLevel] ?? 0;\n  return current >= min;\n}\n\nexport { program, getParserForOptions, shouldRender };\n","import { type RegexParserRule, type LineParser } from \"@/src/types\";\n\nexport function createRegexLineParser(rules: RegexParserRule[]): LineParser {\n  return (line) => {\n    let result: Record<string, any> | undefined;\n\n    // First, try to match the full log format\n    for (const rule of rules) {\n      const match = line.match(rule.match);\n      if (match) {\n        const extracted = rule.extract?.(line, match) || {};\n        // If we got a full match with timestamp, level, and message, return it\n        if (extracted.timestamp && extracted.level && extracted.message) {\n          return extracted;\n        }\n        // Otherwise, store the partial result, preserving existing values\n        result = {\n          ...extracted,\n          ...result, // This ensures earlier matches take precedence\n        };\n      }\n    }\n\n    // If we have a partial result\n    if (result) {\n      // Try to extract timestamp if not already present\n      if (!result.timestamp) {\n        const timestampMatch = line.match(\n          /(\\d{4}-\\d{2}-\\d{2}(?:T|\\s+)\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:Z|[+-]\\d{2}:?\\d{2})?)/,\n        );\n        if (timestampMatch) {\n          result.timestamp = timestampMatch[1];\n        }\n      }\n\n      // Try to extract message if not already present\n      if (!result.message) {\n        // Look for message after timestamp and level markers\n        const messageMatch = line.match(\n          /(?:\\]|\\d{2}(?:Z|[+-]\\d{2}:?\\d{2})?)\\s+(?:\\[\\w+\\])?\\s+(.+)$/,\n        );\n        if (messageMatch) {\n          result.message = messageMatch[1];\n        }\n      }\n\n      return result;\n    }\n\n    return undefined;\n  };\n}\n","import fs from \"fs\";\nimport JSON5 from \"json5\";\nimport {\n  type LineParser,\n  type LineParseResult,\n  type JSONRule,\n  type LogLevel,\n} from \"@/src/types\";\nimport { logger } from \"@/src/utils/logger\";\n\n// Default rules for JSON parsing\nexport const DEFAULT_JSON_RULES: JSONRule[] = [\n  {\n    match: \"\\\\{.*\\\\}\",\n    lang: \"json\",\n    level: \"info\",\n    meta: {\n      service: \"service\",\n      timestamp: \"timestamp\",\n      message: \"message\",\n      level: \"level\",\n    },\n  },\n];\n\n/**\n * Maps various log level formats to our standard log levels\n * @param level The log level to map\n * @returns A standardized log level\n */\nexport function mapLogLevel(level: string): LogLevel {\n  const levelMap: Record<string, LogLevel> = {\n    // Standard levels\n    debug: \"debug\",\n    info: \"info\",\n    warn: \"warn\",\n    warning: \"warn\",\n    error: \"error\",\n    err: \"error\",\n    success: \"success\",\n    trace: \"trace\",\n\n    // Common variations\n    fatal: \"error\",\n    critical: \"error\",\n    notice: \"info\",\n    verbose: \"debug\",\n    silly: \"debug\",\n\n    // Status-based levels\n    fail: \"error\",\n    failed: \"error\",\n    failure: \"error\",\n    pending: \"warn\",\n    in_progress: \"info\",\n    completed: \"success\",\n  };\n\n  const normalizedLevel = level.toLowerCase().trim();\n  return levelMap[normalizedLevel] || \"info\";\n}\n\n/**\n * Loads JSON rules from a file or uses default rules\n * @param filePath Optional path to a custom rules file\n * @returns A line parser function\n */\nexport async function loadJsonRules(filePath?: string): Promise<LineParser> {\n  let rules: JSONRule[] = DEFAULT_JSON_RULES;\n\n  // If a file path is provided, try to load custom rules\n  if (filePath) {\n    try {\n      const data = fs.readFileSync(filePath, \"utf-8\");\n      const customRules = JSON5.parse(data);\n      if (Array.isArray(customRules) && customRules.length > 0) {\n        rules = customRules;\n      }\n    } catch (error) {\n      logger.warn(\n        `Failed to load custom JSON rules: ${JSON5.stringify(error)}`,\n      );\n      logger.info(\"Using default JSON rules instead\");\n    }\n  }\n\n  // Create a direct JSON parser using JSON5\n  return (line: string): LineParseResult | undefined => {\n    try {\n      // Check if the line looks like JSON\n      if (!line.trim().startsWith(\"{\") || !line.trim().endsWith(\"}\")) {\n        return undefined;\n      }\n\n      // Parse the JSON using JSON5\n      const json = JSON5.parse(line);\n\n      // Extract common log fields\n      const result: LineParseResult = {\n        level: mapLogLevel(\n          json.level || json.status || json.severity || \"info\",\n        ),\n        timestamp:\n          json.timestamp || json.time || json.date || json[\"@timestamp\"],\n        message: json.message || json.msg || json.log || json.text,\n        language: \"json\",\n      };\n\n      // Add all other fields as metadata\n      for (const [key, value] of Object.entries(json)) {\n        if (\n          ![\n            \"level\",\n            \"status\",\n            \"severity\",\n            \"timestamp\",\n            \"time\",\n            \"date\",\n            \"@timestamp\",\n            \"message\",\n            \"msg\",\n            \"log\",\n            \"text\",\n          ].includes(key)\n        ) {\n          result[key] = value;\n        }\n      }\n\n      return result;\n    } catch (error) {\n      // If parsing fails, return undefined to let other parsers handle it\n      return undefined;\n    }\n  };\n}\n","import { type LineParseResult, type LineParser } from \"../types\";\n\nexport const defaultLineParser: LineParser = (line) => {\n  const result: LineParseResult = {};\n\n  if (line.startsWith(\"[json]\")) result.lang = \"json\";\n  if (line.startsWith(\"[sql]\")) result.lang = \"sql\";\n  if (line.includes(\"ERROR\")) result.level = \"error\";\n  if (line.includes(\"WARN\")) result.level = \"warn\";\n  if (line.includes(\"INFO\")) result.level = \"info\";\n\n  return result;\n};\n","import { type LineParser } from \"@/src/types\";\nimport { createRegexLineParser } from \"@/src/parsers/regex/line\";\nimport { loadJsonRules } from \"@/src/parsers/json\";\nimport { defaultLineParser } from \"@/src/parsers/default\";\n\n// Default configuration for regex parser\nexport const DEFAULT_CONFIG = {\n  defaultRules: [\n    {\n      match:\n        /^(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}.\\d{3}Z)\\s+\\[(\\w+)\\]\\s+(.*)$/,\n      extract: (line: string, match: RegExpMatchArray) => ({\n        timestamp: match[1],\n        level: match[2].toLowerCase() as any,\n        message: match[3],\n      }),\n    },\n  ],\n  levels: {\n    debug: 0,\n    info: 1,\n    warn: 2,\n    error: 3,\n  },\n};\n\n// Registry to store available parsers\nexport const parserRegistry: Record<\n  string,\n  (options?: any) => Promise<LineParser>\n> = {\n  // Default parser\n  default: async () => defaultLineParser,\n\n  // Built-in parsers\n  regex: async () => {\n    return createRegexLineParser(DEFAULT_CONFIG.defaultRules);\n  },\n\n  json: async (options?: { rulesFile?: string }) => {\n    return loadJsonRules(options?.rulesFile);\n  },\n};\n\n/**\n * Register a new parser\n * @param name The name of the parser\n * @param factory The factory function that creates the parser\n */\nexport function registerParser(\n  name: string,\n  factory: (options?: any) => Promise<LineParser>,\n): void {\n  parserRegistry[name] = factory;\n}\n\n/**\n * Get a parser by name\n * @param name The name of the parser\n * @param options Options to pass to the parser factory\n * @returns The parser function\n */\nexport async function getParser(\n  name: string,\n  options?: any,\n): Promise<LineParser> {\n  if (!parserRegistry[name]) {\n    throw new Error(\n      `Parser '${name}' not found. Available parsers: ${Object.keys(parserRegistry).join(\", \")}`,\n    );\n  }\n\n  return parserRegistry[name](options);\n}\n\n/**\n * Get all registered parser names\n * @returns Array of parser names\n */\nexport function getRegisteredParsers(): string[] {\n  return Object.keys(parserRegistry);\n}\n"]}