///|
pub fn schema_path(parts : Array[String]) -> String {
  let result : Array[String] = []
  for part in parts {
    let normalized = normalize_identifier(part)
    if normalized != "" {
      result.push(normalized)
    }
  }
  result.join(".")
}

///|
pub fn schema_index(path : String, index : Int) -> String {
  path + "[" + index.to_string() + "]"
}

///|
pub fn schema_child(path : String, child : String) -> String {
  if path == "" {
    normalize_identifier(child)
  } else {
    path + "." + normalize_identifier(child)
  }
}

///|
pub fn schema_is_array_path(path : String) -> Bool {
  path.contains("[") && path.contains("]")
}

///|
pub fn schema_parent(path : String) -> String {
  let last_dot = last_separator(path, '.')
  if last_dot < 0 {
    ""
  } else {
    substring_owned(path, 0, last_dot)
  }
}

///|
pub fn schema_leaf(path : String) -> String {
  let last_dot = last_separator(path, '.')
  if last_dot < 0 {
    path
  } else {
    substring_owned(path, last_dot + 1, path.length())
  }
}

///|
fn last_separator(text : String, separator : Char) -> Int {
  let mut found = -1
  for i, ch in text {
    if ch == separator {
      found = i
    }
  }
  found
}