///|
/// Parse a Quill Delta JSON value while preserving operation order, empty
/// text operations, and multi-key embed objects accepted by the JavaScript
/// constructor. Unknown JSON fields cannot be represented by typed Op values
/// and are ignored.
pub fn Delta::from_json_compatible(value : Json) -> Delta raise DeltaError {
let items = match value {
Array(operations) => operations
Object(fields) =>
match fields.get("ops") {
Some(Array(operations)) => operations
_ => []
}
_ => []
}
let operations : Array[Op] = []
for index, item in items {
let path = "$.ops[" + index.to_string() + "]"
let fields = match item {
Object(map) => map
_ => raise Invalid(path + " must be an object")
}
let attributes = match fields.get("attributes") {
Some(value) => value
None => empty_attributes()
}
let op = match fields.get("insert") {
Some(String(text)) => InsertText(text, attributes)
Some(Object(embed)) => InsertEmbed(Json::object(embed), attributes)
Some(_) => raise Invalid(path + ".insert must be text or an embed object")
None =>
match fields.get("retain") {
Some(Number(value, ..)) =>
Retain(compatible_length(value, path + ".retain"), attributes)
Some(Object(embed)) => RetainEmbed(Json::object(embed), attributes)
Some(_) => raise Invalid(path + ".retain must be a length or embed object")
None =>
match fields.get("delete") {
Some(Number(value, ..)) =>
Delete(compatible_length(value, path + ".delete"))
_ => raise Invalid(path + " must contain an action")
}
}
}
operations.push(op)
}
Delta::from_ops_raw(operations)
}
///|
pub fn Delta::parse_json_compatible(source : String) -> Delta raise DeltaError {
let value = @json.parse(source) catch { _ => raise Invalid("Invalid JSON") }
Delta::from_json_compatible(value)
}
///|
fn compatible_length(value : Double, path : String) -> Int32 raise DeltaError {
if value < -2147483648.0 ||
value > 2147483647.0 ||
value != value.to_int().to_double() {
raise Invalid(path + " must be an Int32 integer")
}
value.to_int()
}