///|
fn code_at(text : String, index : Int) -> Int {
text[index].to_int()
}
///|
fn slice(text : String, start : Int, end : Int) -> String {
text[start:end].to_owned()
}
///|
fn is_ascii_space(code : Int) -> Bool {
code == 32 || code == 9 || code == 10 || code == 13
}
///|
fn trim_ascii(text : String) -> String {
let mut start = 0
let mut end = text.length()
while start < end && is_ascii_space(code_at(text, start)) {
start += 1
}
while end > start && is_ascii_space(code_at(text, end - 1)) {
end -= 1
}
slice(text, start, end)
}
///|
fn split_lines(text : String) -> Array[String] {
let lines : Array[String] = []
let mut start = 0
let mut index = 0
while index < text.length() {
if code_at(text, index) == 10 {
let mut end = index
if end > start && code_at(text, end - 1) == 13 {
end -= 1
}
lines.push(slice(text, start, end))
start = index + 1
}
index += 1
}
if start <= text.length() {
let mut end = text.length()
if end > start && code_at(text, end - 1) == 13 {
end -= 1
}
lines.push(slice(text, start, end))
}
lines
}
///|
fn starts_with(text : String, prefix : String) -> Bool {
prefix.length() <= text.length() && slice(text, 0, prefix.length()) == prefix
}
///|
fn ends_with(text : String, suffix : String) -> Bool {
suffix.length() <= text.length() &&
slice(text, text.length() - suffix.length(), text.length()) == suffix
}
///|
fn contains(text : String, needle : String) -> Bool {
if needle.length() == 0 {
return true
}
if needle.length() > text.length() {
return false
}
let limit = text.length() - needle.length()
let mut index = 0
while index <= limit {
if slice(text, index, index + needle.length()) == needle {
return true
}
index += 1
}
false
}
///|
fn index_of(text : String, needle : String) -> Int? {
if needle.length() == 0 {
return Some(0)
}
if needle.length() > text.length() {
return None
}
let limit = text.length() - needle.length()
let mut index = 0
while index <= limit {
if slice(text, index, index + needle.length()) == needle {
return Some(index)
}
index += 1
}
None
}
///|
fn ascii_lower_piece(code : Int, original : String) -> String {
match code {
65 => "a"
66 => "b"
67 => "c"
68 => "d"
69 => "e"
70 => "f"
71 => "g"
72 => "h"
73 => "i"
74 => "j"
75 => "k"
76 => "l"
77 => "m"
78 => "n"
79 => "o"
80 => "p"
81 => "q"
82 => "r"
83 => "s"
84 => "t"
85 => "u"
86 => "v"
87 => "w"
88 => "x"
89 => "y"
90 => "z"
_ => original
}
}
///|
fn ascii_lower(text : String) -> String {
let mut out = ""
let mut index = 0
while index < text.length() {
out = out +
ascii_lower_piece(code_at(text, index), slice(text, index, index + 1))
index += 1
}
out
}
///|
fn strip_quotes(text : String) -> String {
let trimmed = trim_ascii(text)
if trimmed.length() >= 2 &&
code_at(trimmed, 0) == 34 &&
code_at(trimmed, trimmed.length() - 1) == 34 {
slice(trimmed, 1, trimmed.length() - 1)
} else {
trimmed
}
}
///|
fn is_digit(code : Int) -> Bool {
code >= 48 && code <= 57
}
///|
fn is_ident_char(code : Int) -> Bool {
(code >= 97 && code <= 122) ||
(code >= 65 && code <= 90) ||
(code >= 48 && code <= 57) ||
code == 95 ||
code == 45
}
///|
fn has_placeholder(text : String) -> Bool {
let lower = ascii_lower(text)
contains(lower, "your-owner") ||
contains(lower, "your-github") ||
contains(lower, "todo") ||
contains(text, "<待填写>") ||
contains(text, "")
}
///|
fn severity_name(severity : Severity) -> String {
match severity {
Pass => "PASS"
Info => "INFO"
Warning => "WARN"
Error => "ERROR"
}
}
///|
fn category_name(category : Category) -> String {
match category {
Manifest => "manifest"
Readme => "readme"
CI => "ci"
License => "license"
Release => "release"
Repository => "repository"
}
}