Skip to content

Commit 0cc5193

Browse files
authored
Merge pull request #141 from cloudpeers/ow/js-pkg-2
npm package: cleanup
2 parents bec842f + 823cf9c commit 0cc5193

File tree

7 files changed

+80
-52
lines changed

7 files changed

+80
-52
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/js/index.ts

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,35 @@ import { Api, Causal, Cursor, Doc, Sdk } from "./bindings"
44

55
let API: Api;
66

7-
const init = async (pkg: number[]) => {
7+
const init = async (appId: string, pkg: number[]) => {
88
if (API) {
9-
return await API.createPersistent("tlfs-0.1.0", pkg);
9+
return await API.createPersistent(appId, pkg);
1010
}
1111
else {
12-
//const x = await wbindgen("../pkg-wasm-bindgen/local_first_bg.wasm");
12+
// There are two ways to load the wasm module:
13+
// 1) Keep the wasm as a separate ES module and load/fetch it on demand.
14+
// This is a bit more efficient in the browser, but adds burden to library
15+
// users when bundling and shipping their app.
16+
// ```
17+
// const x = await wbindgen("../pkg-wasm-bindgen/local_first_bg.wasm");
18+
// ```
19+
// 2) Inline the wasm. Easy, works everywhere, is only loaded once anyway:
1320
const x = await wbindgen(wasmbin)
1421

1522
API = new Api();
1623
// @ts-ignore
1724
API.initWithInstance({ exports: x });
18-
return await API.createPersistent("tlfs-0.1.0", pkg);
25+
return await API.createPersistent(appId, pkg);
1926
}
2027

2128
};
2229

2330
class LocalFirst {
2431
public sdk!: Sdk;
2532

26-
static async create(pkg: number[]) {
33+
static async create(appId: string, pkg: number[]) {
2734
const w = new LocalFirst();
28-
w.sdk = await init(pkg);
35+
w.sdk = await init(appId, pkg);
2936
return w;
3037
}
3138

@@ -35,12 +42,13 @@ class LocalFirst {
3542
}
3643

3744
const traverse = (cursor: Cursor, p: any) => {
38-
if (cursor.pointsAtArray()) {
45+
const ty = cursor.typeOf()
46+
if (pointsAtArray(ty)) {
3947
cursor.arrayIndex(Number(p));
40-
} else if (cursor.pointsAtStruct()) {
48+
} else if (pointsAtStruct(ty)) {
4149
const field = p.toString()
4250
cursor.structField(field)
43-
} else if (cursor.pointsAtTable()) {
51+
} else if (pointsAtTable(ty)) {
4452
const field = p.toString()
4553
cursor.mapKeyStr(field)
4654
} else {
@@ -50,13 +58,11 @@ const traverse = (cursor: Cursor, p: any) => {
5058

5159
const get = <T>(doc: Doc, cursor_?: Cursor) => (target: T, p: string | symbol, receiver: any) => {
5260
const cursor = cursor_ || doc.createCursor()
53-
console.log("get", target, p, receiver)
5461

5562
traverse(cursor, p)
56-
57-
if (cursor.pointsAtValue()) {
58-
switch (cursor.valueType()) {
59-
case "null": { return undefined; }
63+
const ty = cursor.typeOf()
64+
if (pointsAtValue(ty)) {
65+
switch (cursor.typeOf()) {
6066
case "bool": { return cursor.flagEnabled() }
6167
case "Reg<bool>":
6268
{ return Array.from(cursor.regBools())[0] }
@@ -66,6 +72,7 @@ const get = <T>(doc: Doc, cursor_?: Cursor) => (target: T, p: string | symbol, r
6672
{ return Array.from(cursor.regI64s())[0] }
6773
case "Reg<string>":
6874
{ return Array.from(cursor.regStrs())[0] }
75+
default: { return undefined; }
6976
}
7077
} else {
7178
// return new object if not at a leaf
@@ -102,7 +109,7 @@ const setValue = (cursor: Cursor, value: any): Causal => {
102109

103110
} else if (typeof value == 'object') {
104111
// delete complete object, if table
105-
if (cursor.pointsAtTable()) {
112+
if (pointsAtTable(cursor.typeOf())) {
106113
for (const k in cursor.keys()) {
107114
const here = cursor.clone()
108115
here.mapKeyStr(k)
@@ -118,10 +125,9 @@ const setValue = (cursor: Cursor, value: any): Causal => {
118125
// add
119126
Object.entries(value).forEach(([k, v]) => {
120127
const here = cursor.clone()
121-
if (here.pointsAtTable()) {
128+
if (pointsAtTable(here.typeOf())) {
122129
here.mapKeyStr(k)
123130
} else {
124-
console.log("structField", k)
125131
here.structField(k)
126132
}
127133
const c = setPrimitiveValue(here, v)
@@ -142,10 +148,10 @@ const setValue = (cursor: Cursor, value: any): Causal => {
142148

143149
const setPrimitiveValue = (cursor: Cursor, value: any): Causal => {
144150

145-
switch (cursor.valueType()) {
151+
switch (cursor.typeOf()) {
146152
case null:
147153
case "null":
148-
throw new Error(`Not pointing at value type: ${cursor.valueType()}`)
154+
throw new Error(`Not pointing at value type: ${cursor.typeOf()}`)
149155
case "bool":
150156
if (Boolean(value)) {
151157
return cursor.flagEnable()
@@ -166,6 +172,11 @@ const setPrimitiveValue = (cursor: Cursor, value: any): Causal => {
166172
}
167173
}
168174

175+
const pointsAtArray = (ty: string): boolean => ty.startsWith("Array")
176+
const pointsAtTable = (ty: string): boolean => ty.startsWith("Table")
177+
const pointsAtStruct = (ty: string): boolean => ty.startsWith("Struct")
178+
const pointsAtValue = (ty: string): boolean => !(pointsAtArray(ty) || pointsAtTable(ty) || pointsAtStruct(ty))
179+
169180
const mkProxy = <T extends object>(doc: Doc, cursor_?: Cursor): T => {
170181

171182
return new Proxy<T>({} as T, {
@@ -175,22 +186,21 @@ const mkProxy = <T extends object>(doc: Doc, cursor_?: Cursor): T => {
175186
// defineProperty?(target: T, p: string | symbol, attributes: PropertyDescriptor): boolean,
176187
// deleteProperty?(target: T, p: string | symbol): boolean,
177188
get(target: T, p: string | symbol, receiver: any) {
189+
// TODO:
178190
switch (p) {
179191
case Symbol.toPrimitive:
180192
case "valueOf":
181193
return undefined
182194
case "toString": {
183-
return function (...args: any[]) {
184-
console.log("toString", args)
185-
return "LOL"
186-
}
195+
throw new Error(`Method ${p} not implemented in TLFS proxy. Please file a bug and/or use the document API directly to work around.`)
187196
}
188197
}
189198

190199
const cursor = cursor_?.clone() || doc.createCursor()
191-
console.log("get", target, p, receiver)
192200

193-
if (cursor.pointsAtArray()) {
201+
const ty = cursor.typeOf()
202+
203+
if (pointsAtArray(ty)) {
194204
switch (p) {
195205
case 'filter': {
196206
return function (...args: any[]) {
@@ -208,11 +218,9 @@ const mkProxy = <T extends object>(doc: Doc, cursor_?: Cursor): T => {
208218
case 'push': {
209219
const c2 = cursor.clone()
210220
return function (...args: any[]) {
211-
console.log("pushing with", c2, args)
212221
if (args.length > 0) {
213222
let causal: Causal | undefined;
214223
let arrayLen = c2.arrayLength()
215-
console.log("arrayLen", arrayLen)
216224
args.forEach((v, idx) => {
217225

218226
const c = c2.clone()
@@ -233,10 +241,8 @@ const mkProxy = <T extends object>(doc: Doc, cursor_?: Cursor): T => {
233241
}
234242
case 'map': {
235243
return function (...args: any[]) {
236-
console.log("map", cursor.arrayLength())
237244
const arr = new Array(cursor.arrayLength()).fill(undefined).map((_v, idx) => {
238245
const x = get(doc, cursor.clone())({}, idx.toString(), undefined)
239-
console.log("arr get", idx, x)
240246
return x
241247
}
242248
)
@@ -248,8 +254,9 @@ const mkProxy = <T extends object>(doc: Doc, cursor_?: Cursor): T => {
248254
}
249255
traverse(cursor, p)
250256

251-
if (cursor.pointsAtValue()) {
252-
switch (cursor.valueType()) {
257+
const tyAfterTraversal = cursor.typeOf()
258+
if (pointsAtValue(tyAfterTraversal)) {
259+
switch (tyAfterTraversal) {
253260
case "null": return undefined
254261
case "bool": return cursor.flagEnabled()
255262
case "Reg<bool>":
@@ -270,23 +277,18 @@ const mkProxy = <T extends object>(doc: Doc, cursor_?: Cursor): T => {
270277
// TODO: check `p`
271278
const cursor = cursor_?.clone() || doc.createCursor()
272279
const value = get(doc, cursor)(target, p, undefined)
273-
console.log("getOwnPropertDescriptor", target, p, value)
274280
return { configurable: true, enumerable: true, value }
275281
},
276282
// getPrototypeOf?(target: T): object | null,
277283
// has?(target: T, p: string | symbol): boolean,
278284
// isExtensible?(target: T): boolean,
279285
ownKeys(target: T): ArrayLike<string | symbol> {
280-
281-
console.log("ownKeys", target)
282286
const cursor = cursor_?.clone() || doc.createCursor()
283287
return Array.from(cursor.keys())
284288
},
285289
// preventExtensions?(target: T): boolean,
286290
set(target: T, p: string | symbol, value: any, receiver: any): boolean {
287291
const cursor = cursor_?.clone() || doc.createCursor()
288-
console.log("set", target, p, value, receiver)
289-
290292
traverse(cursor, p)
291293

292294
const causal = setValue(cursor, value)

api/js/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/js/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "tlfs",
3-
"version": "0.1.3",
3+
"version": "0.1.4",
44
"description": "The local first SDK",
55
"main": "lib/index.js",
66
"module": "lib/index.js",

api/src/lib.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,28 @@ impl Doc {
136136
#[derive(Clone)]
137137
pub struct Cursor<'a>(tlfs::Cursor<'a>);
138138

139+
fn type_of(schema: &ArchivedSchema, max_depth: u8, depth: u8) -> String {
140+
if depth > max_depth {
141+
return "_".into();
142+
}
143+
match schema {
144+
ArchivedSchema::Null => "null".into(),
145+
ArchivedSchema::Flag => "bool".into(),
146+
ArchivedSchema::Reg(ty) => format!("Reg<{}>", ty),
147+
ArchivedSchema::Table(ks, vs) => {
148+
format!("Table<{},{}>", ks, type_of(vs, max_depth, depth + 1))
149+
}
150+
ArchivedSchema::Array(vs) => format!("Array<{}>", type_of(vs, max_depth, depth + 1)),
151+
ArchivedSchema::Struct(_) => "Struct<_>".into(),
152+
}
153+
}
154+
139155
impl<'a> Cursor<'a> {
156+
/// If this [`Cursor`] points to a value, returns its type. None otherwise.
157+
pub fn type_of(&self) -> String {
158+
type_of(self.0.schema(), 8, 0)
159+
}
160+
140161
pub fn points_at_value(&self) -> bool {
141162
matches!(
142163
self.0.schema(),

api/tlfs.rsh

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -185,17 +185,10 @@ object Cursor {
185185
/// Returns a deep copy of the cursor.
186186
fn clone() -> Cursor;
187187

188-
/// TODO
189-
fn points_at_value() -> bool;
190-
/// TODO
191-
fn points_at_array() -> bool;
192-
/// TODO
193-
fn points_at_struct() -> bool;
194-
/// TODO
195-
fn points_at_table() -> bool;
196-
/// TODO
197-
fn value_type() -> Option<string>;
198-
/// TODO
188+
/// Returns a string representation of the type the cursor points at.
189+
fn type_of() -> string;
190+
/// If pointing to a `Struct` or a `Table<string, _>`, returns an iterator
191+
/// over all keys.
199192
fn keys() -> Result<Iterator<string>>;
200193

201194
/// Returns if a flag is enabled.

crdt/src/schema.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use bytecheck::CheckBytes;
55
use ed25519_dalek::{PublicKey, Verifier};
66
use rkyv::{Archive, Serialize};
77
use std::collections::BTreeMap;
8+
use std::fmt;
89

910
/// Kind of a primitive value.
1011
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Archive, CheckBytes, Serialize)]
@@ -21,6 +22,17 @@ pub enum PrimitiveKind {
2122
Str,
2223
}
2324

25+
impl fmt::Display for PrimitiveKind {
26+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27+
f.write_str(match self {
28+
PrimitiveKind::Bool => "bool",
29+
PrimitiveKind::U64 => "u64",
30+
PrimitiveKind::I64 => "i64",
31+
PrimitiveKind::Str => "string",
32+
})
33+
}
34+
}
35+
2436
impl PrimitiveKind {
2537
fn validate(self, seg: Segment) -> bool {
2638
matches!(

0 commit comments

Comments
 (0)