Skip to content

Commit

Permalink
applied prettier
Browse files Browse the repository at this point in the history
  • Loading branch information
mweststrate committed Oct 2, 2019
1 parent bdb643a commit 75733b1
Show file tree
Hide file tree
Showing 15 changed files with 406 additions and 331 deletions.
91 changes: 53 additions & 38 deletions src/computedFn.ts
@@ -1,5 +1,12 @@
import { DeepMap } from "./deepMap"
import { IComputedValue, IComputedValueOptions, computed, onBecomeUnobserved, _isComputingDerivation, isAction } from "mobx";
import {
IComputedValue,
IComputedValueOptions,
computed,
onBecomeUnobserved,
_isComputingDerivation,
isAction
} from "mobx"

/**
* computedFn takes a function with an arbitrarily amount of arguments,
Expand Down Expand Up @@ -35,44 +42,52 @@ import { IComputedValue, IComputedValueOptions, computed, onBecomeUnobserved, _i
* @param fn
* @param keepAliveOrOptions
*/
export function computedFn<T extends (...args: any[]) => any>(fn: T, keepAliveOrOptions: IComputedValueOptions<ReturnType<T>> | boolean = false) {
if (isAction(fn))
throw new Error("computedFn shouldn't be used on actions")
export function computedFn<T extends (...args: any[]) => any>(
fn: T,
keepAliveOrOptions: IComputedValueOptions<ReturnType<T>> | boolean = false
) {
if (isAction(fn)) throw new Error("computedFn shouldn't be used on actions")

let memoWarned = false;
let i = 0;
const opts = typeof keepAliveOrOptions === 'boolean'
? { keepAlive: keepAliveOrOptions }
: keepAliveOrOptions;
const d = new DeepMap<IComputedValue<any>>()
let memoWarned = false
let i = 0
const opts =
typeof keepAliveOrOptions === "boolean"
? { keepAlive: keepAliveOrOptions }
: keepAliveOrOptions
const d = new DeepMap<IComputedValue<any>>()

return function(...args: Parameters<T>): ReturnType<T> {
const self = this
const entry = d.entry(args)
// cache hit, return
if (entry.exists())
return entry.get().get()
// if function is invoked, and its a cache miss without reactive, there is no point in caching...
if (!opts.keepAlive && !_isComputingDerivation()) {
if (!memoWarned) {
console.warn("invoking a computedFn from outside an reactive context won't be memoized, unless keepAlive is set")
memoWarned = true
}
return fn.apply(self, args)
return function(...args: Parameters<T>): ReturnType<T> {
const self = this
const entry = d.entry(args)
// cache hit, return
if (entry.exists()) return entry.get().get()
// if function is invoked, and its a cache miss without reactive, there is no point in caching...
if (!opts.keepAlive && !_isComputingDerivation()) {
if (!memoWarned) {
console.warn(
"invoking a computedFn from outside an reactive context won't be memoized, unless keepAlive is set"
)
memoWarned = true
}
return fn.apply(self, args)
}
// create new entry
const c = computed(
() => {
return fn.apply(self, args)
},
{
...opts,
name: `computedFn(${fn.name}#${++i})`
}
)
entry.set(c)
// clean up if no longer observed
if (!opts.keepAlive)
onBecomeUnobserved(c, () => {
d.entry(args).delete()
})
// return current val
return c.get()
}
// create new entry
const c = computed(() => {
return fn.apply(self, args)
}, {
...opts,
name: `computedFn(${fn.name}#${(++i)})`,
})
entry.set(c)
// clean up if no longer observed
if (!opts.keepAlive) onBecomeUnobserved(c, () => {
d.entry(args).delete()
})
// return current val
return c.get()
}
}
25 changes: 15 additions & 10 deletions src/create-transformer.ts
Expand Up @@ -4,8 +4,8 @@ import { invariant, addHiddenProp } from "./utils"
export type ITransformer<A, B> = (object: A) => B

export interface ITransformerParams<A, B> {
onCleanup?: (resultObject: B | undefined, sourceObject?: A) => void,
debugNameGenerator?: (sourceObject?: A) => string,
onCleanup?: (resultObject: B | undefined, sourceObject?: A) => void
debugNameGenerator?: (sourceObject?: A) => string
}

let memoizationId = 0
Expand All @@ -19,12 +19,15 @@ let memoizationId = 0
export function createTransformer<A, B>(
transformer: ITransformer<A, B>,
onCleanup?: (resultObject: B | undefined, sourceObject?: A) => void
): ITransformer<A, B>;
): ITransformer<A, B>
export function createTransformer<A, B>(
transformer: ITransformer<A, B>,
arg2?: ITransformerParams<A, B>
): ITransformer<A, B>;
export function createTransformer<A, B>(transformer: ITransformer<A, B>, arg2?: any): ITransformer<A, B> {
): ITransformer<A, B>
export function createTransformer<A, B>(
transformer: ITransformer<A, B>,
arg2?: any
): ITransformer<A, B> {
invariant(
typeof transformer === "function" && transformer.length < 2,
"createTransformer expects a function that accepts one argument"
Expand All @@ -34,7 +37,7 @@ export function createTransformer<A, B>(transformer: ITransformer<A, B>, arg2?:
let views: { [id: number]: IComputedValue<B> } = {}
let onCleanup: Function = undefined
let debugNameGenerator: Function = undefined

function createView(sourceIdentifier: number, sourceObject: A) {
let latestValue: B
if (typeof arg2 === "object") {
Expand All @@ -46,9 +49,9 @@ export function createTransformer<A, B>(transformer: ITransformer<A, B>, arg2?:
onCleanup = undefined
debugNameGenerator = undefined
}
const prettifiedName = debugNameGenerator ?
debugNameGenerator(sourceObject) :
`Transformer-${(<any>transformer).name}-${sourceIdentifier}`
const prettifiedName = debugNameGenerator
? debugNameGenerator(sourceObject)
: `Transformer-${(<any>transformer).name}-${sourceIdentifier}`
const expr = computed(
() => {
return (latestValue = transformer(sourceObject))
Expand Down Expand Up @@ -81,7 +84,9 @@ function getMemoizationId(object: any) {
if (objectType === "number") return `number:${object}`
if (object === null || (objectType !== "object" && objectType !== "function"))
throw new Error(
`[mobx-utils] transform expected an object, function, string or number, got: ${String(object)}`
`[mobx-utils] transform expected an object, function, string or number, got: ${String(
object
)}`
)
let tid = object.$transformId
if (tid === undefined) {
Expand Down
4 changes: 2 additions & 2 deletions src/create-view-model.ts
Expand Up @@ -58,8 +58,8 @@ export class ViewModel<T> implements IViewModel<T> {
this.localComputedValues.set(key, computed(derivation.bind(this)))
}

const descriptor = Object.getOwnPropertyDescriptor(model, key);
const additionalDescriptor = descriptor ? { enumerable: descriptor.enumerable } : {};
const descriptor = Object.getOwnPropertyDescriptor(model, key)
const additionalDescriptor = descriptor ? { enumerable: descriptor.enumerable } : {}

Object.defineProperty(this, key, {
...additionalDescriptor,
Expand Down
143 changes: 70 additions & 73 deletions src/deepMap.ts
Expand Up @@ -2,93 +2,90 @@
* @private
*/
export class DeepMapEntry<T> {
private root: Map<any, any>
private closest: Map<any, any>
private closestIdx: number = 0
isDisposed = false
private root: Map<any, any>
private closest: Map<any, any>
private closestIdx: number = 0
isDisposed = false

constructor(private base: Map<any, any>, private args: any[]) {
let current: undefined | Map<any, any> = this.closest = this.root = base
let i = 0
for(; i < this.args.length -1; i++) {
current = current!.get(args[i])
if (current)
this.closest = current
else
break
constructor(private base: Map<any, any>, private args: any[]) {
let current: undefined | Map<any, any> = (this.closest = this.root = base)
let i = 0
for (; i < this.args.length - 1; i++) {
current = current!.get(args[i])
if (current) this.closest = current
else break
}
this.closestIdx = i
}
this.closestIdx = i
}

exists(): boolean {
this.assertNotDisposed()
const l = this.args.length
return this.closestIdx >= l - 1 && this.closest.has(this.args[l - 1])
}

get(): T {
this.assertNotDisposed()
if (!this.exists())
throw new Error("Entry doesn't exist")
return this.closest.get(this.args[this.args.length - 1])
}
exists(): boolean {
this.assertNotDisposed()
const l = this.args.length
return this.closestIdx >= l - 1 && this.closest.has(this.args[l - 1])
}

set(value: T) {
this.assertNotDisposed()
const l = this.args.length
let current: Map<any, any> = this.closest
// create remaining maps
for(let i = this.closestIdx; i < l - 1; i++) {
const m = new Map()
current.set(this.args[i], m)
current = m
get(): T {
this.assertNotDisposed()
if (!this.exists()) throw new Error("Entry doesn't exist")
return this.closest.get(this.args[this.args.length - 1])
}
this.closestIdx = l - 1
this.closest = current
current.set(this.args[l - 1], value)
}

delete() {
this.assertNotDisposed()
if (!this.exists())
throw new Error("Entry doesn't exist")
const l = this.args.length
this.closest.delete(this.args[l - 1])
// clean up remaining maps if needed (reconstruct stack first)
let c = this.root
const maps: Map<any, any>[] = [c]
for (let i = 0; i < l - 1; i++) {
c = c.get(this.args[i])!
maps.push(c)
set(value: T) {
this.assertNotDisposed()
const l = this.args.length
let current: Map<any, any> = this.closest
// create remaining maps
for (let i = this.closestIdx; i < l - 1; i++) {
const m = new Map()
current.set(this.args[i], m)
current = m
}
this.closestIdx = l - 1
this.closest = current
current.set(this.args[l - 1], value)
}
for (let i = maps.length - 1; i > 0; i--) {
if (maps[i].size === 0)
maps[i - 1].delete(this.args[i - 1])

delete() {
this.assertNotDisposed()
if (!this.exists()) throw new Error("Entry doesn't exist")
const l = this.args.length
this.closest.delete(this.args[l - 1])
// clean up remaining maps if needed (reconstruct stack first)
let c = this.root
const maps: Map<any, any>[] = [c]
for (let i = 0; i < l - 1; i++) {
c = c.get(this.args[i])!
maps.push(c)
}
for (let i = maps.length - 1; i > 0; i--) {
if (maps[i].size === 0) maps[i - 1].delete(this.args[i - 1])
}
this.isDisposed = true
}
this.isDisposed = true
}

private assertNotDisposed() {
// TODO: once this becomes annoying, we should introduce a reset method to re-run the constructor logic
if (this.isDisposed) throw new Error("Concurrent modification exception")
}
private assertNotDisposed() {
// TODO: once this becomes annoying, we should introduce a reset method to re-run the constructor logic
if (this.isDisposed) throw new Error("Concurrent modification exception")
}
}

/**
* @private
*/
export class DeepMap<T> {
private store = new Map<any, any>()
private argsLength = -1
private last: DeepMapEntry<T>
private store = new Map<any, any>()
private argsLength = -1
private last: DeepMapEntry<T>

entry(args: any[]): DeepMapEntry<T> {
if (this.argsLength === -1)
this.argsLength = args.length
else if (this.argsLength !== args.length)
throw new Error(`DeepMap should be used with functions with a consistent length, expected: ${this.argsLength}, got: ${args.length}`)
if (this.last) this.last.isDisposed = true

return this.last = new DeepMapEntry(this.store, args)
}
entry(args: any[]): DeepMapEntry<T> {
if (this.argsLength === -1) this.argsLength = args.length
else if (this.argsLength !== args.length)
throw new Error(
`DeepMap should be used with functions with a consistent length, expected: ${this
.argsLength}, got: ${args.length}`
)
if (this.last) this.last.isDisposed = true

return (this.last = new DeepMapEntry(this.store, args))
}
}
4 changes: 2 additions & 2 deletions src/from-promise.ts
Expand Up @@ -7,7 +7,7 @@ export const PENDING = "pending"
export const FULFILLED = "fulfilled"
export const REJECTED = "rejected"

type CaseHandlers<U, T> = {
type CaseHandlers<U, T> = {
pending?: (t?: T) => U
fulfilled?: (t: T) => U
rejected?: (e: any) => U
Expand Down Expand Up @@ -77,7 +77,7 @@ function createObservablePromise(origPromise: any, oldPromise?: any) {

promise.isPromiseBasedObservable = true
promise.case = caseImpl
const oldData = oldPromise && oldPromise.state === FULFILLED ? oldPromise.value : undefined;
const oldData = oldPromise && oldPromise.state === FULFILLED ? oldPromise.value : undefined
extendObservable(
promise,
{
Expand Down
2 changes: 1 addition & 1 deletion src/mobx-utils.ts
Expand Up @@ -15,4 +15,4 @@ export * from "./when-async"
export * from "./expr"
export * from "./create-transformer"
export * from "./deepObserve"
export { computedFn } from "./computedFn"
export { computedFn } from "./computedFn"
11 changes: 7 additions & 4 deletions src/tsconfig.json
Expand Up @@ -11,10 +11,13 @@
"moduleResolution": "node",
"experimentalDecorators": true,
"lib": [
"dom", "es2015", "scripthost", "es2015.promise", "es2015.generator", "es2015.iterable"
"dom",
"es2015",
"scripthost",
"es2015.promise",
"es2015.generator",
"es2015.iterable"
]
},
"exclude": [
"node_modules"
]
"exclude": ["node_modules"]
}

0 comments on commit 75733b1

Please sign in to comment.