// Strict reading of JSON objects. Every property must be consumed or the read
// fails: properties that Vega-Lite defines but this library does not implement
// are reported as " 暂不支持", unknown ones as " 未知属性".
///|
pub(all) suberror SpecError {
SpecError(String)
}
///|
/// Message of a spec error.
pub fn SpecError::message(self : SpecError) -> String {
match self {
SpecError(m) => m
}
}
///|
pub fn unsupported(path : String) -> SpecError {
SpecError(path + " 暂不支持")
}
///|
pub fn invalid(path : String, msg : String) -> SpecError {
SpecError(path + ": " + msg)
}
///|
pub fn join_path(base : String, key : String) -> String {
if base == "" {
key
} else {
base + "." + key
}
}
///|
pub fn index_path(base : String, i : Int32) -> String {
base + "[" + i.to_string() + "]"
}
///|
/// A JSON object being consumed key by key.
pub struct Reader {
path : String
obj : Map[String, Json]
used : Array[String]
}
///|
pub fn Reader::new(path : String, j : Json) -> Reader raise SpecError {
match j {
Object(m) => { path, obj: m, used: [], }
_ => raise invalid(path, "应为对象")
}
}
///|
/// The raw value of a key, marking it consumed.
pub fn Reader::take(self : Reader, key : String) -> Json? {
match self.obj.get(key) {
Some(v) => {
self.used.push(key)
Some(v)
}
None => None
}
}
///|
pub fn Reader::has(self : Reader, key : String) -> Bool {
self.obj.contains(key)
}
///|
pub fn Reader::path_of(self : Reader, key : String) -> String {
join_path(self.path, key)
}
///|
pub fn Reader::string(self : Reader, key : String) -> String? raise SpecError {
match self.take(key) {
None => None
Some(String(s)) => Some(s)
Some(_) => raise invalid(self.path_of(key), "应为字符串")
}
}
///|
pub fn Reader::number(self : Reader, key : String) -> Double? raise SpecError {
match self.take(key) {
None => None
Some(Number(x, ..)) => Some(x)
Some(_) => raise invalid(self.path_of(key), "应为数字")
}
}
///|
pub fn Reader::boolean(self : Reader, key : String) -> Bool? raise SpecError {
match self.take(key) {
None => None
Some(True) => Some(true)
Some(False) => Some(false)
Some(_) => raise invalid(self.path_of(key), "应为布尔值")
}
}
///|
/// A value of any JSON type converted to a `Value`.
pub fn Reader::value(self : Reader, key : String) -> @value.Value? {
match self.take(key) {
None => None
Some(j) => Some(@value.from_json(j))
}
}
///|
/// Fail on any property that has not been consumed. Names in `unsupported_keys`
/// are valid Vega-Lite properties that this library does not implement.
pub fn Reader::finish(
self : Reader,
unsupported_keys~ : Array[String] = [],
) -> Unit raise SpecError {
for k, _ in self.obj {
if !self.used.contains(k) {
if unsupported_keys.contains(k) {
raise unsupported(self.path_of(k))
} else {
raise SpecError(self.path_of(k) + " 未知属性")
}
}
}
}
///|
/// Accept (and ignore) properties that do not affect rendering.
pub fn Reader::ignore(self : Reader, keys : Array[String]) -> Unit {
for k in keys {
if self.obj.contains(k) {
self.used.push(k)
}
}
}