// src/actions/deplint/getExternalImportsFromFiles.ts
import fs2 from "fs";
import chalk from "chalk";

// src/actions/deplint/getImportsFromFile.ts
import fs from "fs";
import path from "path";
import ts from "typescript";

// src/actions/deplint/getBasePackageName.ts
function getBasePackageName(importName) {
  const importNameScrubbed = importName.replaceAll('"', "").trim();
  if (importNameScrubbed.startsWith("@")) {
    const parts = importNameScrubbed.split("/");
    return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : importNameScrubbed;
  }
  return importNameScrubbed.split("/")[0];
}

// src/actions/deplint/getImportsFromFile.ts
function isTypeOnlyImportClause(clause) {
  if (clause === void 0) {
    return false;
  }
  if ("phaseModifier" in clause) {
    const mod = clause.phaseModifier;
    const kind = typeof mod === "number" ? mod : mod?.kind;
    return kind === ts.SyntaxKind.TypeKeyword;
  }
  return clause.isTypeOnly ?? false;
}
function getImportsFromFile(filePath, importPaths, typeImportPaths) {
  const sourceCode = fs.readFileSync(filePath, "utf8");
  const isMjsFile = filePath.endsWith(".mjs");
  const sourceFile = ts.createSourceFile(
    path.basename(filePath),
    sourceCode,
    ts.ScriptTarget.Latest,
    true,
    isMjsFile ? ts.ScriptKind.JS : void 0
  );
  const imports = [];
  const typeImports = [];
  const isDeclarationFile2 = filePath.endsWith(".d.ts");
  function visit(node) {
    if (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) {
      const moduleSpecifier = node.moduleSpecifier?.getFullText();
      const isTypeImport = ts.isImportDeclaration(node) ? isTypeOnlyImportClause(node.importClause) : false;
      if (typeof moduleSpecifier === "string") {
        const trimmed = moduleSpecifier.replaceAll("'", "").replaceAll('"', "").trim();
        if (isTypeImport || isDeclarationFile2) {
          typeImports.push(trimmed);
        } else {
          imports.push(trimmed);
        }
      }
    } else if (ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword) {
      const [arg] = node.arguments;
      if (ts.isStringLiteral(arg)) {
        imports.push(arg.text);
      }
    } else if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "require" && node.arguments.length > 0 && ts.isStringLiteral(node.arguments[0])) {
      imports.push(node.arguments[0].text);
    }
    ts.forEachChild(node, visit);
  }
  visit(sourceFile);
  for (const ref of sourceFile.typeReferenceDirectives) {
    typeImports.push(ref.fileName);
  }
  const importsStartsWithExcludes = [".", "#", "node:"];
  const isValidImport = (imp) => !importsStartsWithExcludes.some((exc) => imp.startsWith(exc)) && !imp.includes("*") && !imp.includes("!");
  const cleanedImports = imports.filter(isValidImport).map(getBasePackageName);
  const cleanedTypeImports = typeImports.filter(isValidImport).map(getBasePackageName);
  for (const imp of cleanedImports) {
    importPaths[imp] = importPaths[imp] ?? [];
    importPaths[imp].push(filePath);
  }
  for (const imp of cleanedTypeImports) {
    typeImportPaths[imp] = typeImportPaths[imp] ?? [];
    typeImportPaths[imp].push(filePath);
  }
  return [cleanedImports, cleanedTypeImports];
}

// src/actions/deplint/getExternalImportsFromFiles.ts
var internalImportPrefixes = [".", "#", "node:"];
var removeInternalImports = (imports) => {
  return imports.filter((imp) => !internalImportPrefixes.some((prefix) => imp.startsWith(prefix)));
};
var isDeclarationFile = (file) => file.endsWith(".d.ts") || file.endsWith(".d.cts") || file.endsWith(".d.mts");
var toolingConfigFilePattern = /(?:^|[\\/])xy\.config\.[cm]?[jt]sx?$/;
var isToolingConfigFile = (file) => toolingConfigFilePattern.test(file);
function excludeToolingConfigImports(paths) {
  const filtered = {};
  for (const [imp, files] of Object.entries(paths)) {
    const kept = files.filter((file) => !isToolingConfigFile(file));
    if (kept.length > 0) filtered[imp] = kept;
  }
  return filtered;
}
function warnMissingDist(name, location, allFiles) {
  if (allFiles.length > 0 && fs2.existsSync(`${location}/src`)) {
    const prefix = name ? `[${chalk.blue(name)}] ` : "";
    console.warn(`${prefix}${chalk.yellow("deplint: dist/ not found \u2014 using source imports (compile first for best accuracy)")}`);
  }
}
function shipsTsconfig(location) {
  try {
    const raw = fs2.readFileSync(`${location}/package.json`, "utf8");
    const pkg = JSON.parse(raw);
    const files = pkg.files;
    return files?.some((f) => f === "tsconfig.json" || f.includes("tsconfig")) ?? false;
  } catch {
    return false;
  }
}
function getExternalImportsFromFiles({
  allFiles,
  distFiles,
  location,
  name,
  tsconfigExtends = [],
  tsconfigTypes = []
}) {
  const srcImportPaths = {};
  const srcTypeImportPaths = {};
  for (const path2 of allFiles) getImportsFromFile(path2, srcImportPaths, srcTypeImportPaths);
  const allImportPaths = { ...srcImportPaths };
  for (const [key, paths] of Object.entries(srcTypeImportPaths)) {
    allImportPaths[key] = [...allImportPaths[key] ?? [], ...paths];
  }
  const distImportPaths = {};
  const distTypeImportPaths = {};
  const hasDist = distFiles.length > 0;
  if (hasDist) {
    const distTypeFiles = distFiles.filter(isDeclarationFile);
    const distCodeFiles = distFiles.filter((file) => !isDeclarationFile(file));
    for (const path2 of distCodeFiles) getImportsFromFile(path2, distImportPaths, distImportPaths);
    for (const path2 of distTypeFiles) getImportsFromFile(path2, distTypeImportPaths, distTypeImportPaths);
  } else {
    warnMissingDist(name, location, allFiles);
  }
  const effectiveDistImportPaths = hasDist ? distImportPaths : excludeToolingConfigImports(srcImportPaths);
  const effectiveDistTypeImportPaths = hasDist ? distTypeImportPaths : excludeToolingConfigImports(srcTypeImportPaths);
  const allImports = Object.keys(allImportPaths);
  const distImports = Object.keys(effectiveDistImportPaths);
  const externalAllImports = removeInternalImports(allImports);
  const externalDistImports = removeInternalImports(distImports);
  const externalDistTypeImports = removeInternalImports(Object.keys(effectiveDistTypeImportPaths));
  const isDistTsconfig = shipsTsconfig(location);
  for (const ext of tsconfigExtends) {
    if (!externalAllImports.includes(ext)) externalAllImports.push(ext);
    if (isDistTsconfig && !externalDistImports.includes(ext)) externalDistImports.push(ext);
  }
  for (const typ of tsconfigTypes) {
    if (!externalAllImports.includes(typ)) externalAllImports.push(typ);
  }
  return {
    allImportPaths,
    allImports,
    distImportPaths: effectiveDistImportPaths,
    distImports,
    externalAllImports,
    externalDistImports,
    externalDistTypeImports,
    tsconfigExtends: [...tsconfigExtends]
  };
}
export {
  getExternalImportsFromFiles
};
//# sourceMappingURL=getExternalImportsFromFiles.mjs.map