///|
pub enum Severity {
Error
Warning
} derive(Debug, Eq, ToJson, FromJson)
///|
pub struct Diagnostic {
severity : Severity
code : String
message : String
} derive(Debug, Eq, ToJson, FromJson)
///|
pub struct DiagnosticSummary {
errors : Int
warnings : Int
} derive(Debug, Eq, ToJson, FromJson)
///|
fn error(code : String, message : String) -> Diagnostic {
{ severity: Error, code, message }
}
///|
fn warning(code : String, message : String) -> Diagnostic {
{ severity: Warning, code, message }
}
///|
pub fn validate_sheet(sheet : SpriteSheet) -> Array[Diagnostic] {
let diagnostics : Array[Diagnostic] = []
let sheet_bounds = { x: 0, y: 0, w: sheet.size.w, h: sheet.size.h }
if sheet.frames.length() == 0 {
diagnostics.push(error("empty_frames", "sprite sheet contains no frames"))
}
if sheet.size.w <= 0 || sheet.size.h <= 0 {
diagnostics.push(error("invalid_sheet_size", "sheet size must be positive"))
}
for frame in sheet.frames {
if frame.duration <= 0 {
diagnostics.push(
error(
"invalid_duration",
"frame duration must be positive: \{frame.filename}",
),
)
}
if frame.source_size.w <= 0 || frame.source_size.h <= 0 {
diagnostics.push(
error(
"invalid_source_size",
"frame source size must be positive: \{frame.filename}",
),
)
}
let source_bounds = {
x: 0,
y: 0,
w: frame.source_size.w,
h: frame.source_size.h,
}
if frame.frame.is_empty() || !sheet_bounds.contains_rect(frame.frame) {
diagnostics.push(
error(
"frame_out_of_bounds", "frame rectangle is outside sheet: \\{frame.filename}",
),
)
}
if frame.sprite_source_size.is_empty() ||
!source_bounds.contains_rect(frame.sprite_source_size) {
diagnostics.push(
error(
"source_rect_out_of_bounds", "sprite source rectangle is outside source size: \\{frame.filename}",
),
)
}
for box in frame.boxes {
if box.rect.is_empty() || !source_bounds.contains_rect(box.rect) {
diagnostics.push(
warning(
"collision_box_out_of_bounds", "collision box is outside source size: \\{frame.filename}",
),
)
}
}
}
for tag in sheet.tags {
if tag.from < 0 || tag.to < tag.from || tag.to >= sheet.frames.length() {
diagnostics.push(
error("tag_out_of_range", "tag range is outside frames: \{tag.name}"),
)
}
if tag.name == "" {
diagnostics.push(warning("empty_tag_name", "frame tag has an empty name"))
}
}
for i in 0..
diagnostics.push(
warning(
"nine_patch_center_out_of_bounds", "nine-patch center is outside slice: \\{slice.name}",
),
)
_ => ()
}
}
}
diagnostics
}
///|
pub fn has_errors(diagnostics : ArrayView[Diagnostic]) -> Bool {
for item in diagnostics {
if item.severity == Error {
return true
}
}
false
}
///|
pub fn summarize_diagnostics(
diagnostics : ArrayView[Diagnostic],
) -> DiagnosticSummary {
let mut errors = 0
let mut warnings = 0
for item in diagnostics {
match item.severity {
Error => errors += 1
Warning => warnings += 1
}
}
{ errors, warnings }
}
///|
pub fn diagnostics_to_json(
diagnostics : Array[Diagnostic],
indent? : Int = 2,
) -> String {
diagnostics.to_json().stringify(indent~)
}