// ../linter-gen/dist/generator/orchestrator.js
import * as fs3 from "fs/promises";
import * as path3 from "path";

// ../linter-gen/dist/parser/config-parser.js
import * as fs from "fs/promises";
import * as yaml from "yaml";

// ../linter-gen/dist/schema/linter-config.js
import { z } from "zod";
var RuleConfigSchema = z.object({
  /** Rule name in kebab-case (e.g., 'no-ui-in-services') */
  name: z.string().regex(/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/, "Rule name must be kebab-case"),
  /** Rule type - determines which template to use */
  type: z.string().min(1),
  /** ESLint severity level */
  severity: z.enum(["error", "warn", "off"]).default("error"),
  /** Template-specific configuration */
  config: z.record(z.unknown())
});
var LinterConfigSchema = z.object({
  /** Config version - currently only 1 is supported */
  version: z.literal(1),
  /** Output directory for generated rules */
  output: z.string().min(1),
  /** Optional explicit template path mappings (type → path) */
  templates: z.record(z.string()).optional(),
  /** Rules to generate */
  rules: z.array(RuleConfigSchema).min(1, "At least one rule is required")
});

// ../linter-gen/dist/parser/config-parser.js
var ParseError = class extends Error {
  code;
  cause;
  constructor(message, code, cause) {
    super(message);
    this.code = code;
    this.cause = cause;
    this.name = "ParseError";
  }
};
async function parseConfig(configPath) {
  let content;
  try {
    content = await fs.readFile(configPath, "utf-8");
  } catch (err) {
    if (err.code === "ENOENT") {
      return {
        success: false,
        error: new ParseError(`Config file not found: ${configPath}`, "FILE_NOT_FOUND", err)
      };
    }
    return {
      success: false,
      error: new ParseError(`Failed to read config file: ${configPath}`, "FILE_READ_ERROR", err)
    };
  }
  let parsed;
  try {
    parsed = yaml.parse(content);
  } catch (err) {
    return {
      success: false,
      error: new ParseError(`Invalid YAML syntax in ${configPath}: ${err.message}`, "YAML_PARSE_ERROR", err)
    };
  }
  const result = LinterConfigSchema.safeParse(parsed);
  if (!result.success) {
    const issues = result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
    return {
      success: false,
      error: new ParseError(`Invalid config: ${issues}`, "VALIDATION_ERROR", result.error)
    };
  }
  return {
    success: true,
    data: result.data,
    configPath
  };
}

// ../linter-gen/dist/engine/template-loader.js
import * as fs2 from "fs/promises";
import * as path from "path";
import { fileURLToPath } from "url";
var __filename = fileURLToPath(import.meta.url);
var __dirname = path.dirname(__filename);
var TemplateLoadError = class extends Error {
  code;
  cause;
  constructor(message, code, cause) {
    super(message);
    this.code = code;
    this.cause = cause;
    this.name = "TemplateLoadError";
  }
};
var BUILTIN_TEMPLATES = ["import-restriction", "boundary-validation", "dependency-graph"];
async function fileExists(filePath) {
  try {
    await fs2.access(filePath);
    return true;
  } catch {
    return false;
  }
}
async function loadTemplateFile(filePath, type) {
  try {
    const content = await fs2.readFile(filePath, "utf-8");
    return {
      success: true,
      source: { type, path: filePath, content }
    };
  } catch (err) {
    return {
      success: false,
      error: new TemplateLoadError(`Failed to read template: ${filePath}`, "TEMPLATE_READ_ERROR", err)
    };
  }
}
async function loadTemplate(ruleType, templatesConfig, configDir) {
  if (templatesConfig?.[ruleType]) {
    const explicitPath = path.resolve(configDir, templatesConfig[ruleType]);
    if (await fileExists(explicitPath)) {
      return loadTemplateFile(explicitPath, "explicit");
    }
    return {
      success: false,
      error: new TemplateLoadError(`Explicit template not found: ${explicitPath}`, "TEMPLATE_NOT_FOUND")
    };
  }
  const conventionPath = path.join(configDir, "templates", `${ruleType}.ts.hbs`);
  if (await fileExists(conventionPath)) {
    return loadTemplateFile(conventionPath, "convention");
  }
  if (BUILTIN_TEMPLATES.includes(ruleType)) {
    const builtinPath = path.join(__dirname, "..", "templates", `${ruleType}.ts.hbs`);
    if (await fileExists(builtinPath)) {
      return loadTemplateFile(builtinPath, "builtin");
    }
  }
  return {
    success: false,
    error: new TemplateLoadError(`Template not found for type '${ruleType}'. Checked: explicit config, ./templates/${ruleType}.ts.hbs, built-in templates.`, "TEMPLATE_NOT_FOUND")
  };
}

// ../linter-gen/dist/generator/rule-generator.js
import * as path2 from "path";

// ../linter-gen/dist/engine/context-builder.js
var GENERATOR_VERSION = "0.1.4";
function toCamelCase(str) {
  return str.replace(/-([a-z0-9])/g, (_, char) => char.toUpperCase());
}
function toPascalCase(str) {
  const camel = toCamelCase(str);
  return camel.charAt(0).toUpperCase() + camel.slice(1);
}
function buildRuleContext(rule, configPath) {
  return {
    name: rule.name,
    nameCamel: toCamelCase(rule.name),
    namePascal: toPascalCase(rule.name),
    severity: rule.severity,
    config: rule.config,
    meta: {
      generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
      generatorVersion: GENERATOR_VERSION,
      configPath
    }
  };
}

// ../linter-gen/dist/engine/template-renderer.js
import Handlebars from "handlebars";
var TemplateError = class extends Error {
  cause;
  constructor(message, cause) {
    super(message);
    this.cause = cause;
    this.name = "TemplateError";
  }
};
function toCamelCase2(str) {
  return str.replace(/-([a-z0-9])/g, (_, char) => char.toUpperCase());
}
function toPascalCase2(str) {
  const camel = toCamelCase2(str);
  return camel.charAt(0).toUpperCase() + camel.slice(1);
}
Handlebars.registerHelper("json", (obj) => JSON.stringify(obj));
Handlebars.registerHelper("jsonPretty", (obj) => JSON.stringify(obj, null, 2));
Handlebars.registerHelper("camelCase", (str) => toCamelCase2(str));
Handlebars.registerHelper("pascalCase", (str) => toPascalCase2(str));
function renderTemplate(templateSource, context) {
  try {
    const compiled = Handlebars.compile(templateSource, { strict: true });
    const output = compiled(context);
    return { success: true, output };
  } catch (err) {
    return {
      success: false,
      error: new TemplateError(`Template rendering failed: ${err.message}`, err)
    };
  }
}

// ../linter-gen/dist/generator/rule-generator.js
function generateRule(rule, template, outputDir, configPath) {
  const context = buildRuleContext(rule, configPath);
  const renderResult = renderTemplate(template.content, context);
  if (!renderResult.success) {
    return {
      success: false,
      error: renderResult.error,
      ruleName: rule.name
    };
  }
  const outputPath = path2.join(outputDir, `${rule.name}.ts`);
  return {
    success: true,
    rule: {
      name: rule.name,
      outputPath,
      content: renderResult.output
    }
  };
}

// ../linter-gen/dist/generator/index-generator.js
function toCamelCase3(str) {
  return str.replace(/-([a-z0-9])/g, (_, char) => char.toUpperCase());
}
function generateIndex(ruleNames) {
  const imports = ruleNames.map((name) => {
    const camel = toCamelCase3(name);
    return `import ${camel} from './${name}';`;
  }).join("\n");
  const rulesObject = ruleNames.map((name) => {
    const camel = toCamelCase3(name);
    return `  '${name}': ${camel},`;
  }).join("\n");
  const namedExports = ruleNames.map(toCamelCase3).join(", ");
  return `// Generated by @harness-engineering/linter-gen
// Do not edit manually - regenerate from harness-linter.yml

${imports}

export const rules = {
${rulesObject}
};

export { ${namedExports} };
`;
}

// ../linter-gen/dist/generator/orchestrator.js
async function validate(options) {
  const parseResult = await parseConfig(options.configPath);
  if (!parseResult.success) {
    return { success: false, error: parseResult.error };
  }
  return { success: true, ruleCount: parseResult.data.rules.length };
}
function resolveOutputDir(options, configOutput) {
  const configDir = path3.dirname(path3.resolve(options.configPath));
  return options.outputDir ? path3.resolve(options.outputDir) : path3.resolve(configDir, configOutput);
}
async function prepareOutputDir(outputDir, clean) {
  if (clean) {
    try {
      await fs3.rm(outputDir, { recursive: true, force: true });
    } catch {
    }
  }
  await fs3.mkdir(outputDir, { recursive: true });
}
async function processRule(rule, templates, configDir, outputDir, configPath, dryRun, errors) {
  const templateResult = await loadTemplate(rule.type, templates, configDir);
  if (!templateResult.success) {
    errors.push({ type: "template", error: templateResult.error, ruleName: rule.name });
    return null;
  }
  const ruleResult = generateRule(rule, templateResult.source, outputDir, configPath);
  if (!ruleResult.success) {
    errors.push({ type: "render", error: ruleResult.error, ruleName: ruleResult.ruleName });
    return null;
  }
  if (!dryRun) {
    try {
      await fs3.writeFile(ruleResult.rule.outputPath, ruleResult.rule.content, "utf-8");
    } catch (err) {
      errors.push({ type: "write", error: err, path: ruleResult.rule.outputPath });
      return null;
    }
  }
  return rule.name;
}
async function writeIndexFile(outputDir, generatedRules, errors) {
  const indexContent = generateIndex(generatedRules);
  const indexPath = path3.join(outputDir, "index.ts");
  try {
    await fs3.writeFile(indexPath, indexContent, "utf-8");
  } catch (err) {
    errors.push({ type: "write", error: err, path: indexPath });
  }
}
async function processAllRules(rules, templates, configDir, outputDir, configPath, dryRun, errors) {
  const generatedRules = [];
  for (const rule of rules) {
    const name = await processRule(rule, templates, configDir, outputDir, configPath, dryRun, errors);
    if (name)
      generatedRules.push(name);
  }
  return generatedRules;
}
async function generate(options) {
  const errors = [];
  const parseResult = await parseConfig(options.configPath);
  if (!parseResult.success) {
    return { success: false, errors: [{ type: "parse", error: parseResult.error }] };
  }
  const config = parseResult.data;
  const outputDir = resolveOutputDir(options, config.output);
  const dryRun = options.dryRun ?? false;
  const configDir = path3.dirname(path3.resolve(options.configPath));
  if (!dryRun) {
    await prepareOutputDir(outputDir, options.clean ?? false);
  }
  const generatedRules = await processAllRules(config.rules, config.templates, configDir, outputDir, options.configPath, dryRun, errors);
  if (generatedRules.length > 0 && !dryRun) {
    await writeIndexFile(outputDir, generatedRules, errors);
  }
  if (errors.length > 0) {
    return { success: false, errors };
  }
  return { success: true, rulesGenerated: generatedRules, outputDir, dryRun };
}

export {
  RuleConfigSchema,
  LinterConfigSchema,
  ParseError,
  TemplateLoadError,
  TemplateError,
  validate,
  generate
};
