var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var renderGraph_exports = {};
__export(renderGraph_exports, {
  renderGraph: () => renderGraph
});
module.exports = __toCommonJS(renderGraph_exports);
var import_map = __toESM(require("@babel/runtime-corejs3/core-js/instance/map"));
var import_set = __toESM(require("@babel/runtime-corejs3/core-js/set"));
var import_for_each = __toESM(require("@babel/runtime-corejs3/core-js/instance/for-each"));
var import_from = __toESM(require("@babel/runtime-corejs3/core-js/array/from"));
var import_starts_with = __toESM(require("@babel/runtime-corejs3/core-js/instance/starts-with"));
var import_ends_with = __toESM(require("@babel/runtime-corejs3/core-js/instance/ends-with"));
var import_find = __toESM(require("@babel/runtime-corejs3/core-js/instance/find"));
var import_filter = __toESM(require("@babel/runtime-corejs3/core-js/instance/filter"));
var import_includes = __toESM(require("@babel/runtime-corejs3/core-js/instance/includes"));
var import_stringify = __toESM(require("@babel/runtime-corejs3/core-js/json/stringify"));
var import_fs = __toESM(require("fs"));
var import_node_crypto = __toESM(require("node:crypto"));
var import_path = __toESM(require("path"));
var import_path2 = require("path");
var import_graphql_server = require("@cedarjs/graphql-server");
var import_project_config = require("@cedarjs/project-config");
var import_structure = require("@cedarjs/structure");
var import_project = require("../../util/project");
var import_project2 = require("../../util/project");
const renderGraph = async ({
  routeName
}) => {
  var _context0;
  const config = await (0, import_project.getUserProjectConfig)();
  if (!config.experimental?.rsc?.enabled) {
    throw new import_graphql_server.SyntaxError("RSC is not enabled");
  }
  const parser = require("@babel/parser");
  const traverse = require("@babel/traverse").default;
  const generateId = (value) => {
    return import_node_crypto.default.createHash("md5").update(value).digest("hex");
  };
  const getRoutes = () => {
    const rwProject = (0, import_structure.getProject)((0, import_project2.getUserProjectPaths)().base);
    const routes2 = rwProject.getRouter().routes;
    return routes2;
  };
  const getPages = (routes2) => {
    var _context;
    const pages2 = (0, import_map.default)(_context = routes2 || getRoutes()).call(_context, (route) => route.page);
    return pages2;
  };
  const getLayouts = (pages2) => {
    const layouts2 = new import_set.default();
    const pagesWithLayout = pages2 || getPages();
    (0, import_for_each.default)(pagesWithLayout).call(pagesWithLayout, (page) => {
      var _context2;
      (0, import_for_each.default)(_context2 = page.parent.layouts).call(_context2, (layout) => {
        layouts2.add(layout);
      });
    });
    return (0, import_from.default)(layouts2);
  };
  const getRouteComponentData = (route) => {
    return {
      id: generateId(route.name || route.page_identifier_str),
      label: `/${route.name}` || route.page_identifier_str,
      componentType: "Route",
      filePath: route.parent.filePath,
      renderContext: "client"
    };
  };
  const getPageComponentData = (page) => {
    return {
      id: generateId(page.path),
      label: page.basenameNoExt,
      componentType: "Page",
      filePath: page.path,
      renderContext: "server"
    };
  };
  const getLayoutComponentData = (layout) => {
    return {
      id: generateId(layout.filePath),
      label: layout.basenameNoExt,
      componentType: "Layout",
      filePath: layout.filePath,
      renderContext: "client"
    };
  };
  const isInternalComponent = (importStatementPath) => {
    return ((0, import_starts_with.default)(importStatementPath).call(importStatementPath, ".") || (0, import_starts_with.default)(importStatementPath).call(importStatementPath, "src/")) && !(0, import_ends_with.default)(importStatementPath).call(importStatementPath, ".css");
  };
  const isValidComponentSpecifier = (specifier) => {
    if (specifier.toUpperCase() === specifier) {
      return false;
    }
    return /^[A-Z][a-zA-Z0-9]*$/.test(specifier);
  };
  const expandPath = (value, filename) => {
    const dirname = import_path.default.dirname(value);
    const basename2 = import_path.default.basename(value);
    const indexImportPath = [dirname, basename2, "index"].join("/");
    if ((0, import_project_config.resolveFile)(import_path.default.resolve(import_path.default.dirname(filename), indexImportPath))) {
      return indexImportPath;
    } else {
      const dirnameImportPath = [dirname, basename2, basename2].join("/");
      if ((0, import_project_config.resolveFile)(import_path.default.resolve(import_path.default.dirname(filename), dirnameImportPath))) {
        return dirnameImportPath;
      }
    }
    return null;
  };
  const resolveFileAndImportPaths = (filePath, importStatementPath) => {
    return (0, import_project_config.resolveFile)(import_path.default.resolve(import_path.default.dirname(filePath), importStatementPath)) || (0, import_project_config.resolveFile)(import_path.default.resolve((0, import_project2.getUserProjectPaths)().web.base, importStatementPath)) || (0, import_project_config.resolveFile)(expandPath(import_path.default.join((0, import_project2.getUserProjectPaths)().web.base, importStatementPath), importStatementPath));
  };
  const basenameNoExt = (path2) => {
    path2 = (0, import_path2.normalize)(path2);
    const parts = (0, import_path2.basename)(path2).split(".");
    if (parts.length > 1) {
      parts.pop();
    }
    return parts.join(".");
  };
  const isPage = (filePath) => {
    var _context3;
    return (0, import_find.default)(_context3 = getPages()).call(_context3, (page) => page.filePath === filePath);
  };
  const isLayout = (filePath) => {
    var _context4;
    return (0, import_find.default)(_context4 = getLayouts()).call(_context4, (layout) => layout.filePath === filePath);
  };
  const isRoute = (path2) => {
    var _context5;
    return (0, import_find.default)(_context5 = getRoutes()).call(_context5, (route) => route.path === path2);
  };
  const isCell = (filePath) => {
    var _context6;
    return (0, import_ends_with.default)(_context6 = basenameNoExt(filePath)).call(_context6, "Cell");
  };
  const buildRouteToPageEdges = (routes2, edges2) => {
    (0, import_for_each.default)(routes2).call(routes2, (route) => {
      edges2.push({
        id: generateId(`${route.page.filePath}-${route.name}`),
        source: generateId(route.name || route.page_identifier_str),
        target: generateId(route.page.filePath),
        label: `${route.name} routes to ${route.page.basenameNoExt} page`,
        type: "step",
        data: {
          source: route.page.filePath,
          target: route.name
        }
      });
    });
  };
  const buildLayoutToPageEdges = (pages2, edges2) => {
    (0, import_for_each.default)(pages2).call(pages2, (page) => {
      var _context7;
      (0, import_for_each.default)(_context7 = page.parent.layouts).call(_context7, (layout) => {
        edges2.push({
          id: generateId(`${page.filePath}-${layout.filePath}`),
          source: generateId(layout.filePath),
          target: generateId(page.filePath),
          label: `layout ${layout.basenameNoExt} wraps ${page.basenameNoExt} page`,
          type: "step",
          data: {
            source: page.filePath,
            target: layout.filePath
          }
        });
      });
    });
  };
  const buildNodes = (routeNodes2, pageNodes2, layoutNodes2) => {
    var _context8;
    return (0, import_map.default)(_context8 = [...routeNodes2, ...pageNodes2, ...layoutNodes2]).call(_context8, (data) => {
      return {
        id: data.id,
        data,
        position: {
          x: 0,
          y: 0
        }
      };
    });
  };
  const processedFiles = new import_set.default();
  function processComponentFilePathForGraph(nodes2, edges2, filePath) {
    let renderContext = "shared";
    if (processedFiles.has(filePath)) return;
    processedFiles.add(filePath);
    const content = import_fs.default.readFileSync(filePath, "utf8");
    const ast = parser.parse(content, {
      sourceType: "module",
      plugins: ["js", "jsx", "typescript"]
    });
    traverse(ast, {
      // here we determine the "default" render context
      // based on the presence of a "use client" or "use server" directive
      // Note: the renderContext will change based on the context of the parent(s)
      Program: function({
        node
      }) {
        var _context9;
        (0, import_for_each.default)(_context9 = node.directives).call(_context9, (directive) => {
          if (directive.value.value === "use client") {
            renderContext = "client";
          }
          if (directive.value.value === "use server") {
            renderContext = "server";
          }
        });
      },
      // here we build the dependency graph of the components
      // by processing the import statements and creating nodes and edges
      ImportDeclaration: function({
        node
      }) {
        const relativeImportPath = node.source.value;
        const importPath = resolveFileAndImportPaths(filePath, relativeImportPath);
        const specifiers = node.specifiers;
        if (isInternalComponent(relativeImportPath)) {
          if (specifiers.length) {
            (0, import_for_each.default)(specifiers).call(specifiers, (specifier) => {
              const name = specifier.local.name;
              if (isValidComponentSpecifier(name)) {
                const importId = generateId(`${import_path.default.basename(filePath)} -> ${relativeImportPath}`);
                let sourceType = "Component";
                let sourceId = null;
                let targetType = "Component";
                let targetId = null;
                if (isRoute(filePath)) {
                  sourceId = generateId(filePath);
                  sourceType = "Route";
                } else if (isPage(filePath)) {
                  sourceId = generateId(filePath);
                  sourceType = "Page";
                } else if (isLayout(filePath)) {
                  sourceId = generateId(filePath);
                  sourceType = "Layout";
                } else if (isCell(filePath)) {
                  sourceType = "Cell";
                  sourceId = filePath;
                } else {
                  sourceType = "Component";
                  if (basenameNoExt(importPath) === name) {
                    sourceId = generateId(filePath);
                  } else {
                    sourceId = generateId(`${filePath}-${name}`);
                  }
                }
                if (isPage(importPath)) {
                  targetId = generateId(importPath);
                  targetType = "Page";
                } else if (isLayout(importPath)) {
                  targetId = generateId(importPath);
                  targetType = "Layout";
                } else if (isCell(importPath)) {
                  targetType = "Cell";
                  targetId = filePath;
                } else {
                  targetType = "Component";
                  if (basenameNoExt(importPath) === name) {
                    targetId = generateId(importPath);
                  } else {
                    targetId = generateId(`${importPath}-${name}`);
                  }
                }
                const targetNode = {
                  id: targetId,
                  data: {
                    id: targetId,
                    label: name,
                    componentType: targetType,
                    filePath: importPath,
                    renderContext
                  },
                  position: {
                    x: 0,
                    y: 0
                  }
                };
                nodes2.push(targetNode);
                const edge = {
                  id: importId,
                  source: sourceId,
                  target: targetId,
                  label: `${name} component imported from ${basenameNoExt(filePath)}`,
                  type: "step",
                  data: {
                    source: sourceId,
                    sourceType,
                    target: targetId,
                    targetType
                  }
                };
                edges2.push(edge);
                if (importPath) {
                  processComponentFilePathForGraph(nodes2, edges2, importPath);
                }
              }
            });
          }
        }
      }
    });
  }
  function findAllAncestors(nodes2, edges2, targetNodeId) {
    const ancestors = [];
    function findAncestors(nodeId) {
      const incomingEdges = (0, import_filter.default)(edges2).call(edges2, (edge) => edge.target === nodeId);
      for (const edge of incomingEdges) {
        if (!(0, import_includes.default)(ancestors).call(ancestors, edge.source)) {
          ancestors.push(edge.source);
          findAncestors(edge.source);
        }
      }
    }
    findAncestors(targetNodeId);
    const ancestorNodes = (0, import_map.default)(ancestors).call(ancestors, (ancestorId) => (0, import_find.default)(nodes2).call(
      nodes2,
      (node) => node.id === ancestorId
      // && node.data.componentType === "Route"
    ));
    return ancestorNodes;
  }
  function findAllDescendants(nodes2, edges2, targetNodeId) {
    const descendants = [];
    function findDescendants(nodeId) {
      const outgoingEdges = (0, import_filter.default)(edges2).call(edges2, (edge) => edge.source === nodeId);
      for (const edge of outgoingEdges) {
        if (!(0, import_includes.default)(descendants).call(descendants, edge.target)) {
          descendants.push(edge.target);
          findDescendants(edge.target);
        }
      }
    }
    findDescendants(targetNodeId);
    const descendantNodes = (0, import_map.default)(descendants).call(descendants, (descendantId) => (0, import_find.default)(nodes2).call(
      nodes2,
      (node) => node.id === descendantId
      // && node.data.componentType === "Route"
    ));
    return descendantNodes;
  }
  const determineRenderContext = (nodes2, edges2, node) => {
    console.log("Determining render context for", node.renderContext);
    if (node.renderContext === "client") {
      console.log("All descendants of", node.data.label, "are client render context");
    }
    const ancestors = findAllAncestors(nodes2, edges2, node.id);
    (0, import_for_each.default)(ancestors).call(ancestors, (ancestor) => {
      if (ancestor) {
        if (ancestor.data.componentType === "Route" || ancestor.data.componentType === "Layout" || ancestor.data.componentType === "Page") {
          console.warn(`Skipping ${ancestor.data.label} as it is a ${ancestor.data.componentType} and its ancestor ${ancestor.data.label} is a ${ancestor.data.componentType}`);
          return;
        }
        if (ancestor.data.renderContext === "client") {
          const descendants = findAllDescendants(nodes2, edges2, node.id);
          (0, import_for_each.default)(descendants).call(descendants, (descendant) => {
            if (descendant) {
              descendant.style = {
                ...descendant.style,
                backgroundColor: "red",
                color: "white"
              };
              descendant.data.renderContext = "client";
            }
          });
        }
      }
    });
  };
  const routes = routeName ? (0, import_filter.default)(_context0 = getRoutes()).call(_context0, (route) => route.name === routeName) : getRoutes();
  if (routes.length === 0) {
    var _context1;
    throw new import_graphql_server.ValidationError(`No route found for ${routeName}. Try: ${(0, import_map.default)(_context1 = getRoutes()).call(_context1, (route) => route.name).join(", ")}`);
  }
  const routeNodes = (0, import_map.default)(routes).call(routes, (route) => getRouteComponentData(route));
  const pages = getPages(routes);
  const pageFilePath = pages[0].filePath;
  const pageNodes = (0, import_map.default)(pages).call(pages, (page) => getPageComponentData(page));
  const layouts = getLayouts(pages);
  const layoutFilePath = layouts[0].filePath;
  const layoutNodes = (0, import_map.default)(layouts).call(layouts, (layout) => getLayoutComponentData(layout));
  const nodes = buildNodes(routeNodes, pageNodes, layoutNodes);
  const edges = [];
  buildRouteToPageEdges(routes, edges);
  buildLayoutToPageEdges(pages, edges);
  processComponentFilePathForGraph(nodes, edges, pageFilePath);
  processComponentFilePathForGraph(nodes, edges, layoutFilePath);
  determineRenderContext(nodes, edges, pageNodes[0]);
  const idData = {
    id: generateId(routeName),
    route: {
      id: generateId(routeName),
      name: routeName
    },
    initialNodes: nodes,
    initialEdges: edges
  };
  return {
    id: generateId((0, import_stringify.default)(idData)),
    route: {
      id: generateId(routeName),
      name: routeName
    },
    initialNodes: nodes,
    initialEdges: edges
  };
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  renderGraph
});
//# sourceMappingURL=renderGraph.js.map
