Skip to content
This repository was archived by the owner on Sep 17, 2023. It is now read-only.

Commit a1ce5d7

Browse files
committed
Introduce ContextKeyDefaults
Use it as a default value provider in context keys.
1 parent 7f29a88 commit a1ce5d7

File tree

6 files changed

+56
-26
lines changed

6 files changed

+56
-26
lines changed

src/context-key.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,24 @@ export interface ContextValueOpts<Ctx extends ContextValues, Value, Src, Seed> {
111111

112112
}
113113

114+
/**
115+
* A provider of default value of context key.
116+
*
117+
* This is typically passed as `byDefault` option to context value key constructor.
118+
*
119+
* @typeparam Ctx Context type.
120+
* @typeparam Value Context value type.
121+
* @typeparam Key Context key type.
122+
*/
123+
export type ContextKeyDefault<Value, Key extends ContextKey<any, any, any>> =
124+
/**
125+
* @param context Target context.
126+
* @param key Context value key the default value is provided for.
127+
*
128+
* @return Either constructed value, or `null`/`undefined` if unknown.
129+
*/
130+
(this: void, context: ContextValues, key: Key) => Value | null | undefined;
131+
114132
/**
115133
* A key of context value holding a seed of context value.
116134
*

src/context-up-key.spec.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,16 @@ describe('ContextUpKey', () => {
8484
it('provides fallback value if there is no provider', () => {
8585
expect(readValue(values.get(key, { or: afterEventOf('fallback') }))).toBe('fallback');
8686
});
87-
it('provides default value if provider did not provide any value', () => {
87+
it('provides default value if not provided', () => {
8888

8989
const defaultValue = 'default';
90-
const keyWithDefaults = new SingleContextUpKey<string>(key.name, { byDefault: () => defaultValue });
90+
const byDefault = jest.fn(() => defaultValue);
91+
const keyWithDefaults = new SingleContextUpKey<string>(key.name, { byDefault });
9192

9293
registry.provide({ a: keyWithDefaults, is: null });
9394

9495
expect(readValue(values.get(keyWithDefaults))).toBe(defaultValue);
96+
expect(byDefault).toHaveBeenCalledWith(values, keyWithDefaults);
9597
});
9698

9799
function readValue<Value>(from: AfterEvent<[Value]>): Value {
@@ -125,12 +127,14 @@ describe('ContextUpKey', () => {
125127
it('is associated with default value if providers did not return any values', () => {
126128

127129
const defaultValue = ['default'];
128-
const keyWithDefaults = new MultiContextUpKey('key', { byDefault: () => defaultValue });
130+
const byDefault = jest.fn(() => defaultValue);
131+
const keyWithDefaults = new MultiContextUpKey('key', { byDefault });
129132

130133
registry.provide({ a: keyWithDefaults, is: null });
131134
registry.provide({ a: keyWithDefaults, is: undefined });
132135

133136
expect(readValue(values.get(keyWithDefaults))).toEqual(defaultValue);
137+
expect(byDefault).toHaveBeenCalledWith(values, keyWithDefaults);
134138
});
135139
it('is associated with provided values array', () => {
136140
registry.provide({ a: key, is: 'a' });

src/context-up-key.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ import {
1414
trackValue,
1515
ValueTracker,
1616
} from 'fun-events';
17-
import { ContextKey, ContextSeedKey, ContextValueOpts } from './context-key';
17+
import { ContextKey, ContextSeedKey, ContextKeyDefault, ContextValueOpts } from './context-key';
18+
import { ContextKeyError } from './context-key-error';
1819
import { ContextRef } from './context-ref';
1920
import { ContextSeeder } from './context-seeder';
2021
import { ContextValueProvider } from './context-value-spec';
2122
import { ContextValues } from './context-values';
22-
import { ContextKeyError } from './context-key-error';
2323

2424
class ContextUpSeeder<Ctx extends ContextValues, Src>
2525
implements ContextSeeder<Ctx, Src | EventKeeper<Src[]>, AfterEvent<Src[]>> {
@@ -162,7 +162,7 @@ export class SingleContextUpKey<Value>
162162
/**
163163
* A provider of context value used when there is no value associated with this key.
164164
*/
165-
readonly byDefault: ContextValueProvider<ContextValues, Value>;
165+
readonly byDefault: ContextKeyDefault<Value, ContextUpKey<AfterEvent<[Value]>, Value>>;
166166

167167
/**
168168
* Constructs single updatable context value key.
@@ -179,8 +179,9 @@ export class SingleContextUpKey<Value>
179179
byDefault = noop,
180180
}: {
181181
seedKey?: ContextSeedKey<Value | EventKeeper<Value[]>, AfterEvent<Value[]>>,
182-
byDefault?: ContextValueProvider<ContextValues, Value>,
183-
} = {}) {
182+
byDefault?: ContextKeyDefault<Value, ContextUpKey<AfterEvent<[Value]>, Value>>,
183+
} = {},
184+
) {
184185
super(name, seedKey);
185186
this.byDefault = byDefault;
186187
}
@@ -197,7 +198,7 @@ export class SingleContextUpKey<Value>
197198
// Sources absent. Attempt to detect the backup value.
198199
const backup = opts.byDefault(() => {
199200

200-
const defaultValue = this.byDefault(opts.context);
201+
const defaultValue = this.byDefault(opts.context, this);
201202

202203
return defaultValue && afterEventOf(defaultValue);
203204
});
@@ -241,7 +242,7 @@ export class MultiContextUpKey<Src>
241242
/**
242243
* A provider of context value used when there is no value associated with this key.
243244
*/
244-
readonly byDefault: ContextValueProvider<ContextValues, readonly Src[]>;
245+
readonly byDefault: ContextKeyDefault<readonly Src[], ContextUpKey<AfterEvent<Src[]>, Src>>;
245246

246247
/**
247248
* Constructs multiple updatable context value key.
@@ -258,8 +259,9 @@ export class MultiContextUpKey<Src>
258259
byDefault = noop,
259260
}: {
260261
seedKey?: ContextSeedKey<Src | EventKeeper<Src[]>, AfterEvent<Src[]>>,
261-
byDefault?: ContextValueProvider<ContextValues, readonly Src[]>,
262-
} = {}) {
262+
byDefault?: ContextKeyDefault<readonly Src[], ContextUpKey<AfterEvent<Src[]>, Src>>,
263+
} = {},
264+
) {
263265
super(name, seedKey);
264266
this.byDefault = byDefault;
265267
}
@@ -276,7 +278,7 @@ export class MultiContextUpKey<Src>
276278
// Sources absent. Attempt to detect the backup value.
277279
const backup = opts.byDefault(() => {
278280

279-
const defaultValue = this.byDefault(opts.context);
281+
const defaultValue = this.byDefault(opts.context, this);
280282

281283
return defaultValue ? afterEventOf(...defaultValue) : afterEventOf();
282284
});

src/context-value-spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export type ContextValueProvider<Ctx extends ContextValues, Src> =
1818
/**
1919
* @param context Target context.
2020
*
21-
* @return Either constructed value, or `null`/`undefined` if the value can not be constructed.
21+
* @return Either constructed value source, or `null`/`undefined` if unknown.
2222
*/
2323
(this: void, context: Ctx) => Src | null | undefined;
2424

src/simple-context-key.spec.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,16 @@ describe('SimpleContextKey', () => {
7171
it('provides fallback value if there is no provider', () => {
7272
expect(values.get(new SingleContextKey<string>(key.name), { or: 'fallback' })).toBe('fallback');
7373
});
74-
it('provides default value if provider did not provide any value', () => {
74+
it('provides default value if no value provided', () => {
7575

7676
const defaultValue = 'default';
77-
const keyWithDefaults = new SingleContextKey(key.name, { byDefault: () => defaultValue });
77+
const byDefault = jest.fn(() => defaultValue);
78+
const keyWithDefaults = new SingleContextKey(key.name, { byDefault });
7879

7980
registry.provide({ a: keyWithDefaults, is: null });
8081

8182
expect(values.get(keyWithDefaults)).toBe(defaultValue);
83+
expect(byDefault).toHaveBeenCalledWith(values, keyWithDefaults);
8284
});
8385
it('provides default value if there is no provider', () => {
8486
expect(values.get(new SingleContextKey<string>(key.name, { byDefault: () => 'default' }))).toBe('default');
@@ -175,12 +177,14 @@ describe('SimpleContextKey', () => {
175177
it('is associated with default value if providers did not return any values', () => {
176178

177179
const defaultValue = ['default'];
178-
const keyWithDefaults = new MultiContextKey('key', { byDefault: () => defaultValue });
180+
const byDefault = jest.fn(() => defaultValue);
181+
const keyWithDefaults = new MultiContextKey('key', { byDefault });
179182

180183
registry.provide({ a: keyWithDefaults, is: null });
181184
registry.provide({ a: keyWithDefaults, is: undefined });
182185

183186
expect(values.get(keyWithDefaults)).toEqual(defaultValue);
187+
expect(byDefault).toHaveBeenCalledWith(values, keyWithDefaults);
184188
});
185189
it('is associated with provided values array', () => {
186190
registry.provide({ a: key, is: 'a' });

src/simple-context-key.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44
import { AIterable, itsEmpty, itsLast, overArray, overNone } from 'a-iterable';
55
import { asis, isPresent, noop, valuesProvider } from 'call-thru';
6-
import { ContextKey, ContextSeedKey, ContextValueOpts } from './context-key';
6+
import { ContextKey, ContextKeyDefault, ContextSeedKey, ContextValueOpts } from './context-key';
77
import { ContextRef } from './context-ref';
88
import { ContextSeeder } from './context-seeder';
99
import { ContextValueProvider } from './context-value-spec';
@@ -99,7 +99,7 @@ export class SingleContextKey<Value>
9999
/**
100100
* A provider of context value used when there is no value associated with this key.
101101
*/
102-
readonly byDefault: ContextValueProvider<ContextValues, Value>;
102+
readonly byDefault: ContextKeyDefault<Value, ContextKey<Value>>;
103103

104104
/**
105105
* Constructs single context value key.
@@ -116,8 +116,9 @@ export class SingleContextKey<Value>
116116
byDefault = noop,
117117
}: {
118118
seedKey?: ContextSeedKey<Value, AIterable<Value>>,
119-
byDefault?: ContextValueProvider<ContextValues, Value>,
120-
} = {}) {
119+
byDefault?: ContextKeyDefault<Value, ContextKey<Value>>,
120+
} = {},
121+
) {
121122
super(name, seedKey);
122123
this.byDefault = byDefault;
123124
}
@@ -132,7 +133,7 @@ export class SingleContextKey<Value>
132133
return value;
133134
}
134135

135-
return opts.byDefault(() => this.byDefault(opts.context));
136+
return opts.byDefault(() => this.byDefault(opts.context, this));
136137
}
137138

138139
}
@@ -163,7 +164,7 @@ export class MultiContextKey<Src>
163164
/**
164165
* A provider of context value used when there is no value associated with this key.
165166
*/
166-
readonly byDefault: ContextValueProvider<ContextValues, readonly Src[]>;
167+
readonly byDefault: ContextKeyDefault<readonly Src[], ContextKey<readonly Src[], Src>>;
167168

168169
/**
169170
* Constructs multiple context values key.
@@ -179,8 +180,9 @@ export class MultiContextKey<Src>
179180
byDefault = valuesProvider(),
180181
}: {
181182
seedKey?: ContextSeedKey<Src, AIterable<Src>>,
182-
byDefault?: ContextValueProvider<ContextValues, readonly Src[]>,
183-
} = {}) {
183+
byDefault?: ContextKeyDefault<readonly Src[], ContextKey<readonly Src[], Src>>,
184+
} = {},
185+
) {
184186
super(name, seedKey);
185187
this.byDefault = byDefault;
186188
}
@@ -197,7 +199,7 @@ export class MultiContextKey<Src>
197199

198200
return opts.byDefault(() => {
199201

200-
const defaultSources = this.byDefault(opts.context);
202+
const defaultSources = this.byDefault(opts.context, this);
201203

202204
if (defaultSources) {
203205
return [...defaultSources];

0 commit comments

Comments
 (0)