Skip to content

Commit eab222e

Browse files
committed
Cleanup in actions
1 parent ec7a543 commit eab222e

4 files changed

Lines changed: 112 additions & 103 deletions

File tree

src/api/action.ts

Lines changed: 7 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { invariant, addHiddenProp, fail, addHiddenFinalProp } from "../utils/utils"
1+
import { invariant, fail, addHiddenFinalProp } from "../utils/utils"
22
import { createAction, executeAction, IAction } from "../core/action"
3-
import { BabelDescriptor } from "../utils/decorators2"
3+
import { namedActionDecorator, boundActionDecorator } from "./actiondecorator"
44

55
export interface IActionFactory {
66
// nameless actions
@@ -38,82 +38,21 @@ export interface IActionFactory {
3838
// unnamed decorator
3939
(target: Object, propertyKey: string, descriptor?: PropertyDescriptor): void
4040

41-
// generic forms
42-
bound<T extends Function>(fn: T): T & IAction
43-
bound<T extends Function>(name: string, fn: T): T & IAction
44-
45-
// .bound decorator
41+
// @action.bound decorator
4642
bound(target: Object, propertyKey: string, descriptor?: PropertyDescriptor): void
4743
}
4844

49-
// TODO: move decoators to own file
50-
function actionFieldDecorator(name: string) {
51-
// Simple property that writes on first invocation to the current instance
52-
return function(target, prop, descriptor) {
53-
Object.defineProperty(target, prop, {
54-
configurable: true,
55-
enumerable: false,
56-
get() {
57-
return undefined
58-
},
59-
set(value) {
60-
addHiddenProp(this, prop, action(name, value))
61-
}
62-
})
63-
}
64-
}
65-
66-
function dontReassignFields() {
67-
invariant(false, process.env.NODE_ENV !== "production" && "@action fields are not reassignable")
68-
}
69-
70-
const boundActionDecorator = function(target, propertyName, descriptor, applyToInstance?: boolean) {
71-
if (applyToInstance === true) {
72-
defineBoundAction(target, propertyName, descriptor.value)
73-
return null
74-
}
75-
if (descriptor) {
76-
if (descriptor.value)
77-
// Typescript / Babel: @action.bound method() { }
78-
return {
79-
configurable: true,
80-
enumerable: false,
81-
get() {
82-
defineBoundAction(this, propertyName, descriptor.value)
83-
return this[propertyName]
84-
},
85-
set: dontReassignFields
86-
}
87-
// babel
88-
return {
89-
configurable: true,
90-
enumerable: false,
91-
writeable: false,
92-
initializer() {
93-
defineBoundAction(this, propertyName, descriptor.initializer.call(this))
94-
}
95-
}
96-
}
97-
// field decorator
98-
return {
99-
enumerable: false,
100-
configurable: true,
101-
set(v) {
102-
defineBoundAction(this, propertyName, v)
103-
},
104-
get() {
105-
return undefined
106-
}
107-
}
108-
}
109-
11045
export var action: IActionFactory = function action(arg1, arg2?, arg3?, arg4?): any {
46+
// action(fn() {})
11147
if (arguments.length === 1 && typeof arg1 === "function")
11248
return createAction(arg1.name || "<unnamed action>", arg1)
49+
// action("name", fn() {})
11350
if (arguments.length === 2 && typeof arg2 === "function") return createAction(arg1, arg2)
11451

52+
// @action("name") fn() {}
11553
if (arguments.length === 1 && typeof arg1 === "string") return namedActionDecorator(arg1)
11654

55+
// @action fn() {}
11756
if (arg4 === true) {
11857
// apply to instance immediately
11958
arg1[arg2] = createAction(name, arg3.value)
@@ -124,40 +63,6 @@ export var action: IActionFactory = function action(arg1, arg2?, arg3?, arg4?):
12463

12564
action.bound = boundActionDecorator as any
12665

127-
function namedActionDecorator(name: string) {
128-
return function(target, prop, descriptor: BabelDescriptor) {
129-
if (descriptor) {
130-
if (process.env.NODE_ENV !== "production" && descriptor.get !== undefined) {
131-
return fail("@action cannot be used with getters")
132-
}
133-
// babel / typescript
134-
// @action method() { }
135-
if (descriptor.value) {
136-
// typescript
137-
return {
138-
value: createAction(name, descriptor.value),
139-
enumerable: false,
140-
configurable: false,
141-
writable: true // for typescript, this must be writable, otherwise it cannot inherit :/ (see inheritable actions test)
142-
}
143-
}
144-
// babel only: @action method = () => {}
145-
const { initializer } = descriptor
146-
return {
147-
enumerable: false,
148-
configurable: false,
149-
writable: false,
150-
initializer() {
151-
// N.B: we can't immediately invoke initializer; this would be wrong
152-
return createAction(name, initializer!.call(this))
153-
}
154-
}
155-
}
156-
// bound instance methods
157-
return actionFieldDecorator(name).apply(this, arguments)
158-
}
159-
}
160-
16166
export function runInAction<T>(block: () => T, scope?: any): T
16267
export function runInAction<T>(name: string, block: () => T, scope?: any): T
16368
export function runInAction(arg1, arg2?, arg3?) {

src/api/actiondecorator.ts

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import { addHiddenProp, fail } from "../utils/utils"
2+
import { createAction } from "../core/action"
3+
import { BabelDescriptor } from "../utils/decorators2"
4+
import { action, defineBoundAction } from "./action"
5+
6+
function dontReassignFields() {
7+
fail(process.env.NODE_ENV !== "production" && "@action fields are not reassignable")
8+
}
9+
10+
export function namedActionDecorator(name: string) {
11+
return function(target, prop, descriptor: BabelDescriptor) {
12+
if (descriptor) {
13+
if (process.env.NODE_ENV !== "production" && descriptor.get !== undefined) {
14+
return fail("@action cannot be used with getters")
15+
}
16+
// babel / typescript
17+
// @action method() { }
18+
if (descriptor.value) {
19+
// typescript
20+
return {
21+
value: createAction(name, descriptor.value),
22+
enumerable: false,
23+
configurable: false,
24+
writable: true // for typescript, this must be writable, otherwise it cannot inherit :/ (see inheritable actions test)
25+
}
26+
}
27+
// babel only: @action method = () => {}
28+
const { initializer } = descriptor
29+
return {
30+
enumerable: false,
31+
configurable: false,
32+
writable: false,
33+
initializer() {
34+
// N.B: we can't immediately invoke initializer; this would be wrong
35+
return createAction(name, initializer!.call(this))
36+
}
37+
}
38+
}
39+
// bound instance methods
40+
return actionFieldDecorator(name).apply(this, arguments)
41+
}
42+
}
43+
44+
export function actionFieldDecorator(name: string) {
45+
// Simple property that writes on first invocation to the current instance
46+
return function(target, prop, descriptor) {
47+
Object.defineProperty(target, prop, {
48+
configurable: true,
49+
enumerable: false,
50+
get() {
51+
return undefined
52+
},
53+
set(value) {
54+
addHiddenProp(this, prop, action(name, value))
55+
}
56+
})
57+
}
58+
}
59+
60+
export function boundActionDecorator(target, propertyName, descriptor, applyToInstance?: boolean) {
61+
if (applyToInstance === true) {
62+
defineBoundAction(target, propertyName, descriptor.value)
63+
return null
64+
}
65+
if (descriptor) {
66+
if (descriptor.value)
67+
// Typescript / Babel: @action.bound method() { }
68+
return {
69+
configurable: true,
70+
enumerable: false,
71+
get() {
72+
defineBoundAction(this, propertyName, descriptor.value)
73+
return this[propertyName]
74+
},
75+
set: dontReassignFields
76+
}
77+
// babel @action.bound method = () => {}
78+
return {
79+
configurable: true,
80+
enumerable: false,
81+
writeable: false,
82+
initializer() {
83+
defineBoundAction(this, propertyName, descriptor.initializer.call(this))
84+
}
85+
}
86+
}
87+
// field decorator Typescript @action.bound method = () => {}
88+
return {
89+
enumerable: false,
90+
configurable: true,
91+
set(v) {
92+
defineBoundAction(this, propertyName, v)
93+
},
94+
get() {
95+
return undefined
96+
}
97+
}
98+
}

src/core/computedvalue.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ export class ComputedValue<T> implements IObservable, IComputedValue<T>, IDeriva
108108
* This is useful for working with vectors, mouse coordinates etc.
109109
*/
110110
constructor(options: IComputedValueOptions<T>) {
111-
if (!options.get && process.env.NODE_ENV === "production")
111+
if (process.env.NODE_ENV === "production" && !options.get)
112112
return fail("missing option for computed: get")
113113
this.derivation = options.get!
114114
this.name = options.name || "ComputedValue@" + getNextId()

test/base/api.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as fs from "fs"
12
var mobx = require("../../src/mobx.ts")
23

34
test("correct api should be exposed", function() {
@@ -58,3 +59,8 @@ test("correct api should be exposed", function() {
5859
].sort()
5960
)
6061
})
62+
63+
test("mobx has no dependencies", () => {
64+
const pkg = JSON.parse(fs.readFileSync(__dirname + "/../../package.json", "utf8"))
65+
expect(pkg.dependencies).toEqual({})
66+
})

0 commit comments

Comments
 (0)