Repository: apple/pkl
File: pkl-core/src/main/java/org/pkl/core/project/Project.java (Java)

Code before:
        path, securityManager, timeout, StackFrameTransformers.defaultTransformer, System.getenv());
  }

  /**
   * Convenience method to load a project with the default security manager, no timeout, and the
   * default stack frame transformer.
   */
  public static Project loadFromPath(Path path) {
    return loadFromPath(path, SecurityManagers.defaultManager, null);
  }

  /** Loads a project from the given source. */
  public static Project load(ModuleSource moduleSource) {
    try (var evaluator = evaluatorBuilder().build()) {
      return load(evaluator, moduleSource);
    }
  }

  public static Project load(Evaluator evaluator, ModuleSource moduleSource) {
    try {
      var output = evaluator.evaluateOutputValueAs(moduleSource, PClassInfo.Project);
      return Project.parseProject(output);
    } catch (StackOverflowError e) {
      var cycle = findImportCycle(moduleSource);
      if (cycle != null) {
        throw new PklException(ErrorMessages.create("dependencyCycle", renderCycle(cycle)));
      }
      throw e;
    } catch (URISyntaxException e) {
      throw new PklException(e.getMessage(), e);
    }
  }

  private static String renderCycle(List<URI> cycle) {
    var sb = new StringBuilder();
    sb.append("┌─>");
    var isFirst = true;
    for (URI uri : cycle) {
      if (isFirst) {
        isFirst = false;
      } else {
        sb.append("\n│");
      }
      sb.append("\n│  ");
      sb.append(uri.toString());
    }
    sb.append("\n└─ ");
    return sb.toString();
  }

  private static @Nullable List<URI> findImportCycle(ModuleSource moduleSource) {

Review comment (suggestion):
```suggestion
        throw new PklException(ErrorMessages.create("cannotHaveCircularProjectDependencies", renderCycle(cycle)));
```

Code after:
        path, securityManager, timeout, StackFrameTransformers.defaultTransformer, System.getenv());
  }

  /**
   * Convenience method to load a project with the default security manager, no timeout, and the
   * default stack frame transformer.
   */
  public static Project loadFromPath(Path path) {
    return loadFromPath(path, SecurityManagers.defaultManager, null);
  }

  /** Loads a project from the given source. */
  public static Project load(ModuleSource moduleSource) {
    try (var evaluator = evaluatorBuilder().build()) {
      return load(evaluator, moduleSource);
    }
  }

  public static Project load(Evaluator evaluator, ModuleSource moduleSource) {
    try {
      var output = evaluator.evaluateOutputValueAs(moduleSource, PClassInfo.Project);
      return Project.parseProject(output);
    } catch (StackOverflowError e) {
      var cycles = findImportCycle(moduleSource);
      VmException vmException;
      if (!cycles.isEmpty()) {
        if (cycles.size() == 1) {
          vmException =
              new VmExceptionBuilder()
                  .evalError(
                      "cannotHaveCircularProjectDependenciesSingle",
                      renderCycle(cycles.stream().toList().get(0)))
                  .withCause(e)
                  .build();
        } else {
          var renderedCycles = renderMultipleCycles(cycles);
          vmException =
              new VmExceptionBuilder()
                  .evalError("cannotHaveCircularProjectDependenciesMultiple", renderedCycles)
                  .withCause(e)
                  .build();
        }
        // stack frame transformer never used; this exception has no stack frames.
        throw vmException.toPklException(StackFrameTransformers.defaultTransformer);
      }
      throw e;
    } catch (URISyntaxException e) {
      throw new PklException(e.getMessage(), e);
    }
  }