Comparing version 1.0.7 to 1.0.8
@@ -28,4 +28,4 @@ import { Subscription, Observable } from "rxjs"; | ||
* @param {string} path - dotted-notation path ("a.b.c") | ||
* @returns {any} - the whole observed object or part of it | ||
* @throws if the current path does not reflect to an available object | ||
* @returns {any | undefined} - the whole observed object or part of it. | ||
* Undefined if the path is not matched; | ||
*/ | ||
@@ -32,0 +32,0 @@ snapshot(path?: string): any; |
23
index.js
@@ -6,2 +6,4 @@ "use strict"; | ||
const observedObjectsSymbol_1 = require("./observedObjectsSymbol"); | ||
const debug = require("debug"); | ||
const roxeDebug = debug("roxe"); | ||
class _ObservableObject { | ||
@@ -125,20 +127,27 @@ constructor(from = {}, optHandlers = {}) { | ||
* @param {string} path - dotted-notation path ("a.b.c") | ||
* @returns {any} - the whole observed object or part of it | ||
* @throws if the current path does not reflect to an available object | ||
* @returns {any | undefined} - the whole observed object or part of it. | ||
* Undefined if the path is not matched; | ||
*/ | ||
snapshot(path) { | ||
let snapshot; | ||
let firstUnavailableKey = ""; | ||
if (path && typeof path === "string") { | ||
snapshot = path.split(".").reduce((acc, current) => { | ||
if (!(current && typeof acc === "object" && !Array.isArray(acc) && acc.hasOwnProperty(current))) { | ||
throw new Error(`Cannot access to ${current} of ${path}. No key available`); | ||
if (!(acc && typeof acc === "object" && !Array.isArray(acc) && current && acc.hasOwnProperty(current))) { | ||
// if the previous iteration returns undefined, | ||
// we'll forward this until the end of the loop. | ||
// We keep the first unavailable key for debug. | ||
firstUnavailableKey = firstUnavailableKey || current; | ||
return undefined; | ||
} | ||
return acc[current]; | ||
}, this); | ||
if (snapshot === undefined) { | ||
roxeDebug(`Cannot access to path "${path}". "${firstUnavailableKey}" is not reachable`); | ||
return snapshot; | ||
} | ||
if (typeof snapshot === "object") { | ||
return Object.assign({}, snapshot); | ||
} | ||
else { | ||
return snapshot; | ||
} | ||
return snapshot; | ||
} | ||
@@ -145,0 +154,0 @@ else { |
{ | ||
"name": "roxe", | ||
"version": "1.0.7", | ||
"version": "1.0.8", | ||
"description": "Observe object changes through proxies", | ||
@@ -25,5 +25,7 @@ "main": "index.js", | ||
"dependencies": { | ||
"debug": "^4.1.1", | ||
"rxjs": "^6.4.0" | ||
}, | ||
"devDependencies": { | ||
"@types/debug": "^4.1.4", | ||
"@types/jasmine": "^3.3.9", | ||
@@ -30,0 +32,0 @@ "jasmine": "^3.3.1", |
@@ -159,2 +159,4 @@ # Roxe | ||
Returns a clean (no proxies or internal props) object structure or value of a nested property. | ||
Returns `undefined` if the specified observed object doesn't own a middle or end key of the specified path. | ||
Use `debug` (see below) to get better info to which part of the path failed if the snapshot is undefined. | ||
@@ -169,2 +171,6 @@ <br> | ||
**Caveats**: | ||
Avoid to snap(shot) your fingers or Thanos will be happy. | ||
<br> | ||
@@ -190,2 +196,17 @@ <br> | ||
___ | ||
### Debug | ||
This package uses [Debug](https://github.com/visionmedia/debug) to show some messages. | ||
To show those messages, start your package as: | ||
```sh | ||
# Bash / linux | ||
$ DEBUG=roxe node app.js | ||
``` | ||
To debug on different OSs, refer to [Debug](https://github.com/visionmedia/debug) package. | ||
___ | ||
### Testing | ||
@@ -192,0 +213,0 @@ |
@@ -5,156 +5,127 @@ "use strict"; | ||
const observedObjectsSymbol_1 = require("../observedObjectsSymbol"); | ||
describe("Creating a new observable object", () => { | ||
let oo; | ||
describe("Registration and observing for changes", () => { | ||
beforeEach(() => { | ||
// I think there is no way someone could do something like this. | ||
oo = new __1.ObservableObject({ | ||
a: 1, | ||
b: { | ||
c: 2, | ||
d: { | ||
e: 3, | ||
f: { | ||
g: 4, | ||
h: { | ||
i: 5, | ||
} | ||
let oo; | ||
describe("Registration and changes observation:", () => { | ||
beforeEach(() => { | ||
// I think there is no way someone could do something like this. | ||
oo = new __1.ObservableObject({ | ||
a: 1, | ||
b: { | ||
c: 2, | ||
d: { | ||
e: 3, | ||
f: { | ||
g: 4, | ||
h: { | ||
i: 5, | ||
} | ||
} | ||
} | ||
}); | ||
} | ||
}); | ||
it("Should register an observer to a specific key of the object", () => { | ||
const observed = oo.observe("b.d.e"); | ||
// @ts-ignore - only because its the only way to check if it went fine | ||
expect(Object.keys(oo[observedObjectsSymbol_1.observedObjects]).includes("b.d.e")).toBeTruthy(); | ||
}); | ||
it("Should register an observer to a specific key of the object", () => { | ||
oo.observe("b.d.e"); | ||
expect(Object.keys(oo[observedObjectsSymbol_1.observedObjects]).includes("b.d.e")).toBeTruthy(); | ||
}); | ||
it("Should notify all the changes", () => { | ||
const observed = oo.observe("b.d.e"); | ||
observed.subscribe({ | ||
next: (newValue) => { | ||
expect(newValue).toBe(5); | ||
expect(oo.b.d.e).toBe(5); | ||
} | ||
}); | ||
it("Should notify all the changes", () => { | ||
const observed = oo.observe("b.d.e"); | ||
observed.subscribe({ | ||
next: (newValue) => { | ||
expect(newValue).toBe(5); | ||
expect(oo.b.d.e).toBe(5); | ||
} | ||
}); | ||
oo.b.d.e = 5; | ||
oo.b.d.e = 5; | ||
}); | ||
it("Unsubscribed object should not receive any update", () => { | ||
const observed = oo.observe("b.d.e"); | ||
let subscription = observed.subscribe({ | ||
next: (newValue) => { | ||
// this won't be executed since unsubscribed | ||
expect(newValue).toBe(42); | ||
} | ||
}); | ||
it("Unsubscribed object should not show any update", () => { | ||
const observed = oo.observe("b.d.e"); | ||
let subscription = observed.subscribe({ | ||
next: (newValue) => { | ||
// this won't be executed since unsubscribed | ||
expect(newValue).toBe(42); | ||
} | ||
}); | ||
subscription.unsubscribe(); | ||
oo.b.d.e = 42; | ||
}); | ||
subscription.unsubscribe(); | ||
oo.b.d.e = 42; | ||
}); | ||
describe("Proxy handler", () => { | ||
let oo; | ||
it("Should attach custom handlers to the original one", () => { | ||
oo = new __1.ObservableObject({ | ||
a: 1, | ||
b: { | ||
c: 2, | ||
d: { | ||
e: 3, | ||
f: { | ||
g: 4, | ||
h: { | ||
i: 5, | ||
} | ||
}); | ||
describe("Custom Proxy handler:", () => { | ||
it("Should attach custom handlers to the original one", () => { | ||
oo = new __1.ObservableObject({ | ||
a: 1, | ||
b: { | ||
c: 2, | ||
d: { | ||
e: 3, | ||
f: { | ||
g: 4, | ||
h: { | ||
i: 5, | ||
} | ||
} | ||
} | ||
}, { | ||
get(target, prop, receiver) { | ||
// this trap will be executed always, when getting values | ||
// from the observed objects | ||
if (typeof target[prop] === "number") { | ||
return Math.pow(target[prop], 2); | ||
} | ||
return target[prop]; | ||
} | ||
}, { | ||
get(target, prop, receiver) { | ||
// this trap will be executed always, when getting values | ||
// from the observed objects | ||
if (typeof target[prop] === "number") { | ||
return Math.pow(target[prop], 2); | ||
} | ||
}); | ||
expect(oo.b.c).toBe(4); | ||
return target[prop]; | ||
} | ||
}); | ||
expect(oo.b.c).toBe(4); | ||
}); | ||
describe("But first... let me take a snapshot", () => { | ||
let oo; | ||
it("Should return a full snapshot of the structure", () => { | ||
oo = new __1.ObservableObject({ | ||
a: 1, | ||
b: { | ||
c: 2, | ||
d: { | ||
e: 3, | ||
f: { | ||
g: 4, | ||
h: { | ||
i: 5, | ||
} | ||
}); | ||
describe("Snapshot:", () => { | ||
let oo; | ||
beforeEach(() => { | ||
oo = new __1.ObservableObject({ | ||
a: 1, | ||
b: { | ||
c: 2, | ||
d: { | ||
e: 3, | ||
f: { | ||
g: 4, | ||
h: { | ||
i: 5, | ||
} | ||
} | ||
} | ||
}); | ||
expect(compareObjects({ | ||
a: 1, | ||
b: { | ||
c: 2, | ||
d: { | ||
e: 3, | ||
f: { | ||
g: 4, | ||
h: { | ||
i: 5, | ||
} | ||
} | ||
} | ||
} | ||
}, oo.snapshot())).toBe(true); | ||
} | ||
}); | ||
it("Should take a partial snapshot (object) of the main object", () => { | ||
oo = new __1.ObservableObject({ | ||
a: 1, | ||
b: { | ||
c: 2, | ||
d: { | ||
e: 3, | ||
f: { | ||
g: 4, | ||
h: { | ||
i: 5, | ||
} | ||
}); | ||
it("Should return a full snapshot of the structure", () => { | ||
expect(compareObjects({ | ||
a: 1, | ||
b: { | ||
c: 2, | ||
d: { | ||
e: 3, | ||
f: { | ||
g: 4, | ||
h: { | ||
i: 5, | ||
} | ||
} | ||
} | ||
}); | ||
expect(compareObjects({ | ||
g: 4, | ||
h: { | ||
i: 5, | ||
} | ||
}, oo.snapshot("b.d.f"))).toBe(true); | ||
}); | ||
it("Should take a partial snapshot (value) of the main object", () => { | ||
oo = new __1.ObservableObject({ | ||
a: 1, | ||
b: { | ||
c: 2, | ||
d: { | ||
e: 3, | ||
f: { | ||
g: 4, | ||
h: { | ||
i: 5, | ||
} | ||
} | ||
} | ||
} | ||
}); | ||
expect(oo.snapshot("b.d.e")).toBe(3); | ||
}); | ||
} | ||
}, oo.snapshot())).toBe(true); | ||
}); | ||
it("Should take a partial snapshot (object) of the main object", () => { | ||
expect(compareObjects({ | ||
g: 4, | ||
h: { | ||
i: 5, | ||
} | ||
}, oo.snapshot("b.d.f"))).toBe(true); | ||
}); | ||
it("Should take a partial snapshot (value) of the main object", () => { | ||
expect(oo.snapshot("b.d.e")).toBe(3); | ||
}); | ||
it("Should return undefined if the key does not exist", () => { | ||
expect(oo.snapshot("b.d.h")).toBe(undefined); | ||
}); | ||
}); | ||
@@ -161,0 +132,0 @@ function compareObjects(obj1, obj2) { |
244
58502
2
4
407
+ Addeddebug@^4.1.1
+ Addeddebug@4.4.0(transitive)
+ Addedms@2.1.3(transitive)