@tko/computed 4.0.0-alpha8.0 → 4.0.0-beta1.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/dist/computed.js CHANGED
@@ -1,668 +1,425 @@
1
- /*!
2
- * TKO Computed Observables 🥊 @tko/computed@4.0.0-alpha8.0
3
- * (c) The Knockout.js Team - https://tko.io
4
- * License: MIT (http://www.opensource.org/licenses/mit-license.php)
5
- */
6
-
7
- import { addDisposeCallback, arrayForEach, createSymbolOrString, domNodeIsAttachedToDocument, extend, options, hasOwnProperty, objectForEach, removeDisposeCallback, safeSetTimeout } from '@tko/utils';
8
- import { dependencyDetection, extenders, valuesArePrimitiveAndEqual, observable, subscribable, LATEST_VALUE, observableArray, unwrap } from '@tko/observable';
9
-
10
- var _a;
11
- var computedState = createSymbolOrString('_state');
12
- var DISPOSED_STATE = {
13
- dependencyTracking: null,
14
- dependenciesCount: 0,
15
- isDisposed: true,
16
- isStale: false,
17
- isDirty: false,
18
- isSleeping: false,
19
- disposeWhenNodeIsRemoved: null,
20
- readFunction: null,
21
- _options: null
22
- };
23
- function computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget, options$$1) {
24
- if (typeof evaluatorFunctionOrOptions === 'object') {
25
- // Single-parameter syntax - everything is on this "options" param
26
- options$$1 = evaluatorFunctionOrOptions;
27
- }
28
- else {
29
- // Multi-parameter syntax - construct the options according to the params passed
30
- options$$1 = options$$1 || {};
31
- if (evaluatorFunctionOrOptions) {
32
- options$$1.read = evaluatorFunctionOrOptions;
33
- }
34
- }
35
- if (typeof options$$1.read !== 'function') {
36
- throw Error('Pass a function that returns the value of the computed');
37
- }
38
- var writeFunction = options$$1.write;
39
- var state = {
40
- latestValue: undefined,
41
- isStale: true,
42
- isDirty: true,
43
- isBeingEvaluated: false,
44
- suppressDisposalUntilDisposeWhenReturnsFalse: false,
45
- isDisposed: false,
46
- pure: false,
47
- isSleeping: false,
48
- readFunction: options$$1.read,
49
- evaluatorFunctionTarget: evaluatorFunctionTarget || options$$1.owner,
50
- disposeWhenNodeIsRemoved: options$$1.disposeWhenNodeIsRemoved || options$$1.disposeWhenNodeIsRemoved || null,
51
- disposeWhen: options$$1.disposeWhen || options$$1.disposeWhen,
52
- domNodeDisposalCallback: null,
53
- dependencyTracking: {},
54
- dependenciesCount: 0,
55
- evaluationTimeoutInstance: null
56
- };
57
- function computedObservable() {
58
- if (arguments.length > 0) {
59
- if (typeof writeFunction === 'function') {
60
- // Writing a value
61
- writeFunction.apply(state.evaluatorFunctionTarget, arguments);
62
- }
63
- else {
64
- throw new Error("Cannot write a value to a computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");
65
- }
66
- return this; // Permits chained assignments
67
- }
68
- else {
69
- // Reading the value
70
- if (!state.isDisposed) {
71
- dependencyDetection.registerDependency(computedObservable);
72
- }
73
- if (state.isDirty || (state.isSleeping && computedObservable.haveDependenciesChanged())) {
74
- computedObservable.evaluateImmediate();
75
- }
76
- return state.latestValue;
77
- }
78
- }
79
- computedObservable[computedState] = state;
80
- computedObservable.isWriteable = typeof writeFunction === 'function';
81
- subscribable.fn.init(computedObservable);
82
- // Inherit from 'computed'
83
- Object.setPrototypeOf(computedObservable, computed.fn);
84
- if (options$$1.pure) {
85
- state.pure = true;
86
- state.isSleeping = true; // Starts off sleeping; will awake on the first subscription
87
- extend(computedObservable, pureComputedOverrides);
88
- }
89
- else if (options$$1.deferEvaluation) {
90
- extend(computedObservable, deferEvaluationOverrides);
91
- }
92
- if (options.deferUpdates) {
93
- extenders.deferred(computedObservable, true);
94
- }
95
- if (options.debug) {
96
- // #1731 - Aid debugging by exposing the computed's options
97
- computedObservable._options = options$$1;
98
- }
99
- if (state.disposeWhenNodeIsRemoved) {
100
- // Since this computed is associated with a DOM node, and we don't want to dispose the computed
101
- // until the DOM node is *removed* from the document (as opposed to never having been in the document),
102
- // we'll prevent disposal until "disposeWhen" first returns false.
103
- state.suppressDisposalUntilDisposeWhenReturnsFalse = true;
104
- // disposeWhenNodeIsRemoved: true can be used to opt into the "only dispose after first false result"
105
- // behavior even if there's no specific node to watch. In that case, clear the option so we don't try
106
- // to watch for a non-node's disposal. This technique is intended for KO's internal use only and shouldn't
107
- // be documented or used by application code, as it's likely to change in a future version of KO.
108
- if (!state.disposeWhenNodeIsRemoved.nodeType) {
109
- state.disposeWhenNodeIsRemoved = null;
110
- }
111
- }
112
- // Evaluate, unless sleeping or deferEvaluation is true
113
- if (!state.isSleeping && !options$$1.deferEvaluation) {
114
- computedObservable.evaluateImmediate();
115
- }
116
- // Attach a DOM node disposal callback so that the computed will be proactively disposed as soon as the node is
117
- // removed using ko.removeNode. But skip if isActive is false (there will never be any dependencies to dispose).
118
- if (state.disposeWhenNodeIsRemoved && computedObservable.isActive()) {
119
- addDisposeCallback(state.disposeWhenNodeIsRemoved, state.domNodeDisposalCallback = function () {
120
- computedObservable.dispose();
121
- });
122
- }
123
- return computedObservable;
124
- }
125
- // Utility function that disposes a given dependencyTracking entry
126
- function computedDisposeDependencyCallback(id, entryToDispose) {
127
- if (entryToDispose !== null && entryToDispose.dispose) {
128
- entryToDispose.dispose();
129
- }
130
- }
131
- // This function gets called each time a dependency is detected while evaluating a computed.
132
- // It's factored out as a shared function to avoid creating unnecessary function instances during evaluation.
133
- function computedBeginDependencyDetectionCallback(subscribable$$1, id) {
134
- var computedObservable = this.computedObservable, state = computedObservable[computedState];
135
- if (!state.isDisposed) {
136
- if (this.disposalCount && this.disposalCandidates[id]) {
137
- // Don't want to dispose this subscription, as it's still being used
138
- computedObservable.addDependencyTracking(id, subscribable$$1, this.disposalCandidates[id]);
139
- this.disposalCandidates[id] = null; // No need to actually delete the property - disposalCandidates is a transient object anyway
140
- --this.disposalCount;
141
- }
142
- else if (!state.dependencyTracking[id]) {
143
- // Brand new subscription - add it
144
- computedObservable.addDependencyTracking(id, subscribable$$1, state.isSleeping ? { _target: subscribable$$1 } : computedObservable.subscribeToDependency(subscribable$$1));
145
- }
146
- // If the observable we've accessed has a pending notification, ensure
147
- // we get notified of the actual final value (bypass equality checks)
148
- if (subscribable$$1._notificationIsPending) {
149
- subscribable$$1._notifyNextChangeIfValueIsDifferent();
150
- }
151
- }
152
- }
153
- computed.fn = (_a = {
154
- equalityComparer: valuesArePrimitiveAndEqual,
155
- getDependenciesCount: function () {
156
- return this[computedState].dependenciesCount;
157
- },
158
- getDependencies: function () {
159
- var dependencyTracking = this[computedState].dependencyTracking;
160
- var dependentObservables = [];
161
- objectForEach(dependencyTracking, function (id, dependency) {
162
- dependentObservables[dependency._order] = dependency._target;
163
- });
164
- return dependentObservables;
165
- },
166
- addDependencyTracking: function (id, target, trackingObj) {
167
- if (this[computedState].pure && target === this) {
168
- throw Error("A 'pure' computed must not be called recursively");
169
- }
170
- this[computedState].dependencyTracking[id] = trackingObj;
171
- trackingObj._order = this[computedState].dependenciesCount++;
172
- trackingObj._version = target.getVersion();
173
- },
174
- haveDependenciesChanged: function () {
175
- var id, dependency, dependencyTracking = this[computedState].dependencyTracking;
176
- for (id in dependencyTracking) {
177
- if (hasOwnProperty(dependencyTracking, id)) {
178
- dependency = dependencyTracking[id];
179
- if ((this._evalDelayed && dependency._target._notificationIsPending) || dependency._target.hasChanged(dependency._version)) {
180
- return true;
181
- }
182
- }
183
- }
184
- },
185
- markDirty: function () {
186
- // Process "dirty" events if we can handle delayed notifications
187
- if (this._evalDelayed && !this[computedState].isBeingEvaluated) {
188
- this._evalDelayed(false /* notifyChange */);
189
- }
190
- },
191
- isActive: function () {
192
- var state = this[computedState];
193
- return state.isDirty || state.dependenciesCount > 0;
194
- },
195
- respondToChange: function () {
196
- // Ignore "change" events if we've already scheduled a delayed notification
197
- if (!this._notificationIsPending) {
198
- this.evaluatePossiblyAsync();
199
- }
200
- else if (this[computedState].isDirty) {
201
- this[computedState].isStale = true;
202
- }
203
- },
204
- subscribeToDependency: function (target) {
205
- if (target._deferUpdates) {
206
- var dirtySub = target.subscribe(this.markDirty, this, 'dirty'), changeSub = target.subscribe(this.respondToChange, this);
207
- return {
208
- _target: target,
209
- dispose: function () {
210
- dirtySub.dispose();
211
- changeSub.dispose();
212
- }
213
- };
214
- }
215
- else {
216
- return target.subscribe(this.evaluatePossiblyAsync, this);
217
- }
218
- },
219
- evaluatePossiblyAsync: function () {
220
- var computedObservable = this, throttleEvaluationTimeout = computedObservable.throttleEvaluation;
221
- if (throttleEvaluationTimeout && throttleEvaluationTimeout >= 0) {
222
- clearTimeout(this[computedState].evaluationTimeoutInstance);
223
- this[computedState].evaluationTimeoutInstance = safeSetTimeout(function () {
224
- computedObservable.evaluateImmediate(true /* notifyChange */);
225
- }, throttleEvaluationTimeout);
226
- }
227
- else if (computedObservable._evalDelayed) {
228
- computedObservable._evalDelayed(true /* notifyChange */);
229
- }
230
- else {
231
- computedObservable.evaluateImmediate(true /* notifyChange */);
232
- }
233
- },
234
- evaluateImmediate: function (notifyChange) {
235
- var computedObservable = this, state = computedObservable[computedState], disposeWhen = state.disposeWhen, changed = false;
236
- if (state.isBeingEvaluated) {
237
- // If the evaluation of a ko.computed causes side effects, it's possible that it will trigger its own re-evaluation.
238
- // This is not desirable (it's hard for a developer to realise a chain of dependencies might cause this, and they almost
239
- // certainly didn't intend infinite re-evaluations). So, for predictability, we simply prevent ko.computeds from causing
240
- // their own re-evaluation. Further discussion at https://github.com/SteveSanderson/knockout/pull/387
241
- return;
242
- }
243
- // Do not evaluate (and possibly capture new dependencies) if disposed
244
- if (state.isDisposed) {
245
- return;
246
- }
247
- if (state.disposeWhenNodeIsRemoved && !domNodeIsAttachedToDocument(state.disposeWhenNodeIsRemoved) || disposeWhen && disposeWhen()) {
248
- // See comment above about suppressDisposalUntilDisposeWhenReturnsFalse
249
- if (!state.suppressDisposalUntilDisposeWhenReturnsFalse) {
250
- computedObservable.dispose();
251
- return;
252
- }
253
- }
254
- else {
255
- // It just did return false, so we can stop suppressing now
256
- state.suppressDisposalUntilDisposeWhenReturnsFalse = false;
257
- }
258
- state.isBeingEvaluated = true;
259
- try {
260
- changed = this.evaluateImmediate_CallReadWithDependencyDetection(notifyChange);
261
- }
262
- finally {
263
- state.isBeingEvaluated = false;
264
- }
265
- return changed;
266
- },
267
- evaluateImmediate_CallReadWithDependencyDetection: function (notifyChange) {
268
- // This function is really just part of the evaluateImmediate logic. You would never call it from anywhere else.
269
- // Factoring it out into a separate function means it can be independent of the try/catch block in evaluateImmediate,
270
- // which contributes to saving about 40% off the CPU overhead of computed evaluation (on V8 at least).
271
- var computedObservable = this, state = computedObservable[computedState], changed = false;
272
- // Initially, we assume that none of the subscriptions are still being used (i.e., all are candidates for disposal).
273
- // Then, during evaluation, we cross off any that are in fact still being used.
274
- var isInitial = state.pure ? undefined : !state.dependenciesCount, // If we're evaluating when there are no previous dependencies, it must be the first time
275
- dependencyDetectionContext = {
276
- computedObservable: computedObservable,
277
- disposalCandidates: state.dependencyTracking,
278
- disposalCount: state.dependenciesCount
279
- };
280
- dependencyDetection.begin({
281
- callbackTarget: dependencyDetectionContext,
282
- callback: computedBeginDependencyDetectionCallback,
283
- computed: computedObservable,
284
- isInitial: isInitial
285
- });
286
- state.dependencyTracking = {};
287
- state.dependenciesCount = 0;
288
- var newValue = this.evaluateImmediate_CallReadThenEndDependencyDetection(state, dependencyDetectionContext);
289
- if (!state.dependenciesCount) {
290
- computedObservable.dispose();
291
- changed = true; // When evaluation causes a disposal, make sure all dependent computeds get notified so they'll see the new state
292
- }
293
- else {
294
- changed = computedObservable.isDifferent(state.latestValue, newValue);
295
- }
296
- if (changed) {
297
- if (!state.isSleeping) {
298
- computedObservable.notifySubscribers(state.latestValue, 'beforeChange');
299
- }
300
- else {
301
- computedObservable.updateVersion();
302
- }
303
- state.latestValue = newValue;
304
- if (options.debug) {
305
- computedObservable._latestValue = newValue;
306
- }
307
- computedObservable.notifySubscribers(state.latestValue, 'spectate');
308
- if (!state.isSleeping && notifyChange) {
309
- computedObservable.notifySubscribers(state.latestValue);
310
- }
311
- if (computedObservable._recordUpdate) {
312
- computedObservable._recordUpdate();
313
- }
314
- }
315
- if (isInitial) {
316
- computedObservable.notifySubscribers(state.latestValue, 'awake');
317
- }
318
- return changed;
319
- },
320
- evaluateImmediate_CallReadThenEndDependencyDetection: function (state, dependencyDetectionContext) {
321
- // This function is really part of the evaluateImmediate_CallReadWithDependencyDetection logic.
322
- // You'd never call it from anywhere else. Factoring it out means that evaluateImmediate_CallReadWithDependencyDetection
323
- // can be independent of try/finally blocks, which contributes to saving about 40% off the CPU
324
- // overhead of computed evaluation (on V8 at least).
325
- try {
326
- var readFunction = state.readFunction;
327
- return state.evaluatorFunctionTarget ? readFunction.call(state.evaluatorFunctionTarget) : readFunction();
328
- }
329
- finally {
330
- dependencyDetection.end();
331
- // For each subscription no longer being used, remove it from the active subscriptions list and dispose it
332
- if (dependencyDetectionContext.disposalCount && !state.isSleeping) {
333
- objectForEach(dependencyDetectionContext.disposalCandidates, computedDisposeDependencyCallback);
334
- }
335
- state.isStale = state.isDirty = false;
336
- }
337
- },
338
- peek: function (forceEvaluate) {
339
- // Peek won't ordinarily re-evaluate, except while the computed is sleeping
340
- // or to get the initial value when "deferEvaluation" is set.
341
- var state = this[computedState];
342
- if ((state.isDirty && (forceEvaluate || !state.dependenciesCount)) || (state.isSleeping && this.haveDependenciesChanged())) {
343
- this.evaluateImmediate();
344
- }
345
- return state.latestValue;
346
- }
347
- },
348
- Object.defineProperty(_a, LATEST_VALUE, {
349
- get: function () {
350
- return this.peek();
351
- },
352
- enumerable: true,
353
- configurable: true
354
- }),
355
- _a.limit = function (limitFunction) {
356
- var state = this[computedState];
357
- // Override the limit function with one that delays evaluation as well
358
- subscribable.fn.limit.call(this, limitFunction);
359
- Object.assign(this, {
360
- _evalIfChanged: function () {
361
- if (!this[computedState].isSleeping) {
362
- if (this[computedState].isStale) {
363
- this.evaluateImmediate();
364
- }
365
- else {
366
- this[computedState].isDirty = false;
367
- }
368
- }
369
- return state.latestValue;
370
- },
371
- _evalDelayed: function (isChange) {
372
- this._limitBeforeChange(state.latestValue);
373
- // Mark as dirty
374
- state.isDirty = true;
375
- if (isChange) {
376
- state.isStale = true;
377
- }
378
- // Pass the observable to the "limit" code, which will evaluate it when
379
- // it's time to do the notification.
380
- this._limitChange(this, !isChange /* isDirty */);
381
- }
382
- });
383
- },
384
- _a.dispose = function () {
385
- var state = this[computedState];
386
- if (!state.isSleeping && state.dependencyTracking) {
387
- objectForEach(state.dependencyTracking, function (id, dependency) {
388
- if (dependency.dispose) {
389
- dependency.dispose();
390
- }
391
- });
392
- }
393
- if (state.disposeWhenNodeIsRemoved && state.domNodeDisposalCallback) {
394
- removeDisposeCallback(state.disposeWhenNodeIsRemoved, state.domNodeDisposalCallback);
395
- }
396
- Object.assign(state, DISPOSED_STATE);
397
- },
398
- _a);
399
- var pureComputedOverrides = {
400
- beforeSubscriptionAdd: function (event) {
401
- // If asleep, wake up the computed by subscribing to any dependencies.
402
- var computedObservable = this, state = computedObservable[computedState];
403
- if (!state.isDisposed && state.isSleeping && event === 'change') {
404
- state.isSleeping = false;
405
- if (state.isStale || computedObservable.haveDependenciesChanged()) {
406
- state.dependencyTracking = null;
407
- state.dependenciesCount = 0;
408
- if (computedObservable.evaluateImmediate()) {
409
- computedObservable.updateVersion();
410
- }
411
- }
412
- else {
413
- // First put the dependencies in order
414
- var dependenciesOrder = [];
415
- objectForEach(state.dependencyTracking, function (id, dependency) {
416
- dependenciesOrder[dependency._order] = id;
417
- });
418
- // Next, subscribe to each one
419
- arrayForEach(dependenciesOrder, function (id, order) {
420
- var dependency = state.dependencyTracking[id], subscription = computedObservable.subscribeToDependency(dependency._target);
421
- subscription._order = order;
422
- subscription._version = dependency._version;
423
- state.dependencyTracking[id] = subscription;
424
- });
425
- // Waking dependencies may have triggered effects
426
- if (computedObservable.haveDependenciesChanged()) {
427
- if (computedObservable.evaluateImmediate()) {
428
- computedObservable.updateVersion();
429
- }
430
- }
431
- }
432
- if (!state.isDisposed) { // test since evaluating could trigger disposal
433
- computedObservable.notifySubscribers(state.latestValue, 'awake');
434
- }
435
- }
436
- },
437
- afterSubscriptionRemove: function (event) {
438
- var state = this[computedState];
439
- if (!state.isDisposed && event === 'change' && !this.hasSubscriptionsForEvent('change')) {
440
- objectForEach(state.dependencyTracking, function (id, dependency) {
441
- if (dependency.dispose) {
442
- state.dependencyTracking[id] = {
443
- _target: dependency._target,
444
- _order: dependency._order,
445
- _version: dependency._version
446
- };
447
- dependency.dispose();
448
- }
449
- });
450
- state.isSleeping = true;
451
- this.notifySubscribers(undefined, 'asleep');
452
- }
453
- },
454
- getVersion: function () {
455
- // Because a pure computed is not automatically updated while it is sleeping, we can't
456
- // simply return the version number. Instead, we check if any of the dependencies have
457
- // changed and conditionally re-evaluate the computed observable.
458
- var state = this[computedState];
459
- if (state.isSleeping && (state.isStale || this.haveDependenciesChanged())) {
460
- this.evaluateImmediate();
461
- }
462
- return subscribable.fn.getVersion.call(this);
463
- }
464
- };
465
- var deferEvaluationOverrides = {
466
- beforeSubscriptionAdd: function (event) {
467
- // This will force a computed with deferEvaluation to evaluate when the first subscription is registered.
468
- if (event === 'change' || event === 'beforeChange') {
469
- this.peek();
470
- }
471
- }
472
- };
473
- Object.setPrototypeOf(computed.fn, subscribable.fn);
474
- // Set the proto values for ko.computed
475
- var protoProp = observable.protoProperty; // == "__ko_proto__"
476
- computed.fn[protoProp] = computed;
477
- /* This is used by ko.isObservable */
478
- observable.observablePrototypes.add(computed);
479
- function isComputed(instance) {
480
- return (typeof instance === 'function' && instance[protoProp] === computed);
481
- }
482
- function isPureComputed(instance) {
483
- return isComputed(instance) && instance[computedState] && instance[computedState].pure;
484
- }
485
- function pureComputed(evaluatorFunctionOrOptions, evaluatorFunctionTarget) {
486
- if (typeof evaluatorFunctionOrOptions === 'function') {
487
- return computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget, { 'pure': true });
488
- }
489
- else {
490
- evaluatorFunctionOrOptions = extend({}, evaluatorFunctionOrOptions); // make a copy of the parameter object
491
- evaluatorFunctionOrOptions.pure = true;
492
- return computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget);
493
- }
1
+ // @tko/computed 🥊 4.0.0-beta1.0 ESM
2
+ import {
3
+ addDisposeCallback,
4
+ arrayForEach,
5
+ createSymbolOrString,
6
+ domNodeIsAttachedToDocument,
7
+ extend,
8
+ options,
9
+ hasOwnProperty,
10
+ objectForEach,
11
+ options as koOptions,
12
+ removeDisposeCallback,
13
+ safeSetTimeout
14
+ } from "@tko/utils";
15
+ import {
16
+ dependencyDetection,
17
+ extenders,
18
+ valuesArePrimitiveAndEqual,
19
+ observable,
20
+ subscribable,
21
+ LATEST_VALUE
22
+ } from "@tko/observable";
23
+ const computedState = createSymbolOrString("_state");
24
+ const DISPOSED_STATE = {
25
+ dependencyTracking: null,
26
+ dependenciesCount: 0,
27
+ isDisposed: true,
28
+ isStale: false,
29
+ isDirty: false,
30
+ isSleeping: false,
31
+ disposeWhenNodeIsRemoved: null,
32
+ readFunction: null,
33
+ _options: null
34
+ };
35
+ export function computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget, options2) {
36
+ if (typeof evaluatorFunctionOrOptions === "object") {
37
+ options2 = evaluatorFunctionOrOptions;
38
+ } else {
39
+ options2 = options2 || {};
40
+ if (evaluatorFunctionOrOptions) {
41
+ options2.read = evaluatorFunctionOrOptions;
42
+ }
43
+ }
44
+ if (typeof options2.read !== "function") {
45
+ throw Error("Pass a function that returns the value of the computed");
46
+ }
47
+ var writeFunction = options2.write;
48
+ var state = {
49
+ latestValue: void 0,
50
+ isStale: true,
51
+ isDirty: true,
52
+ isBeingEvaluated: false,
53
+ suppressDisposalUntilDisposeWhenReturnsFalse: false,
54
+ isDisposed: false,
55
+ pure: false,
56
+ isSleeping: false,
57
+ readFunction: options2.read,
58
+ evaluatorFunctionTarget: evaluatorFunctionTarget || options2.owner,
59
+ disposeWhenNodeIsRemoved: options2.disposeWhenNodeIsRemoved || options2.disposeWhenNodeIsRemoved || null,
60
+ disposeWhen: options2.disposeWhen || options2.disposeWhen,
61
+ domNodeDisposalCallback: null,
62
+ dependencyTracking: {},
63
+ dependenciesCount: 0,
64
+ evaluationTimeoutInstance: null
65
+ };
66
+ function computedObservable() {
67
+ if (arguments.length > 0) {
68
+ if (typeof writeFunction === "function") {
69
+ writeFunction.apply(state.evaluatorFunctionTarget, arguments);
70
+ } else {
71
+ throw new Error("Cannot write a value to a computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");
72
+ }
73
+ return this;
74
+ } else {
75
+ if (!state.isDisposed) {
76
+ dependencyDetection.registerDependency(computedObservable);
77
+ }
78
+ if (state.isDirty || state.isSleeping && computedObservable.haveDependenciesChanged()) {
79
+ computedObservable.evaluateImmediate();
80
+ }
81
+ return state.latestValue;
82
+ }
83
+ }
84
+ computedObservable[computedState] = state;
85
+ computedObservable.isWriteable = typeof writeFunction === "function";
86
+ subscribable.fn.init(computedObservable);
87
+ Object.setPrototypeOf(computedObservable, computed.fn);
88
+ if (options2.pure) {
89
+ state.pure = true;
90
+ state.isSleeping = true;
91
+ extend(computedObservable, pureComputedOverrides);
92
+ } else if (options2.deferEvaluation) {
93
+ extend(computedObservable, deferEvaluationOverrides);
94
+ }
95
+ if (koOptions.deferUpdates) {
96
+ extenders.deferred(computedObservable, true);
97
+ }
98
+ if (koOptions.debug) {
99
+ computedObservable._options = options2;
100
+ }
101
+ if (state.disposeWhenNodeIsRemoved) {
102
+ state.suppressDisposalUntilDisposeWhenReturnsFalse = true;
103
+ if (!state.disposeWhenNodeIsRemoved.nodeType) {
104
+ state.disposeWhenNodeIsRemoved = null;
105
+ }
106
+ }
107
+ if (!state.isSleeping && !options2.deferEvaluation) {
108
+ computedObservable.evaluateImmediate();
109
+ }
110
+ if (state.disposeWhenNodeIsRemoved && computedObservable.isActive()) {
111
+ addDisposeCallback(state.disposeWhenNodeIsRemoved, state.domNodeDisposalCallback = function() {
112
+ computedObservable.dispose();
113
+ });
114
+ }
115
+ return computedObservable;
494
116
  }
495
-
496
- function throttleExtender(target, timeout) {
497
- // Throttling means two things:
498
- // (1) For dependent observables, we throttle *evaluations* so that, no matter how fast its dependencies
499
- // notify updates, the target doesn't re-evaluate (and hence doesn't notify) faster than a certain rate
500
- target.throttleEvaluation = timeout;
501
- // (2) For writable targets (observables, or writable dependent observables), we throttle *writes*
502
- // so the target cannot change value synchronously or faster than a certain rate
503
- var writeTimeoutInstance = null;
504
- return computed({
505
- read: target,
506
- write: function (value) {
507
- clearTimeout(writeTimeoutInstance);
508
- writeTimeoutInstance = setTimeout(function () {
509
- target(value);
510
- }, timeout);
511
- }
512
- });
513
- }
514
- extenders.throttle = throttleExtender;
515
-
516
- /*! *****************************************************************************
517
- Copyright (c) Microsoft Corporation. All rights reserved.
518
- Licensed under the Apache License, Version 2.0 (the "License"); you may not use
519
- this file except in compliance with the License. You may obtain a copy of the
520
- License at http://www.apache.org/licenses/LICENSE-2.0
521
-
522
- THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
523
- KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
524
- WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
525
- MERCHANTABLITY OR NON-INFRINGEMENT.
526
-
527
- See the Apache Version 2.0 License for specific language governing permissions
528
- and limitations under the License.
529
- ***************************************************************************** */
530
-
531
- function __values(o) {
532
- var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
533
- if (m) return m.call(o);
534
- return {
535
- next: function () {
536
- if (o && i >= o.length) o = void 0;
537
- return { value: o && o[i++], done: !o };
538
- }
539
- };
540
- }
541
-
542
- function __read(o, n) {
543
- var m = typeof Symbol === "function" && o[Symbol.iterator];
544
- if (!m) return o;
545
- var i = m.call(o), r, ar = [], e;
546
- try {
547
- while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
548
- }
549
- catch (error) { e = { error: error }; }
550
- finally {
551
- try {
552
- if (r && !r.done && (m = i["return"])) m.call(i);
553
- }
554
- finally { if (e) throw e.error; }
555
- }
556
- return ar;
557
- }
558
-
559
- function __spread() {
560
- for (var ar = [], i = 0; i < arguments.length; i++)
561
- ar = ar.concat(__read(arguments[i]));
562
- return ar;
117
+ function computedDisposeDependencyCallback(id, entryToDispose) {
118
+ if (entryToDispose !== null && entryToDispose.dispose) {
119
+ entryToDispose.dispose();
120
+ }
563
121
  }
564
-
565
- /**
566
- * Create an ES
567
- */
568
- var PROXY_SYM = Symbol('Knockout Proxied Object');
569
- var MIRROR_SYM = Symbol('Knockout Proxied Observables');
570
- function makeComputed(proxy, fn) {
571
- return computed({
572
- owner: proxy,
573
- read: fn,
574
- write: fn,
575
- pure: 'pure' in fn ? fn.pure : true,
576
- deferEvaluation: 'deferEvaluation' in fn ? fn.deferEvaluation : true
577
- }).extend({ deferred: true });
578
- }
579
- function setOrCreate(mirror, prop, value, proxy) {
580
- if (!mirror[prop]) {
581
- var ctr = Array.isArray(value) ? observableArray
582
- : typeof value === 'function' ? makeComputed.bind(null, proxy)
583
- : observable;
584
- mirror[prop] = ctr(value);
585
- }
586
- else {
587
- mirror[prop](value);
588
- }
589
- }
590
- function assignOrUpdate(mirror, object, proxy) {
591
- var e_1, _a;
592
- try {
593
- for (var _b = __values(Object.keys(object)), _c = _b.next(); !_c.done; _c = _b.next()) {
594
- var key = _c.value;
595
- setOrCreate(mirror, key, object[key], proxy);
596
- }
597
- }
598
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
599
- finally {
600
- try {
601
- if (_c && !_c.done && (_a = _b["return"])) _a.call(_b);
602
- }
603
- finally { if (e_1) throw e_1.error; }
604
- }
605
- return object;
606
- }
607
- function proxy(object) {
608
- var _a;
609
- var mirror = (_a = {}, _a[PROXY_SYM] = object, _a);
610
- mirror[MIRROR_SYM] = mirror;
611
- var proxy = new Proxy(function () { }, {
612
- has: function (target, prop) { return prop in mirror; },
613
- get: function (target, prop) { return unwrap(mirror[prop]); },
614
- set: function (target, prop, value, receiver) {
615
- setOrCreate(mirror, prop, value, proxy);
616
- object[prop] = value;
617
- return true;
618
- },
619
- deleteProperty: function (property) {
620
- delete mirror[property];
621
- return delete object[property];
622
- },
623
- apply: function (target, thisArg, _a) {
624
- var _b = __read(_a, 1), props = _b[0];
625
- if (props) {
626
- assignOrUpdate(mirror, props, proxy);
627
- return Object.assign(object, props);
628
- }
629
- return object;
630
- },
631
- getPrototypeOf: function () { return Object.getPrototypeOf(object); },
632
- setPrototypeOf: function (target, proto) { return Object.setPrototypeOf(object, proto); },
633
- defineProperty: function (target, prop, desc) { return Object.defineProperty(object, prop, desc); },
634
- preventExtensions: function () { return Object.preventExtensions(object); },
635
- isExtensible: function () { return Object.isExtensible(object); },
636
- ownKeys: function () {
637
- return __spread(Object.getOwnPropertyNames(object), Object.getOwnPropertySymbols(object));
638
- }
639
- });
640
- assignOrUpdate(mirror, object, proxy);
641
- return proxy;
642
- }
643
- function getObservable(proxied, prop) { return proxied[MIRROR_SYM][prop]; }
644
- function peek(proxied, prop) { return getObservable(proxied, prop).peek(); }
645
- function isProxied(proxied) { return PROXY_SYM in proxied; }
646
- Object.assign(proxy, { getObservable: getObservable, peek: peek, isProxied: isProxied });
647
-
648
- function kowhen(predicate, context, resolve) {
649
- var observable$$1 = pureComputed(predicate, context).extend({ notify: 'always' });
650
- var subscription = observable$$1.subscribe(function (value) {
651
- if (value) {
652
- subscription.dispose();
653
- resolve(value);
654
- }
655
- });
656
- // In case the initial value is true, process it right away
657
- observable$$1.notifySubscribers(observable$$1.peek());
658
- return subscription;
659
- }
660
- function when(predicate, callback, context) {
661
- var whenFn = kowhen.bind(null, predicate, context);
662
- return callback ? whenFn(callback.bind(context)) : new Promise(whenFn);
122
+ function computedBeginDependencyDetectionCallback(subscribable2, id) {
123
+ var computedObservable = this.computedObservable, state = computedObservable[computedState];
124
+ if (!state.isDisposed) {
125
+ if (this.disposalCount && this.disposalCandidates[id]) {
126
+ computedObservable.addDependencyTracking(id, subscribable2, this.disposalCandidates[id]);
127
+ this.disposalCandidates[id] = null;
128
+ --this.disposalCount;
129
+ } else if (!state.dependencyTracking[id]) {
130
+ computedObservable.addDependencyTracking(id, subscribable2, state.isSleeping ? { _target: subscribable2 } : computedObservable.subscribeToDependency(subscribable2));
131
+ }
132
+ if (subscribable2._notificationIsPending) {
133
+ subscribable2._notifyNextChangeIfValueIsDifferent();
134
+ }
135
+ }
136
+ }
137
+ computed.fn = {
138
+ equalityComparer: valuesArePrimitiveAndEqual,
139
+ getDependenciesCount() {
140
+ return this[computedState].dependenciesCount;
141
+ },
142
+ getDependencies() {
143
+ const dependencyTracking = this[computedState].dependencyTracking;
144
+ const dependentObservables = [];
145
+ objectForEach(dependencyTracking, function(id, dependency) {
146
+ dependentObservables[dependency._order] = dependency._target;
147
+ });
148
+ return dependentObservables;
149
+ },
150
+ addDependencyTracking(id, target, trackingObj) {
151
+ if (this[computedState].pure && target === this) {
152
+ throw Error("A 'pure' computed must not be called recursively");
153
+ }
154
+ this[computedState].dependencyTracking[id] = trackingObj;
155
+ trackingObj._order = this[computedState].dependenciesCount++;
156
+ trackingObj._version = target.getVersion();
157
+ },
158
+ haveDependenciesChanged() {
159
+ var id, dependency, dependencyTracking = this[computedState].dependencyTracking;
160
+ for (id in dependencyTracking) {
161
+ if (hasOwnProperty(dependencyTracking, id)) {
162
+ dependency = dependencyTracking[id];
163
+ if (this._evalDelayed && dependency._target._notificationIsPending || dependency._target.hasChanged(dependency._version)) {
164
+ return true;
165
+ }
166
+ }
167
+ }
168
+ },
169
+ markDirty() {
170
+ if (this._evalDelayed && !this[computedState].isBeingEvaluated) {
171
+ this._evalDelayed(false);
172
+ }
173
+ },
174
+ isActive() {
175
+ const state = this[computedState];
176
+ return state.isDirty || state.dependenciesCount > 0;
177
+ },
178
+ respondToChange() {
179
+ if (!this._notificationIsPending) {
180
+ this.evaluatePossiblyAsync();
181
+ } else if (this[computedState].isDirty) {
182
+ this[computedState].isStale = true;
183
+ }
184
+ },
185
+ subscribeToDependency(target) {
186
+ if (target._deferUpdates) {
187
+ var dirtySub = target.subscribe(this.markDirty, this, "dirty"), changeSub = target.subscribe(this.respondToChange, this);
188
+ return {
189
+ _target: target,
190
+ dispose() {
191
+ dirtySub.dispose();
192
+ changeSub.dispose();
193
+ }
194
+ };
195
+ } else {
196
+ return target.subscribe(this.evaluatePossiblyAsync, this);
197
+ }
198
+ },
199
+ evaluatePossiblyAsync() {
200
+ var computedObservable = this, throttleEvaluationTimeout = computedObservable.throttleEvaluation;
201
+ if (throttleEvaluationTimeout && throttleEvaluationTimeout >= 0) {
202
+ clearTimeout(this[computedState].evaluationTimeoutInstance);
203
+ this[computedState].evaluationTimeoutInstance = safeSetTimeout(function() {
204
+ computedObservable.evaluateImmediate(true);
205
+ }, throttleEvaluationTimeout);
206
+ } else if (computedObservable._evalDelayed) {
207
+ computedObservable._evalDelayed(true);
208
+ } else {
209
+ computedObservable.evaluateImmediate(true);
210
+ }
211
+ },
212
+ evaluateImmediate(notifyChange) {
213
+ var computedObservable = this, state = computedObservable[computedState], disposeWhen = state.disposeWhen, changed = false;
214
+ if (state.isBeingEvaluated) {
215
+ return;
216
+ }
217
+ if (state.isDisposed) {
218
+ return;
219
+ }
220
+ if (state.disposeWhenNodeIsRemoved && !domNodeIsAttachedToDocument(state.disposeWhenNodeIsRemoved) || disposeWhen && disposeWhen()) {
221
+ if (!state.suppressDisposalUntilDisposeWhenReturnsFalse) {
222
+ computedObservable.dispose();
223
+ return;
224
+ }
225
+ } else {
226
+ state.suppressDisposalUntilDisposeWhenReturnsFalse = false;
227
+ }
228
+ state.isBeingEvaluated = true;
229
+ try {
230
+ changed = this.evaluateImmediate_CallReadWithDependencyDetection(notifyChange);
231
+ } finally {
232
+ state.isBeingEvaluated = false;
233
+ }
234
+ return changed;
235
+ },
236
+ evaluateImmediate_CallReadWithDependencyDetection(notifyChange) {
237
+ var computedObservable = this, state = computedObservable[computedState], changed = false;
238
+ var isInitial = state.pure ? void 0 : !state.dependenciesCount, dependencyDetectionContext = {
239
+ computedObservable,
240
+ disposalCandidates: state.dependencyTracking,
241
+ disposalCount: state.dependenciesCount
242
+ };
243
+ dependencyDetection.begin({
244
+ callbackTarget: dependencyDetectionContext,
245
+ callback: computedBeginDependencyDetectionCallback,
246
+ computed: computedObservable,
247
+ isInitial
248
+ });
249
+ state.dependencyTracking = {};
250
+ state.dependenciesCount = 0;
251
+ var newValue = this.evaluateImmediate_CallReadThenEndDependencyDetection(state, dependencyDetectionContext);
252
+ if (!state.dependenciesCount) {
253
+ computedObservable.dispose();
254
+ changed = true;
255
+ } else {
256
+ changed = computedObservable.isDifferent(state.latestValue, newValue);
257
+ }
258
+ if (changed) {
259
+ if (!state.isSleeping) {
260
+ computedObservable.notifySubscribers(state.latestValue, "beforeChange");
261
+ } else {
262
+ computedObservable.updateVersion();
263
+ }
264
+ state.latestValue = newValue;
265
+ if (options.debug) {
266
+ computedObservable._latestValue = newValue;
267
+ }
268
+ computedObservable.notifySubscribers(state.latestValue, "spectate");
269
+ if (!state.isSleeping && notifyChange) {
270
+ computedObservable.notifySubscribers(state.latestValue);
271
+ }
272
+ if (computedObservable._recordUpdate) {
273
+ computedObservable._recordUpdate();
274
+ }
275
+ }
276
+ if (isInitial) {
277
+ computedObservable.notifySubscribers(state.latestValue, "awake");
278
+ }
279
+ return changed;
280
+ },
281
+ evaluateImmediate_CallReadThenEndDependencyDetection(state, dependencyDetectionContext) {
282
+ try {
283
+ var readFunction = state.readFunction;
284
+ return state.evaluatorFunctionTarget ? readFunction.call(state.evaluatorFunctionTarget) : readFunction();
285
+ } finally {
286
+ dependencyDetection.end();
287
+ if (dependencyDetectionContext.disposalCount && !state.isSleeping) {
288
+ objectForEach(dependencyDetectionContext.disposalCandidates, computedDisposeDependencyCallback);
289
+ }
290
+ state.isStale = state.isDirty = false;
291
+ }
292
+ },
293
+ peek(forceEvaluate) {
294
+ const state = this[computedState];
295
+ if (state.isDirty && (forceEvaluate || !state.dependenciesCount) || state.isSleeping && this.haveDependenciesChanged()) {
296
+ this.evaluateImmediate();
297
+ }
298
+ return state.latestValue;
299
+ },
300
+ get [LATEST_VALUE]() {
301
+ return this.peek();
302
+ },
303
+ limit(limitFunction) {
304
+ const state = this[computedState];
305
+ subscribable.fn.limit.call(this, limitFunction);
306
+ Object.assign(this, {
307
+ _evalIfChanged() {
308
+ if (!this[computedState].isSleeping) {
309
+ if (this[computedState].isStale) {
310
+ this.evaluateImmediate();
311
+ } else {
312
+ this[computedState].isDirty = false;
313
+ }
314
+ }
315
+ return state.latestValue;
316
+ },
317
+ _evalDelayed(isChange) {
318
+ this._limitBeforeChange(state.latestValue);
319
+ state.isDirty = true;
320
+ if (isChange) {
321
+ state.isStale = true;
322
+ }
323
+ this._limitChange(this, !isChange);
324
+ }
325
+ });
326
+ },
327
+ dispose() {
328
+ var state = this[computedState];
329
+ if (!state.isSleeping && state.dependencyTracking) {
330
+ objectForEach(state.dependencyTracking, function(id, dependency) {
331
+ if (dependency.dispose) {
332
+ dependency.dispose();
333
+ }
334
+ });
335
+ }
336
+ if (state.disposeWhenNodeIsRemoved && state.domNodeDisposalCallback) {
337
+ removeDisposeCallback(state.disposeWhenNodeIsRemoved, state.domNodeDisposalCallback);
338
+ }
339
+ Object.assign(state, DISPOSED_STATE);
340
+ }
341
+ };
342
+ var pureComputedOverrides = {
343
+ beforeSubscriptionAdd(event) {
344
+ var computedObservable = this, state = computedObservable[computedState];
345
+ if (!state.isDisposed && state.isSleeping && event === "change") {
346
+ state.isSleeping = false;
347
+ if (state.isStale || computedObservable.haveDependenciesChanged()) {
348
+ state.dependencyTracking = null;
349
+ state.dependenciesCount = 0;
350
+ if (computedObservable.evaluateImmediate()) {
351
+ computedObservable.updateVersion();
352
+ }
353
+ } else {
354
+ var dependenciesOrder = [];
355
+ objectForEach(state.dependencyTracking, function(id, dependency) {
356
+ dependenciesOrder[dependency._order] = id;
357
+ });
358
+ arrayForEach(dependenciesOrder, function(id, order) {
359
+ var dependency = state.dependencyTracking[id], subscription = computedObservable.subscribeToDependency(dependency._target);
360
+ subscription._order = order;
361
+ subscription._version = dependency._version;
362
+ state.dependencyTracking[id] = subscription;
363
+ });
364
+ if (computedObservable.haveDependenciesChanged()) {
365
+ if (computedObservable.evaluateImmediate()) {
366
+ computedObservable.updateVersion();
367
+ }
368
+ }
369
+ }
370
+ if (!state.isDisposed) {
371
+ computedObservable.notifySubscribers(state.latestValue, "awake");
372
+ }
373
+ }
374
+ },
375
+ afterSubscriptionRemove(event) {
376
+ var state = this[computedState];
377
+ if (!state.isDisposed && event === "change" && !this.hasSubscriptionsForEvent("change")) {
378
+ objectForEach(state.dependencyTracking, function(id, dependency) {
379
+ if (dependency.dispose) {
380
+ state.dependencyTracking[id] = {
381
+ _target: dependency._target,
382
+ _order: dependency._order,
383
+ _version: dependency._version
384
+ };
385
+ dependency.dispose();
386
+ }
387
+ });
388
+ state.isSleeping = true;
389
+ this.notifySubscribers(void 0, "asleep");
390
+ }
391
+ },
392
+ getVersion() {
393
+ var state = this[computedState];
394
+ if (state.isSleeping && (state.isStale || this.haveDependenciesChanged())) {
395
+ this.evaluateImmediate();
396
+ }
397
+ return subscribable.fn.getVersion.call(this);
398
+ }
399
+ };
400
+ var deferEvaluationOverrides = {
401
+ beforeSubscriptionAdd(event) {
402
+ if (event === "change" || event === "beforeChange") {
403
+ this.peek();
404
+ }
405
+ }
406
+ };
407
+ Object.setPrototypeOf(computed.fn, subscribable.fn);
408
+ var protoProp = observable.protoProperty;
409
+ computed.fn[protoProp] = computed;
410
+ observable.observablePrototypes.add(computed);
411
+ export function isComputed(instance) {
412
+ return typeof instance === "function" && instance[protoProp] === computed;
413
+ }
414
+ export function isPureComputed(instance) {
415
+ return isComputed(instance) && instance[computedState] && instance[computedState].pure;
416
+ }
417
+ export function pureComputed(evaluatorFunctionOrOptions, evaluatorFunctionTarget) {
418
+ if (typeof evaluatorFunctionOrOptions === "function") {
419
+ return computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget, { "pure": true });
420
+ } else {
421
+ evaluatorFunctionOrOptions = extend({}, evaluatorFunctionOrOptions);
422
+ evaluatorFunctionOrOptions.pure = true;
423
+ return computed(evaluatorFunctionOrOptions, evaluatorFunctionTarget);
424
+ }
663
425
  }
664
-
665
- //
666
-
667
- export { computed, isComputed, isPureComputed, pureComputed, throttleExtender, proxy, when };
668
- //# sourceMappingURL=computed.js.map