harn-stdlib 0.10.171

Embedded Harn standard library source catalog
Documentation
import {
  AstParseError,
  AstParseErrorsResult,
  AstParserHealth,
  ast_parse_errors,
} from "std/ast/parse"

pub type AstParseDeltaRequest = {before?: string, after: string, language: string}

pub type AstParseDeltaStatus = "clean" | "unchanged" | "inconclusive" | "unavailable"

pub type AstParseDeltaResult = {
  status: AstParseDeltaStatus,
  before_health: AstParserHealth?,
  after_health: AstParserHealth,
  before_error_count: int?,
  after_error_count: int?,
  finding_count: int,
  findings: list<AstParseError>,
  primary: AstParseError?,
}

type UnchangedLines = {after_suffix: int, row_delta: int}

fn __ast_unchanged_lines(before: string, after: string) -> UnchangedLines {
  const old_lines = before.split("\n")
  const new_lines = after.split("\n")
  let prefix = 0
  while prefix < len(old_lines) && prefix < len(new_lines) {
    if old_lines[prefix] != new_lines[prefix] {
      break
    }
    prefix = prefix + 1
  }
  let suffix = 0
  while suffix < len(old_lines) - prefix && suffix < len(new_lines) - prefix
    && old_lines[len(old_lines) - suffix - 1] == new_lines[len(new_lines) - suffix - 1] {
    suffix = suffix + 1
  }
  return {after_suffix: len(new_lines) - suffix, row_delta: len(old_lines) - len(new_lines)}
}

fn __ast_error_key(error: AstParseError, row: int) -> string {
  return json_stringify([row, error.start_col, error.message, error.snippet, error.missing])
}

fn __ast_observed_error_count(result: AstParseErrorsResult?) -> int? {
  if result == nil || !result.supported || result.health.source.observation == "not_observed"
    || result.health.source.authority == nil {
    return nil
  }
  return len(result.errors)
}

/**
 * Compare installed-parser observations without treating error shape as syntax
 * authority. Unchanged lines relocate old findings; every unresolved fresh
 * finding is inconclusive until a named independent checker verifies source.
 * At most twenty findings are retained; finding_count reports the complete count.
 *
 * @effects: [ast]
 * @errors: []
 */
pub fn ast_parse_delta(ast: HarnessAst, request: AstParseDeltaRequest) -> AstParseDeltaResult {
  const after = ast_parse_errors(ast, request.after, request.language)
  const before: AstParseErrorsResult? = if request.before == nil || !after.supported {
    nil
  } else if request.before == request.after {
    after
  } else {
    ast_parse_errors(ast, request.before, request.language)
  }
  let status: AstParseDeltaStatus = "inconclusive"
  let findings: list<AstParseError> = []
  let primary: AstParseError? = nil
  let finding_count = 0
  if !after.supported || after.health.coverage == "unavailable" {
    status = "unavailable"
  } else if after.health.coverage == "verified" {
    status = "clean"
  } else {
    const lines = __ast_unchanged_lines(request.before ?? "", request.after)
    let remaining: dict<string, int> = {}
    if before != nil && before.supported {
      for error in before.errors {
        const key = __ast_error_key(error, error.start_row)
        remaining[key] = (remaining[key] ?? 0) + 1
      }
    }
    for error in after.errors {
      const old_row = if error.start_row >= lines.after_suffix {
        error.start_row + lines.row_delta
      } else {
        error.start_row
      }
      const key = __ast_error_key(error, old_row)
      const prior = remaining[key] ?? 0
      if prior > 0 {
        remaining[key] = prior - 1
        continue
      }
      finding_count = finding_count + 1
      if len(findings) < 20 {
        findings = findings + [error]
      }
      const previous = primary
      if previous == nil
        || error.end_byte - error.start_byte < previous.end_byte - previous.start_byte {
        primary = error
      }
    }
    if finding_count == 0 && before != nil && before.supported
      && after.health.source.authority != nil
      && after.health.source.observation != "not_observed" {
      status = "unchanged"
    }
  }
  return {
    status: status,
    before_health: if before != nil {
      before.health
    } else {
      nil
    },
    after_health: after.health,
    before_error_count: __ast_observed_error_count(before),
    after_error_count: __ast_observed_error_count(after),
    finding_count: finding_count,
    findings: findings,
    primary: primary,
  }
}