Skip to content

Commit

Permalink
fix: implement @observable with arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
fi3ework committed Mar 23, 2019
1 parent 04f73f3 commit 01217f9
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 70 deletions.
95 changes: 47 additions & 48 deletions __test__/observable.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,54 +168,53 @@ test('@observable', () => {
expect(b2.toArray()).toEqual(['Adam', 'Adam'])
})

// TODO: save me pls
// test('@observable with arguments', () => {
// const b1 = buffer()
// const b2 = buffer()
// const b3 = buffer()
// @observable('name', 'family')
// class Person {
// public name = 'Adam'
// public family = {
// father: {
// name: 'daddy'
// },
// mother: {
// name: 'mummy'
// }
// }
// public pets = [
// {
// type: 'cat',
// name: 'Cathy'
// }
// ]

// public skills: string[] = ['eat', 'sleep']

// public addSkills(newSkill: string) {
// this.skills.unshift(newSkill)
// }
// }

// const p = new Person()

// autorun(() => {
// b1(p.skills[0])
// b2(p.pets[0].name)
// })

// autorun(() => {
// b3(p.name)
// })

// p.addSkills('code1')
// p.pets[0].name = 'Jessie'
// p.name = 'David'
// expect(b1.toArray()).toEqual(['eat'])
// expect(b2.toArray()).toEqual(['Cathy'])
// expect(b3.toArray()).toEqual(['Adam', 'David'])
// })
test('@observable with arguments', () => {
const b1 = buffer()
const b2 = buffer()
const b3 = buffer()
@observable('name', 'family')
class Person {
public name = 'Adam'
public family = {
father: {
name: 'daddy'
},
mother: {
name: 'mummy'
}
}
public pets = [
{
type: 'cat',
name: 'Cathy'
}
]

public skills: string[] = ['eat', 'sleep']

public addSkills(newSkill: string) {
this.skills.unshift(newSkill)
}
}

const p = new Person()

autorun(() => {
b1(p.skills[0])
b2(p.pets[0].name)
})

autorun(() => {
b3(p.name)
})

p.addSkills('code1')
p.pets[0].name = 'Jessie'
p.name = 'David'
expect(b1.toArray()).toEqual(['eat'])
expect(b2.toArray()).toEqual(['Cathy'])
expect(b3.toArray()).toEqual(['Adam', 'David'])
})

test('tracking of new property', () => {
@observable
Expand Down
22 changes: 19 additions & 3 deletions src/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,12 @@ function relateAtomAndReaction(atom: Atom, reaction: SideEffect | null) {
}
}

interface IHandlerOptions {
pickedProps: string[]
}

/* tslint:disable:cyclomatic-complexity */
export function createHandler(parentPath: string, pathCache: Map<string, Atom>) {
export function createHandler(parentPath: string, pathCache: Map<string, Atom>, options?: IHandlerOptions) {
return {
get(target, prop, receiver) {
// internal assessor
Expand All @@ -74,6 +78,13 @@ export function createHandler(parentPath: string, pathCache: Map<string, Atom>)
return parentPath
}

// ignore non-picked prop
if (options && options.pickedProps) {
if (options.pickedProps.indexOf(prop) < 0) {
return Reflect.get(target, prop, receiver)
}
}

// getter
const path = concatPath(parentPath, prop)
const cachedAtom = pathCache.get(path)
Expand Down Expand Up @@ -168,9 +179,14 @@ export function createHandler(parentPath: string, pathCache: Map<string, Atom>)
}
}

const createRootObservableRoot = object => {
interface ICreateRootOptions {
pickedProps: string[]
}

const createRootObservableRoot = (object: any, options?: ICreateRootOptions) => {
const pathCache = new Map<string, Atom>()
const handler = createHandler('', pathCache)
const rootHandlerOptions = options ? { pickedProps: options.pickedProps } : undefined
const handler = createHandler('', pathCache, rootHandlerOptions)
const proxy = new Proxy(object, handler)
pathCache.set('', new Atom('', proxy, object))

Expand Down
31 changes: 12 additions & 19 deletions src/observable.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,25 @@
import Atom from './Atom'
import createRootObservable from './handlers'
import createRootObservableRoot from './handlers'
import { IDecoratorPropsRestArgs } from './types'

function createProxyOfAtom<T>(target: T): T {
return createRootObservable(target)
}

// @observable('a', 'b', 'c')
// Class Model {...}
function createClassObservableDecorator(props: IDecoratorPropsRestArgs) {
let pickedProps: string[] = props as string[]

// return function decorateClassObservable<T>(TargetClass: T) {
// function wrap(...args: any[]) {
// const proxy = createProxyOfAtom(new (TargetClass as any)(...args))
// const atom = getAtomOfProxy(proxy) as Atom
// atom.pickedProps = pickedProps
// return proxy
// }
// return wrap as any
// }
return function decorateClassObservable(TargetClass: any) {
function wrap(...args: any[]) {
return createRootObservableRoot(new TargetClass(...args), { pickedProps })
}
return wrap as any
}
}

// @observable
// Class Model {...}
function decorateClassObservable(TargetClass: any) {
function wrap(...args: any[]) {
return createProxyOfAtom(new TargetClass(...args))
return createRootObservableRoot(new TargetClass(...args))
}
return wrap as any
}
Expand All @@ -40,7 +33,7 @@ const observableFactories: IObservableFactories = {
if (typeof value === 'object') {
throw Error(`do not use \`observable.box\` to make a primitive value to be observable, use observable directly.`)
}
return createProxyOfAtom(value)
return createRootObservableRoot(value)
}
}

Expand All @@ -51,7 +44,7 @@ export function observable(...props: IDecoratorPropsRestArgs): any {

// observable(model)
if (typeof arg1 === 'object' && props.length === 1) {
return createProxyOfAtom(arg1) as any
return createRootObservableRoot(arg1) as any
}

// @observable
Expand All @@ -63,8 +56,8 @@ export function observable(...props: IDecoratorPropsRestArgs): any {
// @observable('a', 'b', 'c')
// Class Model {...}
if (props.length > 1) {
return decorateClassObservable(arg1)
// return createClassObservableDecorator(props)
// return decorateClassObservable(arg1)
return createClassObservableDecorator(props)
}

throw Error('only accept an plain object or a Class')
Expand Down

0 comments on commit 01217f9

Please sign in to comment.