Skip to content

Commit

Permalink
initial prettiest release
Browse files Browse the repository at this point in the history
  • Loading branch information
anp committed Aug 24, 2020
1 parent 8346e30 commit d22e812
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ members = [
"dom/examples/hacking",
"dom/examples/ssr",
"dom/examples/todo",
"dom/prettiest",
"dom/raf",
"dyn-cache",
"illicit",
Expand Down
10 changes: 10 additions & 0 deletions dom/prettiest/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# prettiest

[prettiest](https://docs.rs/prettiest) provides pretty-printed `Debug` and `Display` impls
for Javascript values in the [wasm-bindgen](https://docs.rs/wasm-bindgen) crate.

<!-- categories: Added, Removed, Changed, Deprecated, Fixed, Security -->

## [0.1.0] - 2020-08-20

Initial release. Only sort of works -- not recommended for use.
28 changes: 28 additions & 0 deletions dom/prettiest/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[package]
name = "prettiest"
version = "0.1.0"
description = "Pretty-printer for JS values from wasm-bindgen."
categories = ["web"]
keywords = ["debug", "pretty", "javascript"]
readme = "CHANGELOG.md"

# update here, update everywhere!
license = "MIT/Apache-2.0"
homepage = "https://moxie.rs"
repository = "https://github.com/anp/moxie.git"
authors = ["Adam Perry <[email protected]>"]
edition = "2018"

[dependencies]
js-sys = "0.3.25"
ordered-float = "2.0.0"
wasm-bindgen = "0.2.48"

[dev-dependencies]
wasm-bindgen-test = "0.3"

[dev-dependencies.web-sys]
version = "0.3.28"
features = [
"KeyboardEvent",
]
132 changes: 132 additions & 0 deletions dom/prettiest/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
use js_sys::{
Array, Date, Error, Function, JsString, Map, Object, Promise, Reflect, RegExp, Set, Symbol,
};
use ordered_float::OrderedFloat;
use std::collections::{BTreeMap, BTreeSet, HashSet};
use wasm_bindgen::{convert::IntoWasmAbi, JsCast, JsValue};

// TODO impl Display
// TODO impl serialize
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)] // TODO we can do Debug better!
pub enum Pretty {
Cycle,
Function,
Promise,

Number(OrderedFloat<f64>),
Boolean(bool),

Str(String),
Date(String),
Error(String),
Regex(String),
Symbol(String),

Object { name: String, contents: BTreeMap<String, Pretty> },
Array(Vec<Pretty>),
Map(BTreeMap<Pretty, Pretty>),
Set(BTreeSet<Pretty>),
}

impl<T> From<T> for Pretty
where
T: AsRef<JsValue>,
{
fn from(val: T) -> Self {
let mut collector = Collector::default();
collector.collect(val.as_ref())
}
}

#[derive(Default)]
struct Collector {
seen: HashSet<u32>,
}

impl Collector {
fn have_seen(&mut self, val: &JsValue) -> bool {
let raw = val.clone().into_abi();
let already_has = self.seen.contains(&raw);
self.seen.insert(raw);
already_has
}

fn collect(&mut self, val: &JsValue) -> Pretty {
if self.have_seen(val) {
Pretty::Cycle
} else if let Some(a) = val.dyn_ref::<Array>() {
let mut children = vec![];
for val in a.iter() {
children.push(self.collect(&val));
}

Pretty::Array(children)
} else if let Some(s) = val.dyn_ref::<Set>() {
let mut contents = BTreeSet::new();
let entries = s.entries();
while let Ok(next) = entries.next() {
if next.done() {
break;
}
contents.insert(self.collect(&next.value()));
}

Pretty::Set(contents)
} else if let Some(m) = val.dyn_ref::<Map>() {
let mut contents = BTreeMap::new();
let keys = m.keys();
while let Ok(next) = keys.next() {
if next.done() {
break;
}
let key = next.value();
let value = m.get(&key);

contents.insert(self.collect(&key), self.collect(&value));
}

Pretty::Map(contents)
} else if let Some(d) = val.dyn_ref::<Date>() {
Pretty::Date(d.to_iso_string().as_string().unwrap())
} else if let Some(e) = val.dyn_ref::<Error>() {
Pretty::Error(e.to_string().as_string().unwrap())
} else if let Some(r) = val.dyn_ref::<RegExp>() {
Pretty::Regex(r.to_string().as_string().unwrap())
} else if let Some(s) = val.dyn_ref::<Symbol>() {
Pretty::Symbol(s.to_string().as_string().unwrap())
} else if val.dyn_ref::<Function>().is_some() {
Pretty::Function
} else if val.dyn_ref::<Promise>().is_some() {
Pretty::Promise
} else if let Some(s) = val.dyn_ref::<JsString>() {
Pretty::Str(s.as_string().unwrap())
} else if let Some(n) = val.as_f64() {
Pretty::Number(OrderedFloat(n))
} else if let Some(b) = val.as_bool() {
Pretty::Boolean(b)
} else {
let mut contents = BTreeMap::new();
let obj =
val.dyn_ref::<Object>().expect("fallthrough condition is to an Object").clone();
let name = obj.constructor().name().as_string().unwrap();
let proto = obj.clone();

while !obj.is_falsy() {
for raw_key in Object::get_own_property_names(&proto).iter() {
let key = raw_key.as_string().expect("object keys are always strings");
if contents.contains_key(&key) {
continue;
}
if let Ok(value) = Reflect::get(&obj, &raw_key) {
let value = self.collect(&value);
contents.insert(key, value);
}
}
// proto = Object::get_prototype_of(proto.as_ref());
break;
}

Pretty::Object { name, contents }
}
}
}

0 comments on commit d22e812

Please sign in to comment.