context 2.0.9 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -13
- package/dist/cjs/context.development.js +36 -26
- package/dist/cjs/context.production.js +1 -1
- package/dist/es/context.development.js +36 -27
- package/dist/es/context.production.js +1 -1
- package/dist/umd/context.development.js +36 -26
- package/dist/umd/context.production.js +1 -1
- package/package.json +1 -1
- package/types/context.d.ts +12 -5
package/README.md
CHANGED
|
@@ -5,32 +5,86 @@ It allows you to keep reference for shared variables, and access them down in yo
|
|
|
5
5
|
|
|
6
6
|
## How Context Works?
|
|
7
7
|
|
|
8
|
-
The way context works is quite simple. Creating a context initializes a closure with a context storage object. When you run your context call, it takes your values, and places them in the context
|
|
9
|
-
|
|
10
|
-

|
|
8
|
+
The way context works is quite simple. Creating a context initializes a closure with a context storage object. When you run your context call, it takes your values, and places them in the context's closure. When your function finishes running, the context is cleared.
|
|
11
9
|
|
|
12
10
|
The reason the context is cleared after its run is so that items can't override one another. Assume you have two running the same async function twice, and it writes to the context, expecting to read the value somewhere down the line. Now you have two competing consumers of this single resource, and one eventually get the wrong value since they both read from and write to the same place.
|
|
13
11
|
|
|
14
12
|
## API Reference
|
|
15
13
|
|
|
16
|
-
|
|
14
|
+
### Top Level Exports
|
|
15
|
+
|
|
16
|
+
The context package exports these two functions:
|
|
17
|
+
|
|
18
|
+
- `createContext`: Creates a new context.
|
|
19
|
+
- `createCascade`: Creates a new cascading context.
|
|
20
|
+
|
|
21
|
+
## createContext()
|
|
22
|
+
|
|
23
|
+
Create context is the minimal implementation of context. It allows propagation of values down in your function call.
|
|
24
|
+
|
|
25
|
+
createContext takes a single argument - defaultContextValue. This value is used when not withing a running context.
|
|
26
|
+
|
|
27
|
+
### Arguments
|
|
28
|
+
|
|
29
|
+
| Argument | Type | Optional? | Description |
|
|
30
|
+
| ------------------- | ----- | --------- | ------------------------------------------------------------ |
|
|
31
|
+
| defaultContextValue | `any` | Yes | The default value to use when not withing a running context. |
|
|
17
32
|
|
|
18
|
-
###
|
|
33
|
+
### Returned object
|
|
19
34
|
|
|
20
|
-
|
|
35
|
+
`createContext` returns an object containing the following functions:
|
|
36
|
+
|
|
37
|
+
- `use`: Returns the current context value, or the default value when not withing a running context.
|
|
38
|
+
- `useX`: Returns the current context, throws an error if not within a running context or the context is undefined. `useX` will throw even if a default value is provided.
|
|
39
|
+
- `run`: Runs the context, passing the given value into the context.
|
|
40
|
+
|
|
41
|
+
**Note About Typescript Usage**
|
|
42
|
+
For convenience, `use` assumes we're alwyas inside a context. If you want to have runtime safety, you can use `useX` instead to make sure you're excplicitly using a defined context.
|
|
43
|
+
|
|
44
|
+
### Usage Example
|
|
21
45
|
|
|
22
46
|
```js
|
|
23
|
-
//
|
|
24
|
-
import { createContext } from 'context';
|
|
47
|
+
const context = createContext(0); // Create a context with a default value of 0.
|
|
25
48
|
|
|
26
|
-
|
|
49
|
+
function myFunc() {
|
|
50
|
+
context.run(100, someOtherFunc); // Run the context with a value of 100.
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function someOtherFunc() {
|
|
54
|
+
const number = context.use(); // Returns the value of the context.
|
|
55
|
+
}
|
|
27
56
|
```
|
|
28
57
|
|
|
29
|
-
|
|
30
|
-
|
|
58
|
+
## createCascade()
|
|
59
|
+
|
|
60
|
+
`createCascade` is a more advanced version of `createContext` that allows you to create cascading contexts. It assumes the value is always an object, and when nesting context layers, it merges their values together.
|
|
61
|
+
|
|
62
|
+
`createCascade` does not take a default value, but an initializer function instead. This initializer is called on each `run` call, and it allows you to modify or augment the context value being passed down. The init function is passed the context object run was called with, and the parent context if it was called within a previously created context. The init function needs to return the desired context object.
|
|
63
|
+
|
|
64
|
+
### Arguments
|
|
65
|
+
|
|
66
|
+
| Argument | Type | Optional? | Description |
|
|
67
|
+
| ----------- | ---------- | --------- | ------------------------------------------------------------ |
|
|
68
|
+
| initializer | `Function` | Yes | The initializer function to use when creating a new context. |
|
|
69
|
+
|
|
70
|
+
The initializer function can either return the the next context object. If null is returned itself, the initializer will take no effect.
|
|
71
|
+
The initializer receives the context object, and the parent context object, if present.
|
|
72
|
+
|
|
73
|
+
### Returned object
|
|
74
|
+
|
|
75
|
+
`createCascade` returns an object containing the following functions:
|
|
76
|
+
|
|
77
|
+
- `use`: Returns the current context value.
|
|
78
|
+
- `useX`: Returns the current context, throws an error if not within a running context.
|
|
79
|
+
- `run`: Runs the context, passing the given value into the context. Merges the given value with the parent context if it exists, while not overriding the parent context.
|
|
80
|
+
- `bind`: Binds a given function to the context. Allows for delayd execution of a function as if it was called within the context.
|
|
81
|
+
|
|
82
|
+
### Usage Examples
|
|
83
|
+
|
|
84
|
+
#### Initializer Function
|
|
31
85
|
|
|
32
86
|
```js
|
|
33
|
-
|
|
87
|
+
createCascade((ctx, parentContext) => {
|
|
34
88
|
if (parentContext === null) {
|
|
35
89
|
// we're at the top level
|
|
36
90
|
// so let's add a default cart object
|
|
@@ -44,7 +98,7 @@ createContext((ctx, parentContext) => {
|
|
|
44
98
|
});
|
|
45
99
|
```
|
|
46
100
|
|
|
47
|
-
|
|
101
|
+
#### run()
|
|
48
102
|
|
|
49
103
|
Runs a callback function within the context. It takes an object referencing the data you want to store within your context, and a callback function to run.
|
|
50
104
|
|
|
@@ -117,6 +171,24 @@ function getProductData(productId) {
|
|
|
117
171
|
}
|
|
118
172
|
```
|
|
119
173
|
|
|
174
|
+
## Typescript Support
|
|
175
|
+
|
|
176
|
+
both `createContext` and `createCascade` have full typescript support. To gain the full benefits of typescript within your context, it is best to annotate your context with its types:
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
const someContext = createContext<number>(0);
|
|
180
|
+
|
|
181
|
+
const someCascadeContext = createCascade<{
|
|
182
|
+
username: string;
|
|
183
|
+
firstName: string;
|
|
184
|
+
middleName?: string;
|
|
185
|
+
lastName: string;
|
|
186
|
+
age: number;
|
|
187
|
+
}>();
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
This meakes sure that all the functions (`run`, `use`, `useX` and `bind`) will be aware of these types, and either accept them as inputs, or add them to the return value.
|
|
191
|
+
|
|
120
192
|
## Troubleshooting
|
|
121
193
|
|
|
122
194
|
### Working with async functions/promises
|
|
@@ -4,49 +4,59 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
var vestUtils = require('vest-utils');
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
var USEX_DEFAULT_ERROR_MESSAGE = 'Not inside of a running context.';
|
|
8
|
+
var EMPTY_CONTEXT = Symbol();
|
|
9
|
+
function createContext(defaultContextValue) {
|
|
10
|
+
var contextValue = EMPTY_CONTEXT;
|
|
10
11
|
return {
|
|
11
|
-
bind: bind,
|
|
12
12
|
run: run,
|
|
13
13
|
use: use,
|
|
14
14
|
useX: useX
|
|
15
15
|
};
|
|
16
|
+
function use() {
|
|
17
|
+
return (isInsideContext() ? contextValue : defaultContextValue);
|
|
18
|
+
}
|
|
16
19
|
function useX(errorMessage) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return ctx;
|
|
20
|
+
vestUtils.invariant(isInsideContext(), vestUtils.defaultTo(errorMessage, USEX_DEFAULT_ERROR_MESSAGE));
|
|
21
|
+
return contextValue;
|
|
20
22
|
}
|
|
21
|
-
function run(
|
|
22
|
-
var
|
|
23
|
-
|
|
24
|
-
var
|
|
25
|
-
|
|
26
|
-
var res = fn(ctx);
|
|
27
|
-
storage.ctx = parentContext;
|
|
23
|
+
function run(value, cb) {
|
|
24
|
+
var parentContext = isInsideContext() ? use() : EMPTY_CONTEXT;
|
|
25
|
+
contextValue = value;
|
|
26
|
+
var res = cb();
|
|
27
|
+
contextValue = parentContext;
|
|
28
28
|
return res;
|
|
29
29
|
}
|
|
30
|
-
function
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
function isInsideContext() {
|
|
31
|
+
return contextValue !== EMPTY_CONTEXT;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function createCascade(init) {
|
|
35
|
+
var ctx = createContext();
|
|
36
|
+
return {
|
|
37
|
+
bind: bind,
|
|
38
|
+
run: run,
|
|
39
|
+
use: ctx.use,
|
|
40
|
+
useX: ctx.useX
|
|
41
|
+
};
|
|
42
|
+
function run(value, fn) {
|
|
43
|
+
var _a;
|
|
44
|
+
var parentContext = ctx.use();
|
|
45
|
+
var out = vestUtils.assign({}, parentContext ? parentContext : {}, (_a = vestUtils.optionalFunctionValue(init, value, parentContext)) !== null && _a !== void 0 ? _a : value);
|
|
46
|
+
return ctx.run(Object.freeze(out), fn);
|
|
47
|
+
}
|
|
48
|
+
function bind(value, fn) {
|
|
49
|
+
return function () {
|
|
34
50
|
var runTimeArgs = [];
|
|
35
51
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
36
52
|
runTimeArgs[_i] = arguments[_i];
|
|
37
53
|
}
|
|
38
|
-
return run(
|
|
54
|
+
return run(value, function () {
|
|
39
55
|
return fn.apply(void 0, runTimeArgs);
|
|
40
56
|
});
|
|
41
57
|
};
|
|
42
|
-
return returnedFn;
|
|
43
|
-
}
|
|
44
|
-
function use() {
|
|
45
|
-
return storage.ctx;
|
|
46
|
-
}
|
|
47
|
-
function set(value) {
|
|
48
|
-
return (storage.ctx = value);
|
|
49
58
|
}
|
|
50
59
|
}
|
|
51
60
|
|
|
61
|
+
exports.createCascade = createCascade;
|
|
52
62
|
exports.createContext = createContext;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var n=require("vest-utils"),e=Symbol();function r(r){function t(){return u!==e?u:r}var u=e;return{run:function(n,r){var o=u!==e?t():e;return u=n,n=r(),u=o,n},use:t,useX:function(r){return n.invariant(u!==e,n.defaultTo(r,"Not inside of a running context.")),u}}}exports.createCascade=function(e){function t(r,t){var o,i=u.use();return r=n.assign({},i||{},null!==(o=n.optionalFunctionValue(e,r,i))&&void 0!==o?o:r),u.run(Object.freeze(r),t)}var u=r();return{bind:function(n,e){return function(){for(var r=[],u=0;u<arguments.length;u++)r[u]=arguments[u];return t(n,(function(){return e.apply(void 0,r)}))}},run:t,use:u.use,useX:u.useX}},exports.createContext=r;
|
|
@@ -1,48 +1,57 @@
|
|
|
1
1
|
import { invariant, defaultTo, assign, optionalFunctionValue } from 'vest-utils';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
var USEX_DEFAULT_ERROR_MESSAGE = 'Not inside of a running context.';
|
|
4
|
+
var EMPTY_CONTEXT = Symbol();
|
|
5
|
+
function createContext(defaultContextValue) {
|
|
6
|
+
var contextValue = EMPTY_CONTEXT;
|
|
6
7
|
return {
|
|
7
|
-
bind: bind,
|
|
8
8
|
run: run,
|
|
9
9
|
use: use,
|
|
10
10
|
useX: useX
|
|
11
11
|
};
|
|
12
|
+
function use() {
|
|
13
|
+
return (isInsideContext() ? contextValue : defaultContextValue);
|
|
14
|
+
}
|
|
12
15
|
function useX(errorMessage) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
return ctx;
|
|
16
|
+
invariant(isInsideContext(), defaultTo(errorMessage, USEX_DEFAULT_ERROR_MESSAGE));
|
|
17
|
+
return contextValue;
|
|
16
18
|
}
|
|
17
|
-
function run(
|
|
18
|
-
var
|
|
19
|
-
|
|
20
|
-
var
|
|
21
|
-
|
|
22
|
-
var res = fn(ctx);
|
|
23
|
-
storage.ctx = parentContext;
|
|
19
|
+
function run(value, cb) {
|
|
20
|
+
var parentContext = isInsideContext() ? use() : EMPTY_CONTEXT;
|
|
21
|
+
contextValue = value;
|
|
22
|
+
var res = cb();
|
|
23
|
+
contextValue = parentContext;
|
|
24
24
|
return res;
|
|
25
25
|
}
|
|
26
|
-
function
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
function isInsideContext() {
|
|
27
|
+
return contextValue !== EMPTY_CONTEXT;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function createCascade(init) {
|
|
31
|
+
var ctx = createContext();
|
|
32
|
+
return {
|
|
33
|
+
bind: bind,
|
|
34
|
+
run: run,
|
|
35
|
+
use: ctx.use,
|
|
36
|
+
useX: ctx.useX
|
|
37
|
+
};
|
|
38
|
+
function run(value, fn) {
|
|
39
|
+
var _a;
|
|
40
|
+
var parentContext = ctx.use();
|
|
41
|
+
var out = assign({}, parentContext ? parentContext : {}, (_a = optionalFunctionValue(init, value, parentContext)) !== null && _a !== void 0 ? _a : value);
|
|
42
|
+
return ctx.run(Object.freeze(out), fn);
|
|
43
|
+
}
|
|
44
|
+
function bind(value, fn) {
|
|
45
|
+
return function () {
|
|
30
46
|
var runTimeArgs = [];
|
|
31
47
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
32
48
|
runTimeArgs[_i] = arguments[_i];
|
|
33
49
|
}
|
|
34
|
-
return run(
|
|
50
|
+
return run(value, function () {
|
|
35
51
|
return fn.apply(void 0, runTimeArgs);
|
|
36
52
|
});
|
|
37
53
|
};
|
|
38
|
-
return returnedFn;
|
|
39
|
-
}
|
|
40
|
-
function use() {
|
|
41
|
-
return storage.ctx;
|
|
42
|
-
}
|
|
43
|
-
function set(value) {
|
|
44
|
-
return (storage.ctx = value);
|
|
45
54
|
}
|
|
46
55
|
}
|
|
47
56
|
|
|
48
|
-
export { createContext };
|
|
57
|
+
export { createCascade, createContext };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{invariant as
|
|
1
|
+
import{invariant as n,defaultTo as r,assign as u,optionalFunctionValue as t}from"vest-utils";var e=Symbol();function o(u){function t(){return o!==e?o:u}var o=e;return{run:function(n,r){var u=o!==e?t():e;return o=n,n=r(),o=u,n},use:t,useX:function(u){return n(o!==e,r(u,"Not inside of a running context.")),o}}}function i(n){function r(r,o){var i,f=e.use();return r=u({},f||{},null!==(i=t(n,r,f))&&void 0!==i?i:r),e.run(Object.freeze(r),o)}var e=o();return{bind:function(n,u){return function(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];return r(n,(function(){return u.apply(void 0,t)}))}},run:r,use:e.use,useX:e.useX}}export{i as createCascade,o as createContext};
|
|
@@ -4,51 +4,61 @@
|
|
|
4
4
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.context = {}, global['vest-utils']));
|
|
5
5
|
}(this, (function (exports, vestUtils) { 'use strict';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
var USEX_DEFAULT_ERROR_MESSAGE = 'Not inside of a running context.';
|
|
8
|
+
var EMPTY_CONTEXT = Symbol();
|
|
9
|
+
function createContext(defaultContextValue) {
|
|
10
|
+
var contextValue = EMPTY_CONTEXT;
|
|
10
11
|
return {
|
|
11
|
-
bind: bind,
|
|
12
12
|
run: run,
|
|
13
13
|
use: use,
|
|
14
14
|
useX: useX
|
|
15
15
|
};
|
|
16
|
+
function use() {
|
|
17
|
+
return (isInsideContext() ? contextValue : defaultContextValue);
|
|
18
|
+
}
|
|
16
19
|
function useX(errorMessage) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return ctx;
|
|
20
|
+
vestUtils.invariant(isInsideContext(), vestUtils.defaultTo(errorMessage, USEX_DEFAULT_ERROR_MESSAGE));
|
|
21
|
+
return contextValue;
|
|
20
22
|
}
|
|
21
|
-
function run(
|
|
22
|
-
var
|
|
23
|
-
|
|
24
|
-
var
|
|
25
|
-
|
|
26
|
-
var res = fn(ctx);
|
|
27
|
-
storage.ctx = parentContext;
|
|
23
|
+
function run(value, cb) {
|
|
24
|
+
var parentContext = isInsideContext() ? use() : EMPTY_CONTEXT;
|
|
25
|
+
contextValue = value;
|
|
26
|
+
var res = cb();
|
|
27
|
+
contextValue = parentContext;
|
|
28
28
|
return res;
|
|
29
29
|
}
|
|
30
|
-
function
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
function isInsideContext() {
|
|
31
|
+
return contextValue !== EMPTY_CONTEXT;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function createCascade(init) {
|
|
35
|
+
var ctx = createContext();
|
|
36
|
+
return {
|
|
37
|
+
bind: bind,
|
|
38
|
+
run: run,
|
|
39
|
+
use: ctx.use,
|
|
40
|
+
useX: ctx.useX
|
|
41
|
+
};
|
|
42
|
+
function run(value, fn) {
|
|
43
|
+
var _a;
|
|
44
|
+
var parentContext = ctx.use();
|
|
45
|
+
var out = vestUtils.assign({}, parentContext ? parentContext : {}, (_a = vestUtils.optionalFunctionValue(init, value, parentContext)) !== null && _a !== void 0 ? _a : value);
|
|
46
|
+
return ctx.run(Object.freeze(out), fn);
|
|
47
|
+
}
|
|
48
|
+
function bind(value, fn) {
|
|
49
|
+
return function () {
|
|
34
50
|
var runTimeArgs = [];
|
|
35
51
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
36
52
|
runTimeArgs[_i] = arguments[_i];
|
|
37
53
|
}
|
|
38
|
-
return run(
|
|
54
|
+
return run(value, function () {
|
|
39
55
|
return fn.apply(void 0, runTimeArgs);
|
|
40
56
|
});
|
|
41
57
|
};
|
|
42
|
-
return returnedFn;
|
|
43
|
-
}
|
|
44
|
-
function use() {
|
|
45
|
-
return storage.ctx;
|
|
46
|
-
}
|
|
47
|
-
function set(value) {
|
|
48
|
-
return (storage.ctx = value);
|
|
49
58
|
}
|
|
50
59
|
}
|
|
51
60
|
|
|
61
|
+
exports.createCascade = createCascade;
|
|
52
62
|
exports.createContext = createContext;
|
|
53
63
|
|
|
54
64
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";!function(e,
|
|
1
|
+
"use strict";!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("vest-utils")):"function"==typeof define&&define.amd?define(["exports","vest-utils"],n):n((e="undefined"!=typeof globalThis?globalThis:e||self).context={},e["vest-utils"])}(this,(function(e,n){function t(e){function t(){return r!==u?r:e}var r=u;return{run:function(e,n){var o=r!==u?t():u;return r=e,e=n(),r=o,e},use:t,useX:function(e){return n.invariant(r!==u,n.defaultTo(e,"Not inside of a running context.")),r}}}var u=Symbol();e.createCascade=function(e){function u(t,u){var o,i=r.use();return t=n.assign({},i||{},null!==(o=n.optionalFunctionValue(e,t,i))&&void 0!==o?o:t),r.run(Object.freeze(t),u)}var r=t();return{bind:function(e,n){return function(){for(var t=[],r=0;r<arguments.length;r++)t[r]=arguments[r];return u(e,(function(){return n.apply(void 0,t)}))}},run:u,use:r.use,useX:r.useX}},e.createContext=t,Object.defineProperty(e,"__esModule",{value:!0})}));
|
package/package.json
CHANGED
package/types/context.d.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
type CB = (...args: any[]) => any;
|
|
2
|
-
declare function createContext<T extends
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
use: () => T
|
|
2
|
+
declare function createContext<T extends unknown>(defaultContextValue?: T): CtxApi<T>;
|
|
3
|
+
declare function createCascade<T extends Record<string, unknown>>(init?: (value: Partial<T>, parentContext: T | void) => T | null): CtxCascadeApi<T>;
|
|
4
|
+
type ContextConsumptionApi<T> = {
|
|
5
|
+
use: () => T;
|
|
6
6
|
useX: (errorMessage?: string) => T;
|
|
7
7
|
};
|
|
8
|
-
|
|
8
|
+
type CtxApi<T> = ContextConsumptionApi<T> & {
|
|
9
|
+
run: <R>(value: T, cb: () => R) => R;
|
|
10
|
+
};
|
|
11
|
+
type CtxCascadeApi<T> = ContextConsumptionApi<T> & {
|
|
12
|
+
run: <R>(value: Partial<T>, fn: () => R) => R;
|
|
13
|
+
bind: <Fn extends CB>(value: Partial<T>, fn: Fn) => Fn;
|
|
14
|
+
};
|
|
15
|
+
export { createContext, createCascade, CtxApi, CtxCascadeApi };
|