Class SourceFileUri

java.lang.Object
org.ek9lang.core.SourceFileUri

public final class SourceFileUri extends Object
THE decoder turning a compiler source-token identifier into a filesystem path — use this, do not hand-roll the scheme strip.

Source tokens carry the parser's general identifier (CompilableSource#getGeneralIdentifier), which is a file: URI. Every layer that reports a location to a human or a tool has to get a plain path back out of it, so the same three lines had been written independently in compiler-services extractors, the CLI test runner and the IDE.

Why this lives in core, and why it is URI-based

It sits here because its callers span three modules — the compiler's own reporting, the MCP service layer and the JavaFX IDE — and the previous home was a support class inside mcp.oracle, invisible to anyone working in the IDE. That invisibility is precisely how the codebase ended up with three different conventions, consolidated 2026-08-04:

  • raw.substring(5) — eight sites. Wrong: a file:///Users/x token (the triple-slash form, which is legal and does occur) yields ///Users/x, and any percent-encoding survives into the reported path.
  • substring(5) followed by a loop stripping leading // — two byte-identical private copies. This is someone patching the first convention's triple-slash bug locally rather than finding the correct decoder; it still leaves percent-encoding.
  • Paths.get(URI.create(raw)) — correct on both counts, and what this class does.

Letting the URI machinery do the parsing is the whole point: the scheme, the authority-less triple slash and percent-decoding are its job, and re-deriving them by hand is how a path reported to a user acquires a leading // or a stray %20.

  • Method Details

    • toFsPath

      public static String toFsPath(String raw)
      Convert a source-token identifier to a plain filesystem path.

      Anything that is not a file: URI passes through untouched, so this is safe to apply to a value that may already be a plain path — several callers hold exactly that union. A URI that will not parse also passes through rather than throwing: a malformed location is worth reporting as-is, and is never worth failing an enquiry over.

      Parameters:
      raw - the source name, a file: URI or a plain path, or null
      Returns:
      the filesystem path, or null when given null
    • toGeneralIdentifier

      public static String toGeneralIdentifier(String fsPath)
      The inverse of toFsPath(String): a filesystem path as the compiler's general source identifier, the file: URI every CompilableSource, ErrorListener and source token carries, and the key under which LSP diagnostics are published.

      THE encoder — anything that must match a published identifier (clearing an editor's diagnostics on close, turning an extractor's plain path back into an LSP Location) goes through here. The LSP didClose used to clear diagnostics under the bare path while every publish used this form, so the keys never matched and squiggles outlived the buffer.

      Parameters:
      fsPath - a filesystem path (absolute or relative to the working directory)
      Returns:
      the file: URI form, or null when given null