harn-stdlib 0.10.114

Embedded Harn standard library source catalog
Documentation
pub type GitHubRepoRef = {owner: string, name: string, full_name: string}

fn __github_strip_git_suffix(value) {
  const text = trim(to_string(value ?? ""))
  if ends_with(text, ".git") {
    return substring(text, 0, len(text) - len(".git"))
  }
  return text
}

fn __github_slug_match(pattern, text) {
  const captures = regex_captures(pattern, text)
  if len(captures) == 0 {
    return nil
  }
  const groups = captures[0].groups
  if len(groups) < 2 {
    return nil
  }
  const owner = trim(to_string(groups[0]))
  const repo = __github_strip_git_suffix(groups[1])
  if owner == "" || repo == "" || contains(owner, "/") || contains(repo, "/") {
    return nil
  }
  return owner + "/" + repo
}

/**
 * github_slug_from_remote returns `owner/repo` for common GitHub SSH and HTTPS remote URLs.
 *
 * @effects: []
 * @errors: []
 */
pub fn github_slug_from_remote(url: string) -> string? {
  const text = trim(to_string(url ?? ""))
  if text == "" {
    return nil
  }
  const url_slug = __github_slug_match(
    "^(?:git\\+)?(?:https?|ssh|git)://(?:[^@/]+@)?github\\.com(?::[0-9]+)?/([^/]+)/([^/#?]+)(?:[?#].*)?$",
    text,
  )
  if url_slug != nil {
    return url_slug
  }
  return __github_slug_match("^(?:[^@/]+@)?github\\.com:([^/]+)/([^/#?]+)(?:[?#].*)?$", text)
}

/**
 * github_repo normalizes an `owner/repo` slug, GitHub remote URL, or owner+repo pair.
 *
 * @effects: []
 * @errors: []
 */
pub fn github_repo(repo: any, name: string? = nil) -> GitHubRepoRef? {
  if name != nil {
    const owner = trim(to_string(repo ?? ""))
    const repo_name = __github_strip_git_suffix(name)
    if owner == "" || repo_name == "" {
      return nil
    }
    return {owner: owner, name: repo_name, full_name: owner + "/" + repo_name}
  }
  if type_of(repo) == "dict" {
    const full_name = repo?.full_name
    if full_name != nil {
      return github_repo(full_name)
    }
    const owner = repo?.owner ?? repo?.owner_login
    const repo_name = repo?.name ?? repo?.repo
    if owner != nil && repo_name != nil {
      return github_repo(owner, repo_name)
    }
    return nil
  }
  const raw = trim(to_string(repo ?? ""))
  const slug = if contains(raw, "github.com") || contains(raw, "://") {
    github_slug_from_remote(raw)
  } else {
    raw
  }
  if slug == nil || !contains(slug, "/") {
    return nil
  }
  const parts = split(slug, "/")
  if len(parts) != 2 {
    return nil
  }
  return github_repo(parts[0], parts[1])
}

/**
 * Parse a repository reference or raise the connector's canonical input error.
 *
 * @effects: []
 * @errors: [runtime]
 */
pub fn github_repo_or_throw(repo, name = nil) -> GitHubRepoRef {
  const parsed = github_repo(repo, name)
  if parsed == nil {
    throw "std/connectors/github: expected repo as owner/repo, GitHub remote URL, or owner + repo"
  }
  return parsed
}