awa
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { onUnexpectedError } from './commonFacade/deps.js';
|
||||
/**
|
||||
* This function is used to indicate that the caller recovered from an error that indicates a bug.
|
||||
*/
|
||||
export function handleBugIndicatingErrorRecovery(message) {
|
||||
const err = new Error('BugIndicatingErrorRecovery: ' + message);
|
||||
onUnexpectedError(err);
|
||||
console.error('recovered from an error that indicates a bug', err);
|
||||
}
|
||||
//# sourceMappingURL=base.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,71 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { BugIndicatingError } from './commonFacade/deps.js';
|
||||
/**
|
||||
* Subscribes to and records changes and the last value of the given observables.
|
||||
* Don't use the key "changes", as it is reserved for the changes array!
|
||||
*/
|
||||
export function recordChanges(obs) {
|
||||
return {
|
||||
createChangeSummary: (_previousChangeSummary) => {
|
||||
return {
|
||||
changes: [],
|
||||
};
|
||||
},
|
||||
handleChange(ctx, changeSummary) {
|
||||
for (const key in obs) {
|
||||
if (ctx.didChange(obs[key])) {
|
||||
changeSummary.changes.push({ key, change: ctx.change });
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
beforeUpdate(reader, changeSummary) {
|
||||
for (const key in obs) {
|
||||
if (key === 'changes') {
|
||||
throw new BugIndicatingError('property name "changes" is reserved for change tracking');
|
||||
}
|
||||
changeSummary[key] = obs[key].read(reader);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Subscribes to and records changes and the last value of the given observables.
|
||||
* Don't use the key "changes", as it is reserved for the changes array!
|
||||
*/
|
||||
export function recordChangesLazy(getObs) {
|
||||
let obs = undefined;
|
||||
return {
|
||||
createChangeSummary: (_previousChangeSummary) => {
|
||||
return {
|
||||
changes: [],
|
||||
};
|
||||
},
|
||||
handleChange(ctx, changeSummary) {
|
||||
if (!obs) {
|
||||
obs = getObs();
|
||||
}
|
||||
for (const key in obs) {
|
||||
if (ctx.didChange(obs[key])) {
|
||||
changeSummary.changes.push({ key, change: ctx.change });
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
beforeUpdate(reader, changeSummary) {
|
||||
if (!obs) {
|
||||
obs = getObs();
|
||||
}
|
||||
for (const key in obs) {
|
||||
if (key === 'changes') {
|
||||
throw new BugIndicatingError('property name "changes" is reserved for change tracking');
|
||||
}
|
||||
changeSummary[key] = obs[key].read(reader);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=changeTracker.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,7 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
export { CancellationError } from '../../errors.js';
|
||||
export { CancellationToken, CancellationTokenSource, cancelOnDispose } from '../../cancellation.js';
|
||||
//# sourceMappingURL=cancellation.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/observableInternal/commonFacade/cancellation.ts","vs/base/common/observableInternal/commonFacade/cancellation.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAEhG,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC","file":"cancellation.js","sourceRoot":"file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nexport { CancellationError } from '../../errors.js';\nexport { CancellationToken, CancellationTokenSource, cancelOnDispose } from '../../cancellation.js';\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nexport { CancellationError } from '../../errors.js';\nexport { CancellationToken, CancellationTokenSource, cancelOnDispose } from '../../cancellation.js';\n"]}
|
||||
@@ -0,0 +1,10 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
export { assertFn } from '../../assert.js';
|
||||
export { strictEquals } from '../../equals.js';
|
||||
export { BugIndicatingError, onBugIndicatingError, onUnexpectedError } from '../../errors.js';
|
||||
export { Event } from '../../event.js';
|
||||
export { DisposableStore, markAsDisposed, toDisposable, trackDisposable } from '../../lifecycle.js';
|
||||
//# sourceMappingURL=deps.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/observableInternal/commonFacade/deps.ts","vs/base/common/observableInternal/commonFacade/deps.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAEhG,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAyB,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC9F,OAAO,EAAE,KAAK,EAA8B,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAoB,cAAc,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC","file":"deps.js","sourceRoot":"file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nexport { assertFn } from '../../assert.js';\nexport { type EqualityComparer, strictEquals } from '../../equals.js';\nexport { BugIndicatingError, onBugIndicatingError, onUnexpectedError } from '../../errors.js';\nexport { Event, type IValueWithChangeEvent } from '../../event.js';\nexport { DisposableStore, type IDisposable, markAsDisposed, toDisposable, trackDisposable } from '../../lifecycle.js';\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nexport { assertFn } from '../../assert.js';\nexport { type EqualityComparer, strictEquals } from '../../equals.js';\nexport { BugIndicatingError, onBugIndicatingError, onUnexpectedError } from '../../errors.js';\nexport { Event, type IValueWithChangeEvent } from '../../event.js';\nexport { DisposableStore, type IDisposable, markAsDisposed, toDisposable, trackDisposable } from '../../lifecycle.js';\n"]}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
export var DebugLocation;
|
||||
(function (DebugLocation) {
|
||||
let enabled = false;
|
||||
function enable() {
|
||||
enabled = true;
|
||||
}
|
||||
DebugLocation.enable = enable;
|
||||
function ofCaller() {
|
||||
if (!enabled) {
|
||||
return undefined;
|
||||
}
|
||||
const Err = Error; // For the monaco editor checks, which don't have the nodejs types.
|
||||
const l = Err.stackTraceLimit;
|
||||
Err.stackTraceLimit = 3;
|
||||
const stack = new Error().stack;
|
||||
Err.stackTraceLimit = l;
|
||||
return DebugLocationImpl.fromStack(stack, 2);
|
||||
}
|
||||
DebugLocation.ofCaller = ofCaller;
|
||||
})(DebugLocation || (DebugLocation = {}));
|
||||
class DebugLocationImpl {
|
||||
static fromStack(stack, parentIdx) {
|
||||
const lines = stack.split('\n');
|
||||
const location = parseLine(lines[parentIdx + 1]);
|
||||
if (location) {
|
||||
return new DebugLocationImpl(location.fileName, location.line, location.column, location.id);
|
||||
}
|
||||
else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
constructor(fileName, line, column, id) {
|
||||
this.fileName = fileName;
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
function parseLine(stackLine) {
|
||||
const match = stackLine.match(/\((.*):(\d+):(\d+)\)/);
|
||||
if (match) {
|
||||
return {
|
||||
fileName: match[1],
|
||||
line: parseInt(match[2]),
|
||||
column: parseInt(match[3]),
|
||||
id: stackLine,
|
||||
};
|
||||
}
|
||||
const match2 = stackLine.match(/at ([^\(\)]*):(\d+):(\d+)/);
|
||||
if (match2) {
|
||||
return {
|
||||
fileName: match2[1],
|
||||
line: parseInt(match2[2]),
|
||||
column: parseInt(match2[3]),
|
||||
id: stackLine,
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
//# sourceMappingURL=debugLocation.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,108 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
export class DebugNameData {
|
||||
constructor(owner, debugNameSource, referenceFn) {
|
||||
this.owner = owner;
|
||||
this.debugNameSource = debugNameSource;
|
||||
this.referenceFn = referenceFn;
|
||||
}
|
||||
getDebugName(target) {
|
||||
return getDebugName(target, this);
|
||||
}
|
||||
}
|
||||
const countPerName = new Map();
|
||||
const cachedDebugName = new WeakMap();
|
||||
export function getDebugName(target, data) {
|
||||
const cached = cachedDebugName.get(target);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
const dbgName = computeDebugName(target, data);
|
||||
if (dbgName) {
|
||||
let count = countPerName.get(dbgName) ?? 0;
|
||||
count++;
|
||||
countPerName.set(dbgName, count);
|
||||
const result = count === 1 ? dbgName : `${dbgName}#${count}`;
|
||||
cachedDebugName.set(target, result);
|
||||
return result;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
function computeDebugName(self, data) {
|
||||
const cached = cachedDebugName.get(self);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
const ownerStr = data.owner ? formatOwner(data.owner) + `.` : '';
|
||||
let result;
|
||||
const debugNameSource = data.debugNameSource;
|
||||
if (debugNameSource !== undefined) {
|
||||
if (typeof debugNameSource === 'function') {
|
||||
result = debugNameSource();
|
||||
if (result !== undefined) {
|
||||
return ownerStr + result;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return ownerStr + debugNameSource;
|
||||
}
|
||||
}
|
||||
const referenceFn = data.referenceFn;
|
||||
if (referenceFn !== undefined) {
|
||||
result = getFunctionName(referenceFn);
|
||||
if (result !== undefined) {
|
||||
return ownerStr + result;
|
||||
}
|
||||
}
|
||||
if (data.owner !== undefined) {
|
||||
const key = findKey(data.owner, self);
|
||||
if (key !== undefined) {
|
||||
return ownerStr + key;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
function findKey(obj, value) {
|
||||
for (const key in obj) {
|
||||
if (obj[key] === value) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
const countPerClassName = new Map();
|
||||
const ownerId = new WeakMap();
|
||||
function formatOwner(owner) {
|
||||
const id = ownerId.get(owner);
|
||||
if (id) {
|
||||
return id;
|
||||
}
|
||||
const className = getClassName(owner) ?? 'Object';
|
||||
let count = countPerClassName.get(className) ?? 0;
|
||||
count++;
|
||||
countPerClassName.set(className, count);
|
||||
const result = count === 1 ? className : `${className}#${count}`;
|
||||
ownerId.set(owner, result);
|
||||
return result;
|
||||
}
|
||||
export function getClassName(obj) {
|
||||
const ctor = obj.constructor;
|
||||
if (ctor) {
|
||||
if (ctor.name === 'Object') {
|
||||
return undefined;
|
||||
}
|
||||
return ctor.name;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
export function getFunctionName(fn) {
|
||||
const fnSrc = fn.toString();
|
||||
// Pattern: /** @description ... */
|
||||
const regexp = /\/\*\*\s*@description\s*([^*]*)\*\//;
|
||||
const match = regexp.exec(fnSrc);
|
||||
const result = match ? match[1] : undefined;
|
||||
return result?.trim();
|
||||
}
|
||||
//# sourceMappingURL=debugName.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,41 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { strictEquals, BugIndicatingError } from '../commonFacade/deps.js';
|
||||
import { subtransaction } from '../transaction.js';
|
||||
import { DebugNameData } from '../debugName.js';
|
||||
import { DerivedWithSetter } from '../observables/derivedImpl.js';
|
||||
import { DebugLocation } from '../debugLocation.js';
|
||||
/**
|
||||
* Creates an observable value that is based on values and changes from other observables.
|
||||
* Additionally, a reducer can report how that state changed.
|
||||
*/
|
||||
export function observableReducerSettable(owner, options) {
|
||||
let prevValue = undefined;
|
||||
let hasValue = false;
|
||||
const d = new DerivedWithSetter(new DebugNameData(owner, undefined, options.update), (reader, changeSummary) => {
|
||||
if (!hasValue) {
|
||||
prevValue = options.initial instanceof Function ? options.initial() : options.initial;
|
||||
hasValue = true;
|
||||
}
|
||||
const newValue = options.update(reader, prevValue, changeSummary);
|
||||
prevValue = newValue;
|
||||
return newValue;
|
||||
}, options.changeTracker, () => {
|
||||
if (hasValue) {
|
||||
options.disposeFinal?.(prevValue);
|
||||
hasValue = false;
|
||||
}
|
||||
}, options.equalityComparer ?? strictEquals, (value, tx, change) => {
|
||||
if (!hasValue) {
|
||||
throw new BugIndicatingError('Can only set when there is a listener! This is to prevent leaks.');
|
||||
}
|
||||
subtransaction(tx, tx => {
|
||||
prevValue = value;
|
||||
d.setValue(value, tx, change);
|
||||
});
|
||||
}, DebugLocation.ofCaller());
|
||||
return d;
|
||||
}
|
||||
//# sourceMappingURL=reducer.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,14 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { derivedObservableWithCache } from '../utils/utils.js';
|
||||
/**
|
||||
* Works like a derived.
|
||||
* However, if the value is not undefined, it is cached and will not be recomputed anymore.
|
||||
* In that case, the derived will unsubscribe from its dependencies.
|
||||
*/
|
||||
export function derivedConstOnceDefined(owner, fn) {
|
||||
return derivedObservableWithCache(owner, (reader, lastValue) => lastValue ?? fn(reader));
|
||||
}
|
||||
//# sourceMappingURL=utils.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/observableInternal/experimental/utils.ts","vs/base/common/observableInternal/experimental/utils.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAIhG,OAAO,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAE/D;;;;EAIE;AACF,MAAM,UAAU,uBAAuB,CAAI,KAAiB,EAAE,EAA0B;IACvF,OAAO,0BAA0B,CAAgB,KAAK,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,CAAC,SAAS,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;AACzG,CAAC","file":"utils.js","sourceRoot":"file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { IObservable, IReader } from '../base.js';\nimport { DebugOwner } from '../debugName.js';\nimport { derivedObservableWithCache } from '../utils/utils.js';\n\n/**\n * Works like a derived.\n * However, if the value is not undefined, it is cached and will not be recomputed anymore.\n * In that case, the derived will unsubscribe from its dependencies.\n*/\nexport function derivedConstOnceDefined<T>(owner: DebugOwner, fn: (reader: IReader) => T): IObservable<T | undefined> {\n\treturn derivedObservableWithCache<T | undefined>(owner, (reader, lastValue) => lastValue ?? fn(reader));\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { IObservable, IReader } from '../base.js';\nimport { DebugOwner } from '../debugName.js';\nimport { derivedObservableWithCache } from '../utils/utils.js';\n\n/**\n * Works like a derived.\n * However, if the value is not undefined, it is cached and will not be recomputed anymore.\n * In that case, the derived will unsubscribe from its dependencies.\n*/\nexport function derivedConstOnceDefined<T>(owner: DebugOwner, fn: (reader: IReader) => T): IObservable<T | undefined> {\n\treturn derivedObservableWithCache<T | undefined>(owner, (reader, lastValue) => lastValue ?? fn(reader));\n}\n"]}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
// This is a facade for the observable implementation. Only import from here!
|
||||
export { observableValueOpts } from './observables/observableValueOpts.js';
|
||||
export { autorun, autorunDelta, autorunHandleChanges, autorunOpts, autorunWithStore, autorunWithStoreHandleChanges } from './reactions/autorun.js';
|
||||
export { disposableObservableValue } from './observables/observableValue.js';
|
||||
export { derived, derivedDisposable, derivedHandleChanges, derivedOpts, derivedWithSetter } from './observables/derived.js';
|
||||
export { ObservablePromise, PromiseResult } from './utils/promise.js';
|
||||
export { waitForState } from './utils/utilsCancellation.js';
|
||||
export { debouncedObservable, derivedObservableWithCache, derivedObservableWithWritableCache, keepObserved, mapObservableArrayCached, recomputeInitiallyAndOnChange } from './utils/utils.js';
|
||||
export { recordChanges, recordChangesLazy } from './changeTracker.js';
|
||||
export { constObservable } from './observables/constObservable.js';
|
||||
export { observableSignal } from './observables/observableSignal.js';
|
||||
export { observableFromEventOpts } from './observables/observableFromEvent.js';
|
||||
export { observableSignalFromEvent } from './observables/observableSignalFromEvent.js';
|
||||
export { asyncTransaction, globalTransaction, subtransaction, transaction, TransactionImpl } from './transaction.js';
|
||||
export { observableFromValueWithChangeEvent, ValueWithChangeEventFromObservable } from './utils/valueWithChangeEvent.js';
|
||||
export { runOnChange, runOnChangeWithCancellationToken, runOnChangeWithStore } from './utils/runOnChange.js';
|
||||
export { derivedConstOnceDefined } from './experimental/utils.js';
|
||||
export { observableFromEvent } from './observables/observableFromEvent.js';
|
||||
export { observableValue } from './observables/observableValue.js';
|
||||
export { DebugLocation } from './debugLocation.js';
|
||||
import { addLogger, setLogObservableFn } from './logging/logging.js';
|
||||
import { ConsoleObservableLogger, logObservableToConsole } from './logging/consoleObservableLogger.js';
|
||||
import { DevToolsLogger } from './logging/debugger/devToolsLogger.js';
|
||||
import { env } from '../process.js';
|
||||
import { _setDebugGetDependencyGraph } from './observables/baseObservable.js';
|
||||
import { debugGetDependencyGraph } from './logging/debugGetDependencyGraph.js';
|
||||
_setDebugGetDependencyGraph(debugGetDependencyGraph);
|
||||
setLogObservableFn(logObservableToConsole);
|
||||
// Remove "//" in the next line to enable logging
|
||||
const enableLogging = false;
|
||||
if (enableLogging) {
|
||||
addLogger(new ConsoleObservableLogger());
|
||||
}
|
||||
if (env && env['VSCODE_DEV_DEBUG_OBSERVABLES']) {
|
||||
// To debug observables you also need the extension "ms-vscode.debug-value-editor"
|
||||
addLogger(DevToolsLogger.getInstance());
|
||||
}
|
||||
//# sourceMappingURL=index.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,332 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { addLogger } from './logging.js';
|
||||
import { getClassName } from '../debugName.js';
|
||||
import { Derived } from '../observables/derivedImpl.js';
|
||||
let consoleObservableLogger;
|
||||
export function logObservableToConsole(obs) {
|
||||
if (!consoleObservableLogger) {
|
||||
consoleObservableLogger = new ConsoleObservableLogger();
|
||||
addLogger(consoleObservableLogger);
|
||||
}
|
||||
consoleObservableLogger.addFilteredObj(obs);
|
||||
}
|
||||
export class ConsoleObservableLogger {
|
||||
constructor() {
|
||||
this.indentation = 0;
|
||||
this.changedObservablesSets = new WeakMap();
|
||||
}
|
||||
addFilteredObj(obj) {
|
||||
if (!this._filteredObjects) {
|
||||
this._filteredObjects = new Set();
|
||||
}
|
||||
this._filteredObjects.add(obj);
|
||||
}
|
||||
_isIncluded(obj) {
|
||||
return this._filteredObjects?.has(obj) ?? true;
|
||||
}
|
||||
textToConsoleArgs(text) {
|
||||
return consoleTextToArgs([
|
||||
normalText(repeat('| ', this.indentation)),
|
||||
text,
|
||||
]);
|
||||
}
|
||||
formatInfo(info) {
|
||||
if (!info.hadValue) {
|
||||
return [
|
||||
normalText(` `),
|
||||
styled(formatValue(info.newValue, 60), {
|
||||
color: 'green',
|
||||
}),
|
||||
normalText(` (initial)`),
|
||||
];
|
||||
}
|
||||
return info.didChange
|
||||
? [
|
||||
normalText(` `),
|
||||
styled(formatValue(info.oldValue, 70), {
|
||||
color: 'red',
|
||||
strikeThrough: true,
|
||||
}),
|
||||
normalText(` `),
|
||||
styled(formatValue(info.newValue, 60), {
|
||||
color: 'green',
|
||||
}),
|
||||
]
|
||||
: [normalText(` (unchanged)`)];
|
||||
}
|
||||
handleObservableCreated(observable) {
|
||||
if (observable instanceof Derived) {
|
||||
const derived = observable;
|
||||
this.changedObservablesSets.set(derived, new Set());
|
||||
const debugTrackUpdating = false;
|
||||
if (debugTrackUpdating) {
|
||||
const updating = [];
|
||||
derived.__debugUpdating = updating;
|
||||
const existingBeginUpdate = derived.beginUpdate;
|
||||
derived.beginUpdate = (obs) => {
|
||||
updating.push(obs);
|
||||
return existingBeginUpdate.apply(derived, [obs]);
|
||||
};
|
||||
const existingEndUpdate = derived.endUpdate;
|
||||
derived.endUpdate = (obs) => {
|
||||
const idx = updating.indexOf(obs);
|
||||
if (idx === -1) {
|
||||
console.error('endUpdate called without beginUpdate', derived.debugName, obs.debugName);
|
||||
}
|
||||
updating.splice(idx, 1);
|
||||
return existingEndUpdate.apply(derived, [obs]);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
handleOnListenerCountChanged(observable, newCount) {
|
||||
}
|
||||
handleObservableUpdated(observable, info) {
|
||||
if (!this._isIncluded(observable)) {
|
||||
return;
|
||||
}
|
||||
if (observable instanceof Derived) {
|
||||
this._handleDerivedRecomputed(observable, info);
|
||||
return;
|
||||
}
|
||||
console.log(...this.textToConsoleArgs([
|
||||
formatKind('observable value changed'),
|
||||
styled(observable.debugName, { color: 'BlueViolet' }),
|
||||
...this.formatInfo(info),
|
||||
]));
|
||||
}
|
||||
formatChanges(changes) {
|
||||
if (changes.size === 0) {
|
||||
return undefined;
|
||||
}
|
||||
return styled(' (changed deps: ' +
|
||||
[...changes].map((o) => o.debugName).join(', ') +
|
||||
')', { color: 'gray' });
|
||||
}
|
||||
handleDerivedDependencyChanged(derived, observable, change) {
|
||||
if (!this._isIncluded(derived)) {
|
||||
return;
|
||||
}
|
||||
this.changedObservablesSets.get(derived)?.add(observable);
|
||||
}
|
||||
_handleDerivedRecomputed(derived, info) {
|
||||
if (!this._isIncluded(derived)) {
|
||||
return;
|
||||
}
|
||||
const changedObservables = this.changedObservablesSets.get(derived);
|
||||
if (!changedObservables) {
|
||||
return;
|
||||
}
|
||||
console.log(...this.textToConsoleArgs([
|
||||
formatKind('derived recomputed'),
|
||||
styled(derived.debugName, { color: 'BlueViolet' }),
|
||||
...this.formatInfo(info),
|
||||
this.formatChanges(changedObservables),
|
||||
{ data: [{ fn: derived._debugNameData.referenceFn ?? derived._computeFn }] }
|
||||
]));
|
||||
changedObservables.clear();
|
||||
}
|
||||
handleDerivedCleared(derived) {
|
||||
if (!this._isIncluded(derived)) {
|
||||
return;
|
||||
}
|
||||
console.log(...this.textToConsoleArgs([
|
||||
formatKind('derived cleared'),
|
||||
styled(derived.debugName, { color: 'BlueViolet' }),
|
||||
]));
|
||||
}
|
||||
handleAutorunCreated(autorun) {
|
||||
if (!this._isIncluded(autorun)) {
|
||||
return;
|
||||
}
|
||||
this.changedObservablesSets.set(autorun, new Set());
|
||||
}
|
||||
handleAutorunDisposed(autorun) {
|
||||
}
|
||||
handleAutorunDependencyChanged(autorun, observable, change) {
|
||||
if (!this._isIncluded(autorun)) {
|
||||
return;
|
||||
}
|
||||
this.changedObservablesSets.get(autorun).add(observable);
|
||||
}
|
||||
handleAutorunStarted(autorun) {
|
||||
const changedObservables = this.changedObservablesSets.get(autorun);
|
||||
if (!changedObservables) {
|
||||
return;
|
||||
}
|
||||
if (this._isIncluded(autorun)) {
|
||||
console.log(...this.textToConsoleArgs([
|
||||
formatKind('autorun'),
|
||||
styled(autorun.debugName, { color: 'BlueViolet' }),
|
||||
this.formatChanges(changedObservables),
|
||||
{ data: [{ fn: autorun._debugNameData.referenceFn ?? autorun._runFn }] }
|
||||
]));
|
||||
}
|
||||
changedObservables.clear();
|
||||
this.indentation++;
|
||||
}
|
||||
handleAutorunFinished(autorun) {
|
||||
this.indentation--;
|
||||
}
|
||||
handleBeginTransaction(transaction) {
|
||||
let transactionName = transaction.getDebugName();
|
||||
if (transactionName === undefined) {
|
||||
transactionName = '';
|
||||
}
|
||||
if (this._isIncluded(transaction)) {
|
||||
console.log(...this.textToConsoleArgs([
|
||||
formatKind('transaction'),
|
||||
styled(transactionName, { color: 'BlueViolet' }),
|
||||
{ data: [{ fn: transaction._fn }] }
|
||||
]));
|
||||
}
|
||||
this.indentation++;
|
||||
}
|
||||
handleEndTransaction() {
|
||||
this.indentation--;
|
||||
}
|
||||
}
|
||||
function consoleTextToArgs(text) {
|
||||
const styles = new Array();
|
||||
const data = [];
|
||||
let firstArg = '';
|
||||
function process(t) {
|
||||
if ('length' in t) {
|
||||
for (const item of t) {
|
||||
if (item) {
|
||||
process(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ('text' in t) {
|
||||
firstArg += `%c${t.text}`;
|
||||
styles.push(t.style);
|
||||
if (t.data) {
|
||||
data.push(...t.data);
|
||||
}
|
||||
}
|
||||
else if ('data' in t) {
|
||||
data.push(...t.data);
|
||||
}
|
||||
}
|
||||
process(text);
|
||||
const result = [firstArg, ...styles];
|
||||
result.push(...data);
|
||||
return result;
|
||||
}
|
||||
function normalText(text) {
|
||||
return styled(text, { color: 'black' });
|
||||
}
|
||||
function formatKind(kind) {
|
||||
return styled(padStr(`${kind}: `, 10), { color: 'black', bold: true });
|
||||
}
|
||||
function styled(text, options = {
|
||||
color: 'black',
|
||||
}) {
|
||||
function objToCss(styleObj) {
|
||||
return Object.entries(styleObj).reduce((styleString, [propName, propValue]) => {
|
||||
return `${styleString}${propName}:${propValue};`;
|
||||
}, '');
|
||||
}
|
||||
const style = {
|
||||
color: options.color,
|
||||
};
|
||||
if (options.strikeThrough) {
|
||||
style['text-decoration'] = 'line-through';
|
||||
}
|
||||
if (options.bold) {
|
||||
style['font-weight'] = 'bold';
|
||||
}
|
||||
return {
|
||||
text,
|
||||
style: objToCss(style),
|
||||
};
|
||||
}
|
||||
export function formatValue(value, availableLen) {
|
||||
switch (typeof value) {
|
||||
case 'number':
|
||||
return '' + value;
|
||||
case 'string':
|
||||
if (value.length + 2 <= availableLen) {
|
||||
return `"${value}"`;
|
||||
}
|
||||
return `"${value.substr(0, availableLen - 7)}"+...`;
|
||||
case 'boolean':
|
||||
return value ? 'true' : 'false';
|
||||
case 'undefined':
|
||||
return 'undefined';
|
||||
case 'object':
|
||||
if (value === null) {
|
||||
return 'null';
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
return formatArray(value, availableLen);
|
||||
}
|
||||
return formatObject(value, availableLen);
|
||||
case 'symbol':
|
||||
return value.toString();
|
||||
case 'function':
|
||||
return `[[Function${value.name ? ' ' + value.name : ''}]]`;
|
||||
default:
|
||||
return '' + value;
|
||||
}
|
||||
}
|
||||
function formatArray(value, availableLen) {
|
||||
let result = '[ ';
|
||||
let first = true;
|
||||
for (const val of value) {
|
||||
if (!first) {
|
||||
result += ', ';
|
||||
}
|
||||
if (result.length - 5 > availableLen) {
|
||||
result += '...';
|
||||
break;
|
||||
}
|
||||
first = false;
|
||||
result += `${formatValue(val, availableLen - result.length)}`;
|
||||
}
|
||||
result += ' ]';
|
||||
return result;
|
||||
}
|
||||
function formatObject(value, availableLen) {
|
||||
if (typeof value.toString === 'function' && value.toString !== Object.prototype.toString) {
|
||||
const val = value.toString();
|
||||
if (val.length <= availableLen) {
|
||||
return val;
|
||||
}
|
||||
return val.substring(0, availableLen - 3) + '...';
|
||||
}
|
||||
const className = getClassName(value);
|
||||
let result = className ? className + '(' : '{ ';
|
||||
let first = true;
|
||||
for (const [key, val] of Object.entries(value)) {
|
||||
if (!first) {
|
||||
result += ', ';
|
||||
}
|
||||
if (result.length - 5 > availableLen) {
|
||||
result += '...';
|
||||
break;
|
||||
}
|
||||
first = false;
|
||||
result += `${key}: ${formatValue(val, availableLen - result.length)}`;
|
||||
}
|
||||
result += className ? ')' : ' }';
|
||||
return result;
|
||||
}
|
||||
function repeat(str, count) {
|
||||
let result = '';
|
||||
for (let i = 1; i <= count; i++) {
|
||||
result += str;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function padStr(str, length) {
|
||||
while (str.length < length) {
|
||||
str += ' ';
|
||||
}
|
||||
return str;
|
||||
}
|
||||
//# sourceMappingURL=consoleObservableLogger.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,71 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { Derived } from '../observables/derivedImpl.js';
|
||||
import { FromEventObservable } from '../observables/observableFromEvent.js';
|
||||
import { ObservableValue } from '../observables/observableValue.js';
|
||||
import { AutorunObserver } from '../reactions/autorunImpl.js';
|
||||
import { formatValue } from './consoleObservableLogger.js';
|
||||
export function debugGetDependencyGraph(obs, options) {
|
||||
const debugNamePostProcessor = options?.debugNamePostProcessor ?? ((str) => str);
|
||||
const info = Info.from(obs, debugNamePostProcessor);
|
||||
if (!info) {
|
||||
return '';
|
||||
}
|
||||
const alreadyListed = new Set();
|
||||
return formatObservableInfo(info, 0, alreadyListed).trim();
|
||||
}
|
||||
function formatObservableInfo(info, indentLevel, alreadyListed) {
|
||||
const indent = '\t\t'.repeat(indentLevel);
|
||||
const lines = [];
|
||||
const isAlreadyListed = alreadyListed.has(info.sourceObj);
|
||||
if (isAlreadyListed) {
|
||||
lines.push(`${indent}* ${info.type} ${info.name} (already listed)`);
|
||||
return lines.join('\n');
|
||||
}
|
||||
alreadyListed.add(info.sourceObj);
|
||||
lines.push(`${indent}* ${info.type} ${info.name}:`);
|
||||
lines.push(`${indent} value: ${formatValue(info.value, 50)}`);
|
||||
lines.push(`${indent} state: ${info.state}`);
|
||||
if (info.dependencies.length > 0) {
|
||||
lines.push(`${indent} dependencies:`);
|
||||
for (const dep of info.dependencies) {
|
||||
lines.push(formatObservableInfo(dep, indentLevel + 1, alreadyListed));
|
||||
}
|
||||
}
|
||||
return lines.join('\n');
|
||||
}
|
||||
class Info {
|
||||
static from(obs, debugNamePostProcessor) {
|
||||
if (obs instanceof AutorunObserver) {
|
||||
const state = obs.debugGetState();
|
||||
return new Info(obs, debugNamePostProcessor(obs.debugName), 'autorun', undefined, state.stateStr, Array.from(state.dependencies).map(dep => Info.from(dep, debugNamePostProcessor) || Info.unknown(dep)));
|
||||
}
|
||||
else if (obs instanceof Derived) {
|
||||
const state = obs.debugGetState();
|
||||
return new Info(obs, debugNamePostProcessor(obs.debugName), 'derived', state.value, state.stateStr, Array.from(state.dependencies).map(dep => Info.from(dep, debugNamePostProcessor) || Info.unknown(dep)));
|
||||
}
|
||||
else if (obs instanceof ObservableValue) {
|
||||
const state = obs.debugGetState();
|
||||
return new Info(obs, debugNamePostProcessor(obs.debugName), 'observableValue', state.value, 'upToDate', []);
|
||||
}
|
||||
else if (obs instanceof FromEventObservable) {
|
||||
const state = obs.debugGetState();
|
||||
return new Info(obs, debugNamePostProcessor(obs.debugName), 'fromEvent', state.value, state.hasValue ? 'upToDate' : 'initial', []);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
static unknown(obs) {
|
||||
return new Info(obs, '(unknown)', 'unknown', undefined, 'unknown', []);
|
||||
}
|
||||
constructor(sourceObj, name, type, value, state, dependencies) {
|
||||
this.sourceObj = sourceObj;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
this.state = state;
|
||||
this.dependencies = dependencies;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=debugGetDependencyGraph.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,64 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { SimpleTypedRpcConnection } from './rpc.js';
|
||||
export function registerDebugChannel(channelId, createClient) {
|
||||
const g = globalThis;
|
||||
let queuedNotifications = [];
|
||||
let curHost = undefined;
|
||||
const { channel, handler } = createChannelFactoryFromDebugChannel({
|
||||
sendNotification: (data) => {
|
||||
if (curHost) {
|
||||
curHost.sendNotification(data);
|
||||
}
|
||||
else {
|
||||
queuedNotifications.push(data);
|
||||
}
|
||||
},
|
||||
});
|
||||
let curClient = undefined;
|
||||
(g.$$debugValueEditor_debugChannels ?? (g.$$debugValueEditor_debugChannels = {}))[channelId] = (host) => {
|
||||
curClient = createClient();
|
||||
curHost = host;
|
||||
for (const n of queuedNotifications) {
|
||||
host.sendNotification(n);
|
||||
}
|
||||
queuedNotifications = [];
|
||||
return handler;
|
||||
};
|
||||
return SimpleTypedRpcConnection.createClient(channel, () => {
|
||||
if (!curClient) {
|
||||
throw new Error('Not supported');
|
||||
}
|
||||
return curClient;
|
||||
});
|
||||
}
|
||||
function createChannelFactoryFromDebugChannel(host) {
|
||||
let h;
|
||||
const channel = (handler) => {
|
||||
h = handler;
|
||||
return {
|
||||
sendNotification: data => {
|
||||
host.sendNotification(data);
|
||||
},
|
||||
sendRequest: data => {
|
||||
throw new Error('not supported');
|
||||
},
|
||||
};
|
||||
};
|
||||
return {
|
||||
channel: channel,
|
||||
handler: {
|
||||
handleRequest: (data) => {
|
||||
if (data.type === 'notification') {
|
||||
return h?.handleNotification(data.data);
|
||||
}
|
||||
else {
|
||||
return h?.handleRequest(data.data);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=debuggerRpc.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,440 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { AutorunObserver } from '../../reactions/autorunImpl.js';
|
||||
import { formatValue } from '../consoleObservableLogger.js';
|
||||
import { registerDebugChannel } from './debuggerRpc.js';
|
||||
import { deepAssign, deepAssignDeleteNulls, Throttler } from './utils.js';
|
||||
import { isDefined } from '../../../types.js';
|
||||
import { FromEventObservable } from '../../observables/observableFromEvent.js';
|
||||
import { BugIndicatingError, onUnexpectedError } from '../../../errors.js';
|
||||
import { Derived } from '../../observables/derivedImpl.js';
|
||||
import { ObservableValue } from '../../observables/observableValue.js';
|
||||
import { DebugLocation } from '../../debugLocation.js';
|
||||
export class DevToolsLogger {
|
||||
static { this._instance = undefined; }
|
||||
static getInstance() {
|
||||
if (DevToolsLogger._instance === undefined) {
|
||||
DevToolsLogger._instance = new DevToolsLogger();
|
||||
}
|
||||
return DevToolsLogger._instance;
|
||||
}
|
||||
getTransactionState() {
|
||||
const affected = [];
|
||||
const txs = [...this._activeTransactions];
|
||||
if (txs.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
const observerQueue = txs.flatMap(t => t.debugGetUpdatingObservers() ?? []).map(o => o.observer);
|
||||
const processedObservers = new Set();
|
||||
while (observerQueue.length > 0) {
|
||||
const observer = observerQueue.shift();
|
||||
if (processedObservers.has(observer)) {
|
||||
continue;
|
||||
}
|
||||
processedObservers.add(observer);
|
||||
const state = this._getInfo(observer, d => {
|
||||
if (!processedObservers.has(d)) {
|
||||
observerQueue.push(d);
|
||||
}
|
||||
});
|
||||
if (state) {
|
||||
affected.push(state);
|
||||
}
|
||||
}
|
||||
return { names: txs.map(t => t.getDebugName() ?? 'tx'), affected };
|
||||
}
|
||||
_getObservableInfo(observable) {
|
||||
const info = this._instanceInfos.get(observable);
|
||||
if (!info) {
|
||||
onUnexpectedError(new BugIndicatingError('No info found'));
|
||||
return undefined;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
_getAutorunInfo(autorun) {
|
||||
const info = this._instanceInfos.get(autorun);
|
||||
if (!info) {
|
||||
onUnexpectedError(new BugIndicatingError('No info found'));
|
||||
return undefined;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
_getInfo(observer, queue) {
|
||||
if (observer instanceof Derived) {
|
||||
const observersToUpdate = [...observer.debugGetObservers()];
|
||||
for (const o of observersToUpdate) {
|
||||
queue(o);
|
||||
}
|
||||
const info = this._getObservableInfo(observer);
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
const observerState = observer.debugGetState();
|
||||
const base = { name: observer.debugName, instanceId: info.instanceId, updateCount: observerState.updateCount };
|
||||
const changedDependencies = [...info.changedObservables].map(o => this._instanceInfos.get(o)?.instanceId).filter(isDefined);
|
||||
if (observerState.isComputing) {
|
||||
return { ...base, type: 'observable/derived', state: 'updating', changedDependencies, initialComputation: false };
|
||||
}
|
||||
switch (observerState.state) {
|
||||
case 0 /* DerivedState.initial */:
|
||||
return { ...base, type: 'observable/derived', state: 'noValue' };
|
||||
case 3 /* DerivedState.upToDate */:
|
||||
return { ...base, type: 'observable/derived', state: 'upToDate' };
|
||||
case 2 /* DerivedState.stale */:
|
||||
return { ...base, type: 'observable/derived', state: 'stale', changedDependencies };
|
||||
case 1 /* DerivedState.dependenciesMightHaveChanged */:
|
||||
return { ...base, type: 'observable/derived', state: 'possiblyStale' };
|
||||
}
|
||||
}
|
||||
else if (observer instanceof AutorunObserver) {
|
||||
const info = this._getAutorunInfo(observer);
|
||||
if (!info) {
|
||||
return undefined;
|
||||
}
|
||||
const base = { name: observer.debugName, instanceId: info.instanceId, updateCount: info.updateCount };
|
||||
const changedDependencies = [...info.changedObservables].map(o => this._instanceInfos.get(o).instanceId);
|
||||
if (observer.debugGetState().isRunning) {
|
||||
return { ...base, type: 'autorun', state: 'updating', changedDependencies };
|
||||
}
|
||||
switch (observer.debugGetState().state) {
|
||||
case 3 /* AutorunState.upToDate */:
|
||||
return { ...base, type: 'autorun', state: 'upToDate' };
|
||||
case 2 /* AutorunState.stale */:
|
||||
return { ...base, type: 'autorun', state: 'stale', changedDependencies };
|
||||
case 1 /* AutorunState.dependenciesMightHaveChanged */:
|
||||
return { ...base, type: 'autorun', state: 'possiblyStale' };
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
_formatObservable(obs) {
|
||||
const info = this._getObservableInfo(obs);
|
||||
if (!info) {
|
||||
return undefined;
|
||||
}
|
||||
return { name: obs.debugName, instanceId: info.instanceId };
|
||||
}
|
||||
_formatObserver(obs) {
|
||||
if (obs instanceof Derived) {
|
||||
return { name: obs.toString(), instanceId: this._getObservableInfo(obs)?.instanceId };
|
||||
}
|
||||
const autorunInfo = this._getAutorunInfo(obs);
|
||||
if (autorunInfo) {
|
||||
return { name: obs.toString(), instanceId: autorunInfo.instanceId };
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
constructor() {
|
||||
this._declarationId = 0;
|
||||
this._instanceId = 0;
|
||||
this._declarations = new Map();
|
||||
this._instanceInfos = new WeakMap();
|
||||
this._aliveInstances = new Map();
|
||||
this._activeTransactions = new Set();
|
||||
this._channel = registerDebugChannel('observableDevTools', () => {
|
||||
return {
|
||||
notifications: {
|
||||
setDeclarationIdFilter: declarationIds => {
|
||||
},
|
||||
logObservableValue: (observableId) => {
|
||||
console.log('logObservableValue', observableId);
|
||||
},
|
||||
flushUpdates: () => {
|
||||
this._flushUpdates();
|
||||
},
|
||||
resetUpdates: () => {
|
||||
this._pendingChanges = null;
|
||||
this._channel.api.notifications.handleChange(this._fullState, true);
|
||||
},
|
||||
},
|
||||
requests: {
|
||||
getDeclarations: () => {
|
||||
const result = {};
|
||||
for (const decl of this._declarations.values()) {
|
||||
result[decl.id] = decl;
|
||||
}
|
||||
return { decls: result };
|
||||
},
|
||||
getSummarizedInstances: () => {
|
||||
return null;
|
||||
},
|
||||
getObservableValueInfo: instanceId => {
|
||||
const obs = this._aliveInstances.get(instanceId);
|
||||
return {
|
||||
observers: [...obs.debugGetObservers()].map(d => this._formatObserver(d)).filter(isDefined),
|
||||
};
|
||||
},
|
||||
getDerivedInfo: instanceId => {
|
||||
const d = this._aliveInstances.get(instanceId);
|
||||
return {
|
||||
dependencies: [...d.debugGetState().dependencies].map(d => this._formatObservable(d)).filter(isDefined),
|
||||
observers: [...d.debugGetObservers()].map(d => this._formatObserver(d)).filter(isDefined),
|
||||
};
|
||||
},
|
||||
getAutorunInfo: instanceId => {
|
||||
const obs = this._aliveInstances.get(instanceId);
|
||||
return {
|
||||
dependencies: [...obs.debugGetState().dependencies].map(d => this._formatObservable(d)).filter(isDefined),
|
||||
};
|
||||
},
|
||||
getTransactionState: () => {
|
||||
return this.getTransactionState();
|
||||
},
|
||||
setValue: (instanceId, jsonValue) => {
|
||||
const obs = this._aliveInstances.get(instanceId);
|
||||
if (obs instanceof Derived) {
|
||||
obs.debugSetValue(jsonValue);
|
||||
}
|
||||
else if (obs instanceof ObservableValue) {
|
||||
obs.debugSetValue(jsonValue);
|
||||
}
|
||||
else if (obs instanceof FromEventObservable) {
|
||||
obs.debugSetValue(jsonValue);
|
||||
}
|
||||
else {
|
||||
throw new BugIndicatingError('Observable is not supported');
|
||||
}
|
||||
const observers = [...obs.debugGetObservers()];
|
||||
for (const d of observers) {
|
||||
d.beginUpdate(obs);
|
||||
}
|
||||
for (const d of observers) {
|
||||
d.handleChange(obs, undefined);
|
||||
}
|
||||
for (const d of observers) {
|
||||
d.endUpdate(obs);
|
||||
}
|
||||
},
|
||||
getValue: instanceId => {
|
||||
const obs = this._aliveInstances.get(instanceId);
|
||||
if (obs instanceof Derived) {
|
||||
return formatValue(obs.debugGetState().value, 200);
|
||||
}
|
||||
else if (obs instanceof ObservableValue) {
|
||||
return formatValue(obs.debugGetState().value, 200);
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
logValue: (instanceId) => {
|
||||
const obs = this._aliveInstances.get(instanceId);
|
||||
if (obs && 'get' in obs) {
|
||||
console.log('Logged Value:', obs.get());
|
||||
}
|
||||
else {
|
||||
throw new BugIndicatingError('Observable is not supported');
|
||||
}
|
||||
},
|
||||
rerun: (instanceId) => {
|
||||
const obs = this._aliveInstances.get(instanceId);
|
||||
if (obs instanceof Derived) {
|
||||
obs.debugRecompute();
|
||||
}
|
||||
else if (obs instanceof AutorunObserver) {
|
||||
obs.debugRerun();
|
||||
}
|
||||
else {
|
||||
throw new BugIndicatingError('Observable is not supported');
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
});
|
||||
this._pendingChanges = null;
|
||||
this._changeThrottler = new Throttler();
|
||||
this._fullState = {};
|
||||
this._flushUpdates = () => {
|
||||
if (this._pendingChanges !== null) {
|
||||
this._channel.api.notifications.handleChange(this._pendingChanges, false);
|
||||
this._pendingChanges = null;
|
||||
}
|
||||
};
|
||||
DebugLocation.enable();
|
||||
}
|
||||
_handleChange(update) {
|
||||
deepAssignDeleteNulls(this._fullState, update);
|
||||
if (this._pendingChanges === null) {
|
||||
this._pendingChanges = update;
|
||||
}
|
||||
else {
|
||||
deepAssign(this._pendingChanges, update);
|
||||
}
|
||||
this._changeThrottler.throttle(this._flushUpdates, 10);
|
||||
}
|
||||
_getDeclarationId(type, location) {
|
||||
if (!location) {
|
||||
return -1;
|
||||
}
|
||||
let decInfo = this._declarations.get(location.id);
|
||||
if (decInfo === undefined) {
|
||||
decInfo = {
|
||||
id: this._declarationId++,
|
||||
type,
|
||||
url: location.fileName,
|
||||
line: location.line,
|
||||
column: location.column,
|
||||
};
|
||||
this._declarations.set(location.id, decInfo);
|
||||
this._handleChange({ decls: { [decInfo.id]: decInfo } });
|
||||
}
|
||||
return decInfo.id;
|
||||
}
|
||||
handleObservableCreated(observable, location) {
|
||||
const declarationId = this._getDeclarationId('observable/value', location);
|
||||
const info = {
|
||||
declarationId,
|
||||
instanceId: this._instanceId++,
|
||||
listenerCount: 0,
|
||||
lastValue: undefined,
|
||||
updateCount: 0,
|
||||
changedObservables: new Set(),
|
||||
};
|
||||
this._instanceInfos.set(observable, info);
|
||||
}
|
||||
handleOnListenerCountChanged(observable, newCount) {
|
||||
const info = this._getObservableInfo(observable);
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
if (info.listenerCount === 0 && newCount > 0) {
|
||||
const type = observable instanceof Derived ? 'observable/derived' : 'observable/value';
|
||||
this._aliveInstances.set(info.instanceId, observable);
|
||||
this._handleChange({
|
||||
instances: {
|
||||
[info.instanceId]: {
|
||||
instanceId: info.instanceId,
|
||||
declarationId: info.declarationId,
|
||||
formattedValue: info.lastValue,
|
||||
type,
|
||||
name: observable.debugName,
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (info.listenerCount > 0 && newCount === 0) {
|
||||
this._handleChange({
|
||||
instances: { [info.instanceId]: null }
|
||||
});
|
||||
this._aliveInstances.delete(info.instanceId);
|
||||
}
|
||||
info.listenerCount = newCount;
|
||||
}
|
||||
handleObservableUpdated(observable, changeInfo) {
|
||||
if (observable instanceof Derived) {
|
||||
this._handleDerivedRecomputed(observable, changeInfo);
|
||||
return;
|
||||
}
|
||||
const info = this._getObservableInfo(observable);
|
||||
if (info) {
|
||||
if (changeInfo.didChange) {
|
||||
info.lastValue = formatValue(changeInfo.newValue, 30);
|
||||
if (info.listenerCount > 0) {
|
||||
this._handleChange({
|
||||
instances: { [info.instanceId]: { formattedValue: info.lastValue } }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
handleAutorunCreated(autorun, location) {
|
||||
const declarationId = this._getDeclarationId('autorun', location);
|
||||
const info = {
|
||||
declarationId,
|
||||
instanceId: this._instanceId++,
|
||||
updateCount: 0,
|
||||
changedObservables: new Set(),
|
||||
};
|
||||
this._instanceInfos.set(autorun, info);
|
||||
this._aliveInstances.set(info.instanceId, autorun);
|
||||
if (info) {
|
||||
this._handleChange({
|
||||
instances: {
|
||||
[info.instanceId]: {
|
||||
instanceId: info.instanceId,
|
||||
declarationId: info.declarationId,
|
||||
runCount: 0,
|
||||
type: 'autorun',
|
||||
name: autorun.debugName,
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
handleAutorunDisposed(autorun) {
|
||||
const info = this._getAutorunInfo(autorun);
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
this._handleChange({
|
||||
instances: { [info.instanceId]: null }
|
||||
});
|
||||
this._instanceInfos.delete(autorun);
|
||||
this._aliveInstances.delete(info.instanceId);
|
||||
}
|
||||
handleAutorunDependencyChanged(autorun, observable, change) {
|
||||
const info = this._getAutorunInfo(autorun);
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
info.changedObservables.add(observable);
|
||||
}
|
||||
handleAutorunStarted(autorun) {
|
||||
}
|
||||
handleAutorunFinished(autorun) {
|
||||
const info = this._getAutorunInfo(autorun);
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
info.changedObservables.clear();
|
||||
info.updateCount++;
|
||||
this._handleChange({
|
||||
instances: { [info.instanceId]: { runCount: info.updateCount } }
|
||||
});
|
||||
}
|
||||
handleDerivedDependencyChanged(derived, observable, change) {
|
||||
const info = this._getObservableInfo(derived);
|
||||
if (info) {
|
||||
info.changedObservables.add(observable);
|
||||
}
|
||||
}
|
||||
_handleDerivedRecomputed(observable, changeInfo) {
|
||||
const info = this._getObservableInfo(observable);
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
const formattedValue = formatValue(changeInfo.newValue, 30);
|
||||
info.updateCount++;
|
||||
info.changedObservables.clear();
|
||||
info.lastValue = formattedValue;
|
||||
if (info.listenerCount > 0) {
|
||||
this._handleChange({
|
||||
instances: { [info.instanceId]: { formattedValue: formattedValue, recomputationCount: info.updateCount } }
|
||||
});
|
||||
}
|
||||
}
|
||||
handleDerivedCleared(observable) {
|
||||
const info = this._getObservableInfo(observable);
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
info.lastValue = undefined;
|
||||
info.changedObservables.clear();
|
||||
if (info.listenerCount > 0) {
|
||||
this._handleChange({
|
||||
instances: {
|
||||
[info.instanceId]: {
|
||||
formattedValue: undefined,
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
handleBeginTransaction(transaction) {
|
||||
this._activeTransactions.add(transaction);
|
||||
}
|
||||
handleEndTransaction(transaction) {
|
||||
this._activeTransactions.delete(transaction);
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=devToolsLogger.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,55 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
export class SimpleTypedRpcConnection {
|
||||
static createClient(channelFactory, getHandler) {
|
||||
return new SimpleTypedRpcConnection(channelFactory, getHandler);
|
||||
}
|
||||
constructor(_channelFactory, _getHandler) {
|
||||
this._channelFactory = _channelFactory;
|
||||
this._getHandler = _getHandler;
|
||||
this._channel = this._channelFactory({
|
||||
handleNotification: (notificationData) => {
|
||||
const m = notificationData;
|
||||
const fn = this._getHandler().notifications[m[0]];
|
||||
if (!fn) {
|
||||
throw new Error(`Unknown notification "${m[0]}"!`);
|
||||
}
|
||||
fn(...m[1]);
|
||||
},
|
||||
handleRequest: (requestData) => {
|
||||
const m = requestData;
|
||||
try {
|
||||
const result = this._getHandler().requests[m[0]](...m[1]);
|
||||
return { type: 'result', value: result };
|
||||
}
|
||||
catch (e) {
|
||||
return { type: 'error', value: e };
|
||||
}
|
||||
},
|
||||
});
|
||||
const requests = new Proxy({}, {
|
||||
get: (target, key) => {
|
||||
return async (...args) => {
|
||||
const result = await this._channel.sendRequest([key, args]);
|
||||
if (result.type === 'error') {
|
||||
throw result.value;
|
||||
}
|
||||
else {
|
||||
return result.value;
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
const notifications = new Proxy({}, {
|
||||
get: (target, key) => {
|
||||
return (...args) => {
|
||||
this._channel.sendNotification([key, args]);
|
||||
};
|
||||
}
|
||||
});
|
||||
this.api = { notifications: notifications, requests: requests };
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=rpc.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,46 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
export class Throttler {
|
||||
constructor() {
|
||||
this._timeout = undefined;
|
||||
}
|
||||
throttle(fn, timeoutMs) {
|
||||
if (this._timeout === undefined) {
|
||||
this._timeout = setTimeout(() => {
|
||||
this._timeout = undefined;
|
||||
fn();
|
||||
}, timeoutMs);
|
||||
}
|
||||
}
|
||||
dispose() {
|
||||
if (this._timeout !== undefined) {
|
||||
clearTimeout(this._timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
export function deepAssign(target, source) {
|
||||
for (const key in source) {
|
||||
if (!!target[key] && typeof target[key] === 'object' && !!source[key] && typeof source[key] === 'object') {
|
||||
deepAssign(target[key], source[key]);
|
||||
}
|
||||
else {
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
export function deepAssignDeleteNulls(target, source) {
|
||||
for (const key in source) {
|
||||
if (source[key] === null) {
|
||||
delete target[key];
|
||||
}
|
||||
else if (!!target[key] && typeof target[key] === 'object' && !!source[key] && typeof source[key] === 'object') {
|
||||
deepAssignDeleteNulls(target[key], source[key]);
|
||||
}
|
||||
else {
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=utils.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/observableInternal/logging/debugger/utils.ts","vs/base/common/observableInternal/logging/debugger/utils.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAIhG,MAAM,OAAO,SAAS;IAAtB;QACS,aAAQ,GAAwB,SAAS,CAAC;IAgBnD,CAAC;IAdO,QAAQ,CAAC,EAAc,EAAE,SAAiB;QAChD,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YACjC,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC/B,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;gBAC1B,EAAE,EAAE,CAAC;YACN,CAAC,EAAE,SAAS,CAAC,CAAC;QACf,CAAC;IACF,CAAC;IAED,OAAO;QACN,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YACjC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7B,CAAC;IACF,CAAC;CACD;AAED,MAAM,UAAU,UAAU,CAAI,MAAS,EAAE,MAAS;IACjD,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QAC1B,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC1G,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACtC,CAAC;aAAM,CAAC;YACP,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;IACF,CAAC;AACF,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAI,MAAS,EAAE,MAAS;IAC5D,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QAC1B,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;YAC1B,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;QACpB,CAAC;aAAM,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,QAAQ,EAAE,CAAC;YACjH,qBAAqB,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACjD,CAAC;aAAM,CAAC;YACP,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;IACF,CAAC;AACF,CAAC","file":"utils.js","sourceRoot":"file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { IDisposable } from '../../../lifecycle.js';\n\nexport class Throttler implements IDisposable {\n\tprivate _timeout: Timeout | undefined = undefined;\n\n\tpublic throttle(fn: () => void, timeoutMs: number): void {\n\t\tif (this._timeout === undefined) {\n\t\t\tthis._timeout = setTimeout(() => {\n\t\t\t\tthis._timeout = undefined;\n\t\t\t\tfn();\n\t\t\t}, timeoutMs);\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tif (this._timeout !== undefined) {\n\t\t\tclearTimeout(this._timeout);\n\t\t}\n\t}\n}\n\nexport function deepAssign<T>(target: T, source: T): void {\n\tfor (const key in source) {\n\t\tif (!!target[key] && typeof target[key] === 'object' && !!source[key] && typeof source[key] === 'object') {\n\t\t\tdeepAssign(target[key], source[key]);\n\t\t} else {\n\t\t\ttarget[key] = source[key];\n\t\t}\n\t}\n}\n\nexport function deepAssignDeleteNulls<T>(target: T, source: T): void {\n\tfor (const key in source) {\n\t\tif (source[key] === null) {\n\t\t\tdelete target[key];\n\t\t} else if (!!target[key] && typeof target[key] === 'object' && !!source[key] && typeof source[key] === 'object') {\n\t\t\tdeepAssignDeleteNulls(target[key], source[key]);\n\t\t} else {\n\t\t\ttarget[key] = source[key];\n\t\t}\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { IDisposable } from '../../../lifecycle.js';\n\nexport class Throttler implements IDisposable {\n\tprivate _timeout: Timeout | undefined = undefined;\n\n\tpublic throttle(fn: () => void, timeoutMs: number): void {\n\t\tif (this._timeout === undefined) {\n\t\t\tthis._timeout = setTimeout(() => {\n\t\t\t\tthis._timeout = undefined;\n\t\t\t\tfn();\n\t\t\t}, timeoutMs);\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tif (this._timeout !== undefined) {\n\t\t\tclearTimeout(this._timeout);\n\t\t}\n\t}\n}\n\nexport function deepAssign<T>(target: T, source: T): void {\n\tfor (const key in source) {\n\t\tif (!!target[key] && typeof target[key] === 'object' && !!source[key] && typeof source[key] === 'object') {\n\t\t\tdeepAssign(target[key], source[key]);\n\t\t} else {\n\t\t\ttarget[key] = source[key];\n\t\t}\n\t}\n}\n\nexport function deepAssignDeleteNulls<T>(target: T, source: T): void {\n\tfor (const key in source) {\n\t\tif (source[key] === null) {\n\t\t\tdelete target[key];\n\t\t} else if (!!target[key] && typeof target[key] === 'object' && !!source[key] && typeof source[key] === 'object') {\n\t\t\tdeepAssignDeleteNulls(target[key], source[key]);\n\t\t} else {\n\t\t\ttarget[key] = source[key];\n\t\t}\n\t}\n}\n"]}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
let globalObservableLogger;
|
||||
export function addLogger(logger) {
|
||||
if (!globalObservableLogger) {
|
||||
globalObservableLogger = logger;
|
||||
}
|
||||
else if (globalObservableLogger instanceof ComposedLogger) {
|
||||
globalObservableLogger.loggers.push(logger);
|
||||
}
|
||||
else {
|
||||
globalObservableLogger = new ComposedLogger([globalObservableLogger, logger]);
|
||||
}
|
||||
}
|
||||
export function getLogger() {
|
||||
return globalObservableLogger;
|
||||
}
|
||||
let globalObservableLoggerFn = undefined;
|
||||
export function setLogObservableFn(fn) {
|
||||
globalObservableLoggerFn = fn;
|
||||
}
|
||||
class ComposedLogger {
|
||||
constructor(loggers) {
|
||||
this.loggers = loggers;
|
||||
}
|
||||
handleObservableCreated(observable, location) {
|
||||
for (const logger of this.loggers) {
|
||||
logger.handleObservableCreated(observable, location);
|
||||
}
|
||||
}
|
||||
handleOnListenerCountChanged(observable, newCount) {
|
||||
for (const logger of this.loggers) {
|
||||
logger.handleOnListenerCountChanged(observable, newCount);
|
||||
}
|
||||
}
|
||||
handleObservableUpdated(observable, info) {
|
||||
for (const logger of this.loggers) {
|
||||
logger.handleObservableUpdated(observable, info);
|
||||
}
|
||||
}
|
||||
handleAutorunCreated(autorun, location) {
|
||||
for (const logger of this.loggers) {
|
||||
logger.handleAutorunCreated(autorun, location);
|
||||
}
|
||||
}
|
||||
handleAutorunDisposed(autorun) {
|
||||
for (const logger of this.loggers) {
|
||||
logger.handleAutorunDisposed(autorun);
|
||||
}
|
||||
}
|
||||
handleAutorunDependencyChanged(autorun, observable, change) {
|
||||
for (const logger of this.loggers) {
|
||||
logger.handleAutorunDependencyChanged(autorun, observable, change);
|
||||
}
|
||||
}
|
||||
handleAutorunStarted(autorun) {
|
||||
for (const logger of this.loggers) {
|
||||
logger.handleAutorunStarted(autorun);
|
||||
}
|
||||
}
|
||||
handleAutorunFinished(autorun) {
|
||||
for (const logger of this.loggers) {
|
||||
logger.handleAutorunFinished(autorun);
|
||||
}
|
||||
}
|
||||
handleDerivedDependencyChanged(derived, observable, change) {
|
||||
for (const logger of this.loggers) {
|
||||
logger.handleDerivedDependencyChanged(derived, observable, change);
|
||||
}
|
||||
}
|
||||
handleDerivedCleared(observable) {
|
||||
for (const logger of this.loggers) {
|
||||
logger.handleDerivedCleared(observable);
|
||||
}
|
||||
}
|
||||
handleBeginTransaction(transaction) {
|
||||
for (const logger of this.loggers) {
|
||||
logger.handleBeginTransaction(transaction);
|
||||
}
|
||||
}
|
||||
handleEndTransaction(transaction) {
|
||||
for (const logger of this.loggers) {
|
||||
logger.handleEndTransaction(transaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=logging.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,112 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { DebugLocation } from '../debugLocation.js';
|
||||
import { getFunctionName } from '../debugName.js';
|
||||
import { getLogger } from '../logging/logging.js';
|
||||
let _derived;
|
||||
/**
|
||||
* @internal
|
||||
* This is to allow splitting files.
|
||||
*/
|
||||
export function _setDerivedOpts(derived) {
|
||||
_derived = derived;
|
||||
}
|
||||
let _recomputeInitiallyAndOnChange;
|
||||
export function _setRecomputeInitiallyAndOnChange(recomputeInitiallyAndOnChange) {
|
||||
_recomputeInitiallyAndOnChange = recomputeInitiallyAndOnChange;
|
||||
}
|
||||
let _keepObserved;
|
||||
export function _setKeepObserved(keepObserved) {
|
||||
_keepObserved = keepObserved;
|
||||
}
|
||||
let _debugGetDependencyGraph;
|
||||
export function _setDebugGetDependencyGraph(debugGetDependencyGraph) {
|
||||
_debugGetDependencyGraph = debugGetDependencyGraph;
|
||||
}
|
||||
export class ConvenientObservable {
|
||||
get TChange() { return null; }
|
||||
reportChanges() {
|
||||
this.get();
|
||||
}
|
||||
/** @sealed */
|
||||
read(reader) {
|
||||
if (reader) {
|
||||
return reader.readObservable(this);
|
||||
}
|
||||
else {
|
||||
return this.get();
|
||||
}
|
||||
}
|
||||
map(fnOrOwner, fnOrUndefined, debugLocation = DebugLocation.ofCaller()) {
|
||||
const owner = fnOrUndefined === undefined ? undefined : fnOrOwner;
|
||||
const fn = fnOrUndefined === undefined ? fnOrOwner : fnOrUndefined;
|
||||
return _derived({
|
||||
owner,
|
||||
debugName: () => {
|
||||
const name = getFunctionName(fn);
|
||||
if (name !== undefined) {
|
||||
return name;
|
||||
}
|
||||
// regexp to match `x => x.y` or `x => x?.y` where x and y can be arbitrary identifiers (uses backref):
|
||||
const regexp = /^\s*\(?\s*([a-zA-Z_$][a-zA-Z_$0-9]*)\s*\)?\s*=>\s*\1(?:\??)\.([a-zA-Z_$][a-zA-Z_$0-9]*)\s*$/;
|
||||
const match = regexp.exec(fn.toString());
|
||||
if (match) {
|
||||
return `${this.debugName}.${match[2]}`;
|
||||
}
|
||||
if (!owner) {
|
||||
return `${this.debugName} (mapped)`;
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
debugReferenceFn: fn,
|
||||
}, (reader) => fn(this.read(reader), reader), debugLocation);
|
||||
}
|
||||
/**
|
||||
* @sealed
|
||||
* Converts an observable of an observable value into a direct observable of the value.
|
||||
*/
|
||||
flatten() {
|
||||
return _derived({
|
||||
owner: undefined,
|
||||
debugName: () => `${this.debugName} (flattened)`,
|
||||
}, (reader) => this.read(reader).read(reader));
|
||||
}
|
||||
recomputeInitiallyAndOnChange(store, handleValue) {
|
||||
store.add(_recomputeInitiallyAndOnChange(this, handleValue));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
export class BaseObservable extends ConvenientObservable {
|
||||
constructor(debugLocation) {
|
||||
super();
|
||||
this._observers = new Set();
|
||||
getLogger()?.handleObservableCreated(this, debugLocation);
|
||||
}
|
||||
addObserver(observer) {
|
||||
const len = this._observers.size;
|
||||
this._observers.add(observer);
|
||||
if (len === 0) {
|
||||
this.onFirstObserverAdded();
|
||||
}
|
||||
if (len !== this._observers.size) {
|
||||
getLogger()?.handleOnListenerCountChanged(this, this._observers.size);
|
||||
}
|
||||
}
|
||||
removeObserver(observer) {
|
||||
const deleted = this._observers.delete(observer);
|
||||
if (deleted && this._observers.size === 0) {
|
||||
this.onLastObserverRemoved();
|
||||
}
|
||||
if (deleted) {
|
||||
getLogger()?.handleOnListenerCountChanged(this, this._observers.size);
|
||||
}
|
||||
}
|
||||
onFirstObserverAdded() { }
|
||||
onLastObserverRemoved() { }
|
||||
debugGetObservers() {
|
||||
return this._observers;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=baseObservable.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,33 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { ConvenientObservable } from './baseObservable.js';
|
||||
/**
|
||||
* Represents an efficient observable whose value never changes.
|
||||
*/
|
||||
export function constObservable(value) {
|
||||
return new ConstObservable(value);
|
||||
}
|
||||
class ConstObservable extends ConvenientObservable {
|
||||
constructor(value) {
|
||||
super();
|
||||
this.value = value;
|
||||
}
|
||||
get debugName() {
|
||||
return this.toString();
|
||||
}
|
||||
get() {
|
||||
return this.value;
|
||||
}
|
||||
addObserver(observer) {
|
||||
// NO OP
|
||||
}
|
||||
removeObserver(observer) {
|
||||
// NO OP
|
||||
}
|
||||
toString() {
|
||||
return `Const: ${this.value}`;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=constObservable.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/observableInternal/observables/constObservable.ts","vs/base/common/observableInternal/observables/constObservable.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAGhG,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAE3D;;GAEG;AAEH,MAAM,UAAU,eAAe,CAAI,KAAQ;IAC1C,OAAO,IAAI,eAAe,CAAC,KAAK,CAAC,CAAC;AACnC,CAAC;AACD,MAAM,eAAmB,SAAQ,oBAA6B;IAC7D,YAA6B,KAAQ;QACpC,KAAK,EAAE,CAAC;QADoB,UAAK,GAAL,KAAK,CAAG;IAErC,CAAC;IAED,IAAoB,SAAS;QAC5B,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC;IACxB,CAAC;IAEM,GAAG;QACT,OAAO,IAAI,CAAC,KAAK,CAAC;IACnB,CAAC;IACM,WAAW,CAAC,QAAmB;QACrC,QAAQ;IACT,CAAC;IACM,cAAc,CAAC,QAAmB;QACxC,QAAQ;IACT,CAAC;IAEQ,QAAQ;QAChB,OAAO,UAAU,IAAI,CAAC,KAAK,EAAE,CAAC;IAC/B,CAAC;CACD","file":"constObservable.js","sourceRoot":"file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { IObservable, IObserver } from '../base.js';\nimport { ConvenientObservable } from './baseObservable.js';\n\n/**\n * Represents an efficient observable whose value never changes.\n */\n\nexport function constObservable<T>(value: T): IObservable<T> {\n\treturn new ConstObservable(value);\n}\nclass ConstObservable<T> extends ConvenientObservable<T, void> {\n\tconstructor(private readonly value: T) {\n\t\tsuper();\n\t}\n\n\tpublic override get debugName(): string {\n\t\treturn this.toString();\n\t}\n\n\tpublic get(): T {\n\t\treturn this.value;\n\t}\n\tpublic addObserver(observer: IObserver): void {\n\t\t// NO OP\n\t}\n\tpublic removeObserver(observer: IObserver): void {\n\t\t// NO OP\n\t}\n\n\toverride toString(): string {\n\t\treturn `Const: ${this.value}`;\n\t}\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { IObservable, IObserver } from '../base.js';\nimport { ConvenientObservable } from './baseObservable.js';\n\n/**\n * Represents an efficient observable whose value never changes.\n */\n\nexport function constObservable<T>(value: T): IObservable<T> {\n\treturn new ConstObservable(value);\n}\nclass ConstObservable<T> extends ConvenientObservable<T, void> {\n\tconstructor(private readonly value: T) {\n\t\tsuper();\n\t}\n\n\tpublic override get debugName(): string {\n\t\treturn this.toString();\n\t}\n\n\tpublic get(): T {\n\t\treturn this.value;\n\t}\n\tpublic addObserver(observer: IObserver): void {\n\t\t// NO OP\n\t}\n\tpublic removeObserver(observer: IObserver): void {\n\t\t// NO OP\n\t}\n\n\toverride toString(): string {\n\t\treturn `Const: ${this.value}`;\n\t}\n}\n"]}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { DisposableStore, strictEquals } from '../commonFacade/deps.js';
|
||||
import { DebugLocation } from '../debugLocation.js';
|
||||
import { DebugNameData } from '../debugName.js';
|
||||
import { _setDerivedOpts } from './baseObservable.js';
|
||||
import { Derived, DerivedWithSetter } from './derivedImpl.js';
|
||||
export function derived(computeFnOrOwner, computeFn, debugLocation = DebugLocation.ofCaller()) {
|
||||
if (computeFn !== undefined) {
|
||||
return new Derived(new DebugNameData(computeFnOrOwner, undefined, computeFn), computeFn, undefined, undefined, strictEquals, debugLocation);
|
||||
}
|
||||
return new Derived(new DebugNameData(undefined, undefined, computeFnOrOwner), computeFnOrOwner, undefined, undefined, strictEquals, debugLocation);
|
||||
}
|
||||
export function derivedWithSetter(owner, computeFn, setter, debugLocation = DebugLocation.ofCaller()) {
|
||||
return new DerivedWithSetter(new DebugNameData(owner, undefined, computeFn), computeFn, undefined, undefined, strictEquals, setter, debugLocation);
|
||||
}
|
||||
export function derivedOpts(options, computeFn, debugLocation = DebugLocation.ofCaller()) {
|
||||
return new Derived(new DebugNameData(options.owner, options.debugName, options.debugReferenceFn), computeFn, undefined, options.onLastObserverRemoved, options.equalsFn ?? strictEquals, debugLocation);
|
||||
}
|
||||
_setDerivedOpts(derivedOpts);
|
||||
/**
|
||||
* Represents an observable that is derived from other observables.
|
||||
* The value is only recomputed when absolutely needed.
|
||||
*
|
||||
* {@link computeFn} should start with a JS Doc using `@description` to name the derived.
|
||||
*
|
||||
* Use `createEmptyChangeSummary` to create a "change summary" that can collect the changes.
|
||||
* Use `handleChange` to add a reported change to the change summary.
|
||||
* The compute function is given the last change summary.
|
||||
* The change summary is discarded after the compute function was called.
|
||||
*
|
||||
* @see derived
|
||||
*/
|
||||
export function derivedHandleChanges(options, computeFn, debugLocation = DebugLocation.ofCaller()) {
|
||||
return new Derived(new DebugNameData(options.owner, options.debugName, undefined), computeFn, options.changeTracker, undefined, options.equalityComparer ?? strictEquals, debugLocation);
|
||||
}
|
||||
export function derivedDisposable(computeFnOrOwner, computeFnOrUndefined, debugLocation = DebugLocation.ofCaller()) {
|
||||
let computeFn;
|
||||
let owner;
|
||||
if (computeFnOrUndefined === undefined) {
|
||||
computeFn = computeFnOrOwner;
|
||||
owner = undefined;
|
||||
}
|
||||
else {
|
||||
owner = computeFnOrOwner;
|
||||
computeFn = computeFnOrUndefined;
|
||||
}
|
||||
let store = undefined;
|
||||
return new Derived(new DebugNameData(owner, undefined, computeFn), r => {
|
||||
if (!store) {
|
||||
store = new DisposableStore();
|
||||
}
|
||||
else {
|
||||
store.clear();
|
||||
}
|
||||
const result = computeFn(r);
|
||||
if (result) {
|
||||
store.add(result);
|
||||
}
|
||||
return result;
|
||||
}, undefined, () => {
|
||||
if (store) {
|
||||
store.dispose();
|
||||
store = undefined;
|
||||
}
|
||||
}, strictEquals, debugLocation);
|
||||
}
|
||||
//# sourceMappingURL=derived.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,348 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { BaseObservable } from './baseObservable.js';
|
||||
import { BugIndicatingError, DisposableStore, assertFn, onBugIndicatingError } from '../commonFacade/deps.js';
|
||||
import { getLogger } from '../logging/logging.js';
|
||||
function derivedStateToString(state) {
|
||||
switch (state) {
|
||||
case 0 /* DerivedState.initial */: return 'initial';
|
||||
case 1 /* DerivedState.dependenciesMightHaveChanged */: return 'dependenciesMightHaveChanged';
|
||||
case 2 /* DerivedState.stale */: return 'stale';
|
||||
case 3 /* DerivedState.upToDate */: return 'upToDate';
|
||||
default: return '<unknown>';
|
||||
}
|
||||
}
|
||||
export class Derived extends BaseObservable {
|
||||
get debugName() {
|
||||
return this._debugNameData.getDebugName(this) ?? '(anonymous)';
|
||||
}
|
||||
constructor(_debugNameData, _computeFn, _changeTracker, _handleLastObserverRemoved = undefined, _equalityComparator, debugLocation) {
|
||||
super(debugLocation);
|
||||
this._debugNameData = _debugNameData;
|
||||
this._computeFn = _computeFn;
|
||||
this._changeTracker = _changeTracker;
|
||||
this._handleLastObserverRemoved = _handleLastObserverRemoved;
|
||||
this._equalityComparator = _equalityComparator;
|
||||
this._state = 0 /* DerivedState.initial */;
|
||||
this._value = undefined;
|
||||
this._updateCount = 0;
|
||||
this._dependencies = new Set();
|
||||
this._dependenciesToBeRemoved = new Set();
|
||||
this._changeSummary = undefined;
|
||||
this._isUpdating = false;
|
||||
this._isComputing = false;
|
||||
this._didReportChange = false;
|
||||
this._isInBeforeUpdate = false;
|
||||
this._isReaderValid = false;
|
||||
this._store = undefined;
|
||||
this._delayedStore = undefined;
|
||||
this._removedObserverToCallEndUpdateOn = null;
|
||||
this._changeSummary = this._changeTracker?.createChangeSummary(undefined);
|
||||
}
|
||||
onLastObserverRemoved() {
|
||||
/**
|
||||
* We are not tracking changes anymore, thus we have to assume
|
||||
* that our cache is invalid.
|
||||
*/
|
||||
this._state = 0 /* DerivedState.initial */;
|
||||
this._value = undefined;
|
||||
getLogger()?.handleDerivedCleared(this);
|
||||
for (const d of this._dependencies) {
|
||||
d.removeObserver(this);
|
||||
}
|
||||
this._dependencies.clear();
|
||||
if (this._store !== undefined) {
|
||||
this._store.dispose();
|
||||
this._store = undefined;
|
||||
}
|
||||
if (this._delayedStore !== undefined) {
|
||||
this._delayedStore.dispose();
|
||||
this._delayedStore = undefined;
|
||||
}
|
||||
this._handleLastObserverRemoved?.();
|
||||
}
|
||||
get() {
|
||||
const checkEnabled = false; // TODO set to true
|
||||
if (this._isComputing && checkEnabled) {
|
||||
// investigate why this fails in the diff editor!
|
||||
throw new BugIndicatingError('Cyclic deriveds are not supported yet!');
|
||||
}
|
||||
if (this._observers.size === 0) {
|
||||
let result;
|
||||
// Without observers, we don't know when to clean up stuff.
|
||||
// Thus, we don't cache anything to prevent memory leaks.
|
||||
try {
|
||||
this._isReaderValid = true;
|
||||
let changeSummary = undefined;
|
||||
if (this._changeTracker) {
|
||||
changeSummary = this._changeTracker.createChangeSummary(undefined);
|
||||
this._changeTracker.beforeUpdate?.(this, changeSummary);
|
||||
}
|
||||
result = this._computeFn(this, changeSummary);
|
||||
}
|
||||
finally {
|
||||
this._isReaderValid = false;
|
||||
}
|
||||
// Clear new dependencies
|
||||
this.onLastObserverRemoved();
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
do {
|
||||
// We might not get a notification for a dependency that changed while it is updating,
|
||||
// thus we also have to ask all our depedencies if they changed in this case.
|
||||
if (this._state === 1 /* DerivedState.dependenciesMightHaveChanged */) {
|
||||
for (const d of this._dependencies) {
|
||||
/** might call {@link handleChange} indirectly, which could make us stale */
|
||||
d.reportChanges();
|
||||
if (this._state === 2 /* DerivedState.stale */) {
|
||||
// The other dependencies will refresh on demand, so early break
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// We called report changes of all dependencies.
|
||||
// If we are still not stale, we can assume to be up to date again.
|
||||
if (this._state === 1 /* DerivedState.dependenciesMightHaveChanged */) {
|
||||
this._state = 3 /* DerivedState.upToDate */;
|
||||
}
|
||||
if (this._state !== 3 /* DerivedState.upToDate */) {
|
||||
this._recompute();
|
||||
}
|
||||
// In case recomputation changed one of our dependencies, we need to recompute again.
|
||||
} while (this._state !== 3 /* DerivedState.upToDate */);
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
_recompute() {
|
||||
let didChange = false;
|
||||
this._isComputing = true;
|
||||
this._didReportChange = false;
|
||||
const emptySet = this._dependenciesToBeRemoved;
|
||||
this._dependenciesToBeRemoved = this._dependencies;
|
||||
this._dependencies = emptySet;
|
||||
try {
|
||||
const changeSummary = this._changeSummary;
|
||||
this._isReaderValid = true;
|
||||
if (this._changeTracker) {
|
||||
this._isInBeforeUpdate = true;
|
||||
this._changeTracker.beforeUpdate?.(this, changeSummary);
|
||||
this._isInBeforeUpdate = false;
|
||||
this._changeSummary = this._changeTracker?.createChangeSummary(changeSummary);
|
||||
}
|
||||
const hadValue = this._state !== 0 /* DerivedState.initial */;
|
||||
const oldValue = this._value;
|
||||
this._state = 3 /* DerivedState.upToDate */;
|
||||
const delayedStore = this._delayedStore;
|
||||
if (delayedStore !== undefined) {
|
||||
this._delayedStore = undefined;
|
||||
}
|
||||
try {
|
||||
if (this._store !== undefined) {
|
||||
this._store.dispose();
|
||||
this._store = undefined;
|
||||
}
|
||||
/** might call {@link handleChange} indirectly, which could invalidate us */
|
||||
this._value = this._computeFn(this, changeSummary);
|
||||
}
|
||||
finally {
|
||||
this._isReaderValid = false;
|
||||
// We don't want our observed observables to think that they are (not even temporarily) not being observed.
|
||||
// Thus, we only unsubscribe from observables that are definitely not read anymore.
|
||||
for (const o of this._dependenciesToBeRemoved) {
|
||||
o.removeObserver(this);
|
||||
}
|
||||
this._dependenciesToBeRemoved.clear();
|
||||
if (delayedStore !== undefined) {
|
||||
delayedStore.dispose();
|
||||
}
|
||||
}
|
||||
didChange = this._didReportChange || (hadValue && !(this._equalityComparator(oldValue, this._value)));
|
||||
getLogger()?.handleObservableUpdated(this, {
|
||||
oldValue,
|
||||
newValue: this._value,
|
||||
change: undefined,
|
||||
didChange,
|
||||
hadValue,
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
onBugIndicatingError(e);
|
||||
}
|
||||
this._isComputing = false;
|
||||
if (!this._didReportChange && didChange) {
|
||||
for (const r of this._observers) {
|
||||
r.handleChange(this, undefined);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this._didReportChange = false;
|
||||
}
|
||||
}
|
||||
toString() {
|
||||
return `LazyDerived<${this.debugName}>`;
|
||||
}
|
||||
// IObserver Implementation
|
||||
beginUpdate(_observable) {
|
||||
if (this._isUpdating) {
|
||||
throw new BugIndicatingError('Cyclic deriveds are not supported yet!');
|
||||
}
|
||||
this._updateCount++;
|
||||
this._isUpdating = true;
|
||||
try {
|
||||
const propagateBeginUpdate = this._updateCount === 1;
|
||||
if (this._state === 3 /* DerivedState.upToDate */) {
|
||||
this._state = 1 /* DerivedState.dependenciesMightHaveChanged */;
|
||||
// If we propagate begin update, that will already signal a possible change.
|
||||
if (!propagateBeginUpdate) {
|
||||
for (const r of this._observers) {
|
||||
r.handlePossibleChange(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (propagateBeginUpdate) {
|
||||
for (const r of this._observers) {
|
||||
r.beginUpdate(this); // This signals a possible change
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this._isUpdating = false;
|
||||
}
|
||||
}
|
||||
endUpdate(_observable) {
|
||||
this._updateCount--;
|
||||
if (this._updateCount === 0) {
|
||||
// End update could change the observer list.
|
||||
const observers = [...this._observers];
|
||||
for (const r of observers) {
|
||||
r.endUpdate(this);
|
||||
}
|
||||
if (this._removedObserverToCallEndUpdateOn) {
|
||||
const observers = [...this._removedObserverToCallEndUpdateOn];
|
||||
this._removedObserverToCallEndUpdateOn = null;
|
||||
for (const r of observers) {
|
||||
r.endUpdate(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
assertFn(() => this._updateCount >= 0);
|
||||
}
|
||||
handlePossibleChange(observable) {
|
||||
// In all other states, observers already know that we might have changed.
|
||||
if (this._state === 3 /* DerivedState.upToDate */ && this._dependencies.has(observable) && !this._dependenciesToBeRemoved.has(observable)) {
|
||||
this._state = 1 /* DerivedState.dependenciesMightHaveChanged */;
|
||||
for (const r of this._observers) {
|
||||
r.handlePossibleChange(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
handleChange(observable, change) {
|
||||
if (this._dependencies.has(observable) && !this._dependenciesToBeRemoved.has(observable) || this._isInBeforeUpdate) {
|
||||
getLogger()?.handleDerivedDependencyChanged(this, observable, change);
|
||||
let shouldReact = false;
|
||||
try {
|
||||
shouldReact = this._changeTracker ? this._changeTracker.handleChange({
|
||||
changedObservable: observable,
|
||||
change,
|
||||
didChange: (o) => o === observable,
|
||||
}, this._changeSummary) : true;
|
||||
}
|
||||
catch (e) {
|
||||
onBugIndicatingError(e);
|
||||
}
|
||||
const wasUpToDate = this._state === 3 /* DerivedState.upToDate */;
|
||||
if (shouldReact && (this._state === 1 /* DerivedState.dependenciesMightHaveChanged */ || wasUpToDate)) {
|
||||
this._state = 2 /* DerivedState.stale */;
|
||||
if (wasUpToDate) {
|
||||
for (const r of this._observers) {
|
||||
r.handlePossibleChange(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// IReader Implementation
|
||||
_ensureReaderValid() {
|
||||
if (!this._isReaderValid) {
|
||||
throw new BugIndicatingError('The reader object cannot be used outside its compute function!');
|
||||
}
|
||||
}
|
||||
readObservable(observable) {
|
||||
this._ensureReaderValid();
|
||||
// Subscribe before getting the value to enable caching
|
||||
observable.addObserver(this);
|
||||
/** This might call {@link handleChange} indirectly, which could invalidate us */
|
||||
const value = observable.get();
|
||||
// Which is why we only add the observable to the dependencies now.
|
||||
this._dependencies.add(observable);
|
||||
this._dependenciesToBeRemoved.delete(observable);
|
||||
return value;
|
||||
}
|
||||
get store() {
|
||||
this._ensureReaderValid();
|
||||
if (this._store === undefined) {
|
||||
this._store = new DisposableStore();
|
||||
}
|
||||
return this._store;
|
||||
}
|
||||
addObserver(observer) {
|
||||
const shouldCallBeginUpdate = !this._observers.has(observer) && this._updateCount > 0;
|
||||
super.addObserver(observer);
|
||||
if (shouldCallBeginUpdate) {
|
||||
if (this._removedObserverToCallEndUpdateOn && this._removedObserverToCallEndUpdateOn.has(observer)) {
|
||||
this._removedObserverToCallEndUpdateOn.delete(observer);
|
||||
}
|
||||
else {
|
||||
observer.beginUpdate(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
removeObserver(observer) {
|
||||
if (this._observers.has(observer) && this._updateCount > 0) {
|
||||
if (!this._removedObserverToCallEndUpdateOn) {
|
||||
this._removedObserverToCallEndUpdateOn = new Set();
|
||||
}
|
||||
this._removedObserverToCallEndUpdateOn.add(observer);
|
||||
}
|
||||
super.removeObserver(observer);
|
||||
}
|
||||
debugGetState() {
|
||||
return {
|
||||
state: this._state,
|
||||
stateStr: derivedStateToString(this._state),
|
||||
updateCount: this._updateCount,
|
||||
isComputing: this._isComputing,
|
||||
dependencies: this._dependencies,
|
||||
value: this._value,
|
||||
};
|
||||
}
|
||||
debugSetValue(newValue) {
|
||||
this._value = newValue;
|
||||
}
|
||||
debugRecompute() {
|
||||
if (!this._isComputing) {
|
||||
this._recompute();
|
||||
}
|
||||
else {
|
||||
this._state = 2 /* DerivedState.stale */;
|
||||
}
|
||||
}
|
||||
setValue(newValue, tx, change) {
|
||||
this._value = newValue;
|
||||
const observers = this._observers;
|
||||
tx.updateObserver(this, this);
|
||||
for (const d of observers) {
|
||||
d.handleChange(this, change);
|
||||
}
|
||||
}
|
||||
}
|
||||
export class DerivedWithSetter extends Derived {
|
||||
constructor(debugNameData, computeFn, changeTracker, handleLastObserverRemoved = undefined, equalityComparator, set, debugLocation) {
|
||||
super(debugNameData, computeFn, changeTracker, handleLastObserverRemoved, equalityComparator, debugLocation);
|
||||
this.set = set;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=derivedImpl.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,123 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { TransactionImpl } from '../transaction.js';
|
||||
import { getLogger } from '../logging/logging.js';
|
||||
import { BaseObservable } from './baseObservable.js';
|
||||
/**
|
||||
* Holds off updating observers until the value is actually read.
|
||||
*/
|
||||
export class LazyObservableValue extends BaseObservable {
|
||||
get debugName() {
|
||||
return this._debugNameData.getDebugName(this) ?? 'LazyObservableValue';
|
||||
}
|
||||
constructor(_debugNameData, initialValue, _equalityComparator, debugLocation) {
|
||||
super(debugLocation);
|
||||
this._debugNameData = _debugNameData;
|
||||
this._equalityComparator = _equalityComparator;
|
||||
this._isUpToDate = true;
|
||||
this._deltas = [];
|
||||
this._updateCounter = 0;
|
||||
this._value = initialValue;
|
||||
}
|
||||
get() {
|
||||
this._update();
|
||||
return this._value;
|
||||
}
|
||||
_update() {
|
||||
if (this._isUpToDate) {
|
||||
return;
|
||||
}
|
||||
this._isUpToDate = true;
|
||||
if (this._deltas.length > 0) {
|
||||
for (const change of this._deltas) {
|
||||
getLogger()?.handleObservableUpdated(this, { change, didChange: true, oldValue: '(unknown)', newValue: this._value, hadValue: true });
|
||||
for (const observer of this._observers) {
|
||||
observer.handleChange(this, change);
|
||||
}
|
||||
}
|
||||
this._deltas.length = 0;
|
||||
}
|
||||
else {
|
||||
getLogger()?.handleObservableUpdated(this, { change: undefined, didChange: true, oldValue: '(unknown)', newValue: this._value, hadValue: true });
|
||||
for (const observer of this._observers) {
|
||||
observer.handleChange(this, undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
_beginUpdate() {
|
||||
this._updateCounter++;
|
||||
if (this._updateCounter === 1) {
|
||||
for (const observer of this._observers) {
|
||||
observer.beginUpdate(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
_endUpdate() {
|
||||
this._updateCounter--;
|
||||
if (this._updateCounter === 0) {
|
||||
this._update();
|
||||
// End update could change the observer list.
|
||||
const observers = [...this._observers];
|
||||
for (const r of observers) {
|
||||
r.endUpdate(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
addObserver(observer) {
|
||||
const shouldCallBeginUpdate = !this._observers.has(observer) && this._updateCounter > 0;
|
||||
super.addObserver(observer);
|
||||
if (shouldCallBeginUpdate) {
|
||||
observer.beginUpdate(this);
|
||||
}
|
||||
}
|
||||
removeObserver(observer) {
|
||||
const shouldCallEndUpdate = this._observers.has(observer) && this._updateCounter > 0;
|
||||
super.removeObserver(observer);
|
||||
if (shouldCallEndUpdate) {
|
||||
// Calling end update after removing the observer makes sure endUpdate cannot be called twice here.
|
||||
observer.endUpdate(this);
|
||||
}
|
||||
}
|
||||
set(value, tx, change) {
|
||||
if (change === undefined && this._equalityComparator(this._value, value)) {
|
||||
return;
|
||||
}
|
||||
let _tx;
|
||||
if (!tx) {
|
||||
tx = _tx = new TransactionImpl(() => { }, () => `Setting ${this.debugName}`);
|
||||
}
|
||||
try {
|
||||
this._isUpToDate = false;
|
||||
this._setValue(value);
|
||||
if (change !== undefined) {
|
||||
this._deltas.push(change);
|
||||
}
|
||||
tx.updateObserver({
|
||||
beginUpdate: () => this._beginUpdate(),
|
||||
endUpdate: () => this._endUpdate(),
|
||||
handleChange: (observable, change) => { },
|
||||
handlePossibleChange: (observable) => { },
|
||||
}, this);
|
||||
if (this._updateCounter > 1) {
|
||||
// We already started begin/end update, so we need to manually call handlePossibleChange
|
||||
for (const observer of this._observers) {
|
||||
observer.handlePossibleChange(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (_tx) {
|
||||
_tx.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
toString() {
|
||||
return `${this.debugName}: ${this._value}`;
|
||||
}
|
||||
_setValue(newValue) {
|
||||
this._value = newValue;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=lazyObservableValue.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,118 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { subtransaction } from '../transaction.js';
|
||||
import { strictEquals } from '../commonFacade/deps.js';
|
||||
import { DebugNameData } from '../debugName.js';
|
||||
import { getLogger } from '../logging/logging.js';
|
||||
import { BaseObservable } from './baseObservable.js';
|
||||
import { DebugLocation } from '../debugLocation.js';
|
||||
export function observableFromEvent(...args) {
|
||||
let owner;
|
||||
let event;
|
||||
let getValue;
|
||||
let debugLocation;
|
||||
if (args.length === 2) {
|
||||
[event, getValue] = args;
|
||||
}
|
||||
else {
|
||||
[owner, event, getValue, debugLocation] = args;
|
||||
}
|
||||
return new FromEventObservable(new DebugNameData(owner, undefined, getValue), event, getValue, () => FromEventObservable.globalTransaction, strictEquals, debugLocation ?? DebugLocation.ofCaller());
|
||||
}
|
||||
export function observableFromEventOpts(options, event, getValue, debugLocation = DebugLocation.ofCaller()) {
|
||||
return new FromEventObservable(new DebugNameData(options.owner, options.debugName, options.debugReferenceFn ?? getValue), event, getValue, () => FromEventObservable.globalTransaction, options.equalsFn ?? strictEquals, debugLocation);
|
||||
}
|
||||
export class FromEventObservable extends BaseObservable {
|
||||
constructor(_debugNameData, event, _getValue, _getTransaction, _equalityComparator, debugLocation) {
|
||||
super(debugLocation);
|
||||
this._debugNameData = _debugNameData;
|
||||
this.event = event;
|
||||
this._getValue = _getValue;
|
||||
this._getTransaction = _getTransaction;
|
||||
this._equalityComparator = _equalityComparator;
|
||||
this._hasValue = false;
|
||||
this.handleEvent = (args) => {
|
||||
const newValue = this._getValue(args);
|
||||
const oldValue = this._value;
|
||||
const didChange = !this._hasValue || !(this._equalityComparator(oldValue, newValue));
|
||||
let didRunTransaction = false;
|
||||
if (didChange) {
|
||||
this._value = newValue;
|
||||
if (this._hasValue) {
|
||||
didRunTransaction = true;
|
||||
subtransaction(this._getTransaction(), (tx) => {
|
||||
getLogger()?.handleObservableUpdated(this, { oldValue, newValue, change: undefined, didChange, hadValue: this._hasValue });
|
||||
for (const o of this._observers) {
|
||||
tx.updateObserver(o, this);
|
||||
o.handleChange(this, undefined);
|
||||
}
|
||||
}, () => {
|
||||
const name = this.getDebugName();
|
||||
return 'Event fired' + (name ? `: ${name}` : '');
|
||||
});
|
||||
}
|
||||
this._hasValue = true;
|
||||
}
|
||||
if (!didRunTransaction) {
|
||||
getLogger()?.handleObservableUpdated(this, { oldValue, newValue, change: undefined, didChange, hadValue: this._hasValue });
|
||||
}
|
||||
};
|
||||
}
|
||||
getDebugName() {
|
||||
return this._debugNameData.getDebugName(this);
|
||||
}
|
||||
get debugName() {
|
||||
const name = this.getDebugName();
|
||||
return 'From Event' + (name ? `: ${name}` : '');
|
||||
}
|
||||
onFirstObserverAdded() {
|
||||
this._subscription = this.event(this.handleEvent);
|
||||
}
|
||||
onLastObserverRemoved() {
|
||||
this._subscription.dispose();
|
||||
this._subscription = undefined;
|
||||
this._hasValue = false;
|
||||
this._value = undefined;
|
||||
}
|
||||
get() {
|
||||
if (this._subscription) {
|
||||
if (!this._hasValue) {
|
||||
this.handleEvent(undefined);
|
||||
}
|
||||
return this._value;
|
||||
}
|
||||
else {
|
||||
// no cache, as there are no subscribers to keep it updated
|
||||
const value = this._getValue(undefined);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
debugSetValue(value) {
|
||||
this._value = value;
|
||||
}
|
||||
debugGetState() {
|
||||
return { value: this._value, hasValue: this._hasValue };
|
||||
}
|
||||
}
|
||||
(function (observableFromEvent) {
|
||||
observableFromEvent.Observer = FromEventObservable;
|
||||
function batchEventsGlobally(tx, fn) {
|
||||
let didSet = false;
|
||||
if (FromEventObservable.globalTransaction === undefined) {
|
||||
FromEventObservable.globalTransaction = tx;
|
||||
didSet = true;
|
||||
}
|
||||
try {
|
||||
fn();
|
||||
}
|
||||
finally {
|
||||
if (didSet) {
|
||||
FromEventObservable.globalTransaction = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
observableFromEvent.batchEventsGlobally = batchEventsGlobally;
|
||||
})(observableFromEvent || (observableFromEvent = {}));
|
||||
//# sourceMappingURL=observableFromEvent.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,45 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { transaction } from '../transaction.js';
|
||||
import { DebugNameData } from '../debugName.js';
|
||||
import { BaseObservable } from './baseObservable.js';
|
||||
import { DebugLocation } from '../debugLocation.js';
|
||||
export function observableSignal(debugNameOrOwner, debugLocation = DebugLocation.ofCaller()) {
|
||||
if (typeof debugNameOrOwner === 'string') {
|
||||
return new ObservableSignal(debugNameOrOwner, undefined, debugLocation);
|
||||
}
|
||||
else {
|
||||
return new ObservableSignal(undefined, debugNameOrOwner, debugLocation);
|
||||
}
|
||||
}
|
||||
class ObservableSignal extends BaseObservable {
|
||||
get debugName() {
|
||||
return new DebugNameData(this._owner, this._debugName, undefined).getDebugName(this) ?? 'Observable Signal';
|
||||
}
|
||||
toString() {
|
||||
return this.debugName;
|
||||
}
|
||||
constructor(_debugName, _owner, debugLocation) {
|
||||
super(debugLocation);
|
||||
this._debugName = _debugName;
|
||||
this._owner = _owner;
|
||||
}
|
||||
trigger(tx, change) {
|
||||
if (!tx) {
|
||||
transaction(tx => {
|
||||
this.trigger(tx, change);
|
||||
}, () => `Trigger signal ${this.debugName}`);
|
||||
return;
|
||||
}
|
||||
for (const o of this._observers) {
|
||||
tx.updateObserver(o, this);
|
||||
o.handleChange(this, change);
|
||||
}
|
||||
}
|
||||
get() {
|
||||
// NO OP
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=observableSignal.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,39 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { transaction } from '../transaction.js';
|
||||
import { DebugNameData } from '../debugName.js';
|
||||
import { BaseObservable } from './baseObservable.js';
|
||||
import { DebugLocation } from '../debugLocation.js';
|
||||
export function observableSignalFromEvent(owner, event, debugLocation = DebugLocation.ofCaller()) {
|
||||
return new FromEventObservableSignal(typeof owner === 'string' ? owner : new DebugNameData(owner, undefined, undefined), event, debugLocation);
|
||||
}
|
||||
class FromEventObservableSignal extends BaseObservable {
|
||||
constructor(debugNameDataOrName, event, debugLocation) {
|
||||
super(debugLocation);
|
||||
this.event = event;
|
||||
this.handleEvent = () => {
|
||||
transaction((tx) => {
|
||||
for (const o of this._observers) {
|
||||
tx.updateObserver(o, this);
|
||||
o.handleChange(this, undefined);
|
||||
}
|
||||
}, () => this.debugName);
|
||||
};
|
||||
this.debugName = typeof debugNameDataOrName === 'string'
|
||||
? debugNameDataOrName
|
||||
: debugNameDataOrName.getDebugName(this) ?? 'Observable Signal From Event';
|
||||
}
|
||||
onFirstObserverAdded() {
|
||||
this.subscription = this.event(this.handleEvent);
|
||||
}
|
||||
onLastObserverRemoved() {
|
||||
this.subscription.dispose();
|
||||
this.subscription = undefined;
|
||||
}
|
||||
get() {
|
||||
// NO OP
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=observableSignalFromEvent.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,101 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { TransactionImpl } from '../transaction.js';
|
||||
import { BaseObservable } from './baseObservable.js';
|
||||
import { strictEquals } from '../commonFacade/deps.js';
|
||||
import { DebugNameData } from '../debugName.js';
|
||||
import { getLogger } from '../logging/logging.js';
|
||||
import { DebugLocation } from '../debugLocation.js';
|
||||
export function observableValue(nameOrOwner, initialValue, debugLocation = DebugLocation.ofCaller()) {
|
||||
let debugNameData;
|
||||
if (typeof nameOrOwner === 'string') {
|
||||
debugNameData = new DebugNameData(undefined, nameOrOwner, undefined);
|
||||
}
|
||||
else {
|
||||
debugNameData = new DebugNameData(nameOrOwner, undefined, undefined);
|
||||
}
|
||||
return new ObservableValue(debugNameData, initialValue, strictEquals, debugLocation);
|
||||
}
|
||||
export class ObservableValue extends BaseObservable {
|
||||
get debugName() {
|
||||
return this._debugNameData.getDebugName(this) ?? 'ObservableValue';
|
||||
}
|
||||
constructor(_debugNameData, initialValue, _equalityComparator, debugLocation) {
|
||||
super(debugLocation);
|
||||
this._debugNameData = _debugNameData;
|
||||
this._equalityComparator = _equalityComparator;
|
||||
this._value = initialValue;
|
||||
getLogger()?.handleObservableUpdated(this, { hadValue: false, newValue: initialValue, change: undefined, didChange: true, oldValue: undefined });
|
||||
}
|
||||
get() {
|
||||
return this._value;
|
||||
}
|
||||
set(value, tx, change) {
|
||||
if (change === undefined && this._equalityComparator(this._value, value)) {
|
||||
return;
|
||||
}
|
||||
let _tx;
|
||||
if (!tx) {
|
||||
tx = _tx = new TransactionImpl(() => { }, () => `Setting ${this.debugName}`);
|
||||
}
|
||||
try {
|
||||
const oldValue = this._value;
|
||||
this._setValue(value);
|
||||
getLogger()?.handleObservableUpdated(this, { oldValue, newValue: value, change, didChange: true, hadValue: true });
|
||||
for (const observer of this._observers) {
|
||||
tx.updateObserver(observer, this);
|
||||
observer.handleChange(this, change);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (_tx) {
|
||||
_tx.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
toString() {
|
||||
return `${this.debugName}: ${this._value}`;
|
||||
}
|
||||
_setValue(newValue) {
|
||||
this._value = newValue;
|
||||
}
|
||||
debugGetState() {
|
||||
return {
|
||||
value: this._value,
|
||||
};
|
||||
}
|
||||
debugSetValue(value) {
|
||||
this._value = value;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* A disposable observable. When disposed, its value is also disposed.
|
||||
* When a new value is set, the previous value is disposed.
|
||||
*/
|
||||
export function disposableObservableValue(nameOrOwner, initialValue, debugLocation = DebugLocation.ofCaller()) {
|
||||
let debugNameData;
|
||||
if (typeof nameOrOwner === 'string') {
|
||||
debugNameData = new DebugNameData(undefined, nameOrOwner, undefined);
|
||||
}
|
||||
else {
|
||||
debugNameData = new DebugNameData(nameOrOwner, undefined, undefined);
|
||||
}
|
||||
return new DisposableObservableValue(debugNameData, initialValue, strictEquals, debugLocation);
|
||||
}
|
||||
export class DisposableObservableValue extends ObservableValue {
|
||||
_setValue(newValue) {
|
||||
if (this._value === newValue) {
|
||||
return;
|
||||
}
|
||||
if (this._value) {
|
||||
this._value.dispose();
|
||||
}
|
||||
this._value = newValue;
|
||||
}
|
||||
dispose() {
|
||||
this._value?.dispose();
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=observableValue.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,16 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { DebugNameData } from '../debugName.js';
|
||||
import { strictEquals } from '../commonFacade/deps.js';
|
||||
import { ObservableValue } from './observableValue.js';
|
||||
import { LazyObservableValue } from './lazyObservableValue.js';
|
||||
import { DebugLocation } from '../debugLocation.js';
|
||||
export function observableValueOpts(options, initialValue, debugLocation = DebugLocation.ofCaller()) {
|
||||
if (options.lazy) {
|
||||
return new LazyObservableValue(new DebugNameData(options.owner, options.debugName, undefined), initialValue, options.equalsFn ?? strictEquals, debugLocation);
|
||||
}
|
||||
return new ObservableValue(new DebugNameData(options.owner, options.debugName, undefined), initialValue, options.equalsFn ?? strictEquals, debugLocation);
|
||||
}
|
||||
//# sourceMappingURL=observableValueOpts.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/observableInternal/observables/observableValueOpts.ts","vs/base/common/observableInternal/observables/observableValueOpts.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAGhG,OAAO,EAAE,aAAa,EAAkB,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAoB,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,MAAM,UAAU,mBAAmB,CAClC,OAGC,EACD,YAAe,EACf,aAAa,GAAG,aAAa,CAAC,QAAQ,EAAE;IAExC,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QAClB,OAAO,IAAI,mBAAmB,CAC7B,IAAI,aAAa,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,EAC9D,YAAY,EACZ,OAAO,CAAC,QAAQ,IAAI,YAAY,EAChC,aAAa,CACb,CAAC;IACH,CAAC;IACD,OAAO,IAAI,eAAe,CACzB,IAAI,aAAa,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,EAC9D,YAAY,EACZ,OAAO,CAAC,QAAQ,IAAI,YAAY,EAChC,aAAa,CACb,CAAC;AACH,CAAC","file":"observableValueOpts.js","sourceRoot":"file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { ISettableObservable } from '../base.js';\nimport { DebugNameData, IDebugNameData } from '../debugName.js';\nimport { EqualityComparer, strictEquals } from '../commonFacade/deps.js';\nimport { ObservableValue } from './observableValue.js';\nimport { LazyObservableValue } from './lazyObservableValue.js';\nimport { DebugLocation } from '../debugLocation.js';\n\nexport function observableValueOpts<T, TChange = void>(\n\toptions: IDebugNameData & {\n\t\tequalsFn?: EqualityComparer<T>;\n\t\tlazy?: boolean;\n\t},\n\tinitialValue: T,\n\tdebugLocation = DebugLocation.ofCaller(),\n): ISettableObservable<T, TChange> {\n\tif (options.lazy) {\n\t\treturn new LazyObservableValue(\n\t\t\tnew DebugNameData(options.owner, options.debugName, undefined),\n\t\t\tinitialValue,\n\t\t\toptions.equalsFn ?? strictEquals,\n\t\t\tdebugLocation\n\t\t);\n\t}\n\treturn new ObservableValue(\n\t\tnew DebugNameData(options.owner, options.debugName, undefined),\n\t\tinitialValue,\n\t\toptions.equalsFn ?? strictEquals,\n\t\tdebugLocation\n\t);\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { ISettableObservable } from '../base.js';\nimport { DebugNameData, IDebugNameData } from '../debugName.js';\nimport { EqualityComparer, strictEquals } from '../commonFacade/deps.js';\nimport { ObservableValue } from './observableValue.js';\nimport { LazyObservableValue } from './lazyObservableValue.js';\nimport { DebugLocation } from '../debugLocation.js';\n\nexport function observableValueOpts<T, TChange = void>(\n\toptions: IDebugNameData & {\n\t\tequalsFn?: EqualityComparer<T>;\n\t\tlazy?: boolean;\n\t},\n\tinitialValue: T,\n\tdebugLocation = DebugLocation.ofCaller(),\n): ISettableObservable<T, TChange> {\n\tif (options.lazy) {\n\t\treturn new LazyObservableValue(\n\t\t\tnew DebugNameData(options.owner, options.debugName, undefined),\n\t\t\tinitialValue,\n\t\t\toptions.equalsFn ?? strictEquals,\n\t\t\tdebugLocation\n\t\t);\n\t}\n\treturn new ObservableValue(\n\t\tnew DebugNameData(options.owner, options.debugName, undefined),\n\t\tinitialValue,\n\t\toptions.equalsFn ?? strictEquals,\n\t\tdebugLocation\n\t);\n}\n"]}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { DisposableStore, toDisposable } from '../commonFacade/deps.js';
|
||||
import { DebugNameData } from '../debugName.js';
|
||||
import { AutorunObserver } from './autorunImpl.js';
|
||||
import { DebugLocation } from '../debugLocation.js';
|
||||
/**
|
||||
* Runs immediately and whenever a transaction ends and an observed observable changed.
|
||||
* {@link fn} should start with a JS Doc using `@description` to name the autorun.
|
||||
*/
|
||||
export function autorun(fn, debugLocation = DebugLocation.ofCaller()) {
|
||||
return new AutorunObserver(new DebugNameData(undefined, undefined, fn), fn, undefined, debugLocation);
|
||||
}
|
||||
/**
|
||||
* Runs immediately and whenever a transaction ends and an observed observable changed.
|
||||
* {@link fn} should start with a JS Doc using `@description` to name the autorun.
|
||||
*/
|
||||
export function autorunOpts(options, fn, debugLocation = DebugLocation.ofCaller()) {
|
||||
return new AutorunObserver(new DebugNameData(options.owner, options.debugName, options.debugReferenceFn ?? fn), fn, undefined, debugLocation);
|
||||
}
|
||||
/**
|
||||
* Runs immediately and whenever a transaction ends and an observed observable changed.
|
||||
* {@link fn} should start with a JS Doc using `@description` to name the autorun.
|
||||
*
|
||||
* Use `changeTracker.createChangeSummary` to create a "change summary" that can collect the changes.
|
||||
* Use `changeTracker.handleChange` to add a reported change to the change summary.
|
||||
* The run function is given the last change summary.
|
||||
* The change summary is discarded after the run function was called.
|
||||
*
|
||||
* @see autorun
|
||||
*/
|
||||
export function autorunHandleChanges(options, fn, debugLocation = DebugLocation.ofCaller()) {
|
||||
return new AutorunObserver(new DebugNameData(options.owner, options.debugName, options.debugReferenceFn ?? fn), fn, options.changeTracker, debugLocation);
|
||||
}
|
||||
/**
|
||||
* @see autorunHandleChanges (but with a disposable store that is cleared before the next run or on dispose)
|
||||
*/
|
||||
export function autorunWithStoreHandleChanges(options, fn) {
|
||||
const store = new DisposableStore();
|
||||
const disposable = autorunHandleChanges({
|
||||
owner: options.owner,
|
||||
debugName: options.debugName,
|
||||
debugReferenceFn: options.debugReferenceFn ?? fn,
|
||||
changeTracker: options.changeTracker,
|
||||
}, (reader, changeSummary) => {
|
||||
store.clear();
|
||||
fn(reader, changeSummary, store);
|
||||
});
|
||||
return toDisposable(() => {
|
||||
disposable.dispose();
|
||||
store.dispose();
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @see autorun (but with a disposable store that is cleared before the next run or on dispose)
|
||||
*
|
||||
* @deprecated Use `autorun(reader => { reader.store.add(...) })` instead!
|
||||
*/
|
||||
export function autorunWithStore(fn) {
|
||||
const store = new DisposableStore();
|
||||
const disposable = autorunOpts({
|
||||
owner: undefined,
|
||||
debugName: undefined,
|
||||
debugReferenceFn: fn,
|
||||
}, reader => {
|
||||
store.clear();
|
||||
fn(reader, store);
|
||||
});
|
||||
return toDisposable(() => {
|
||||
disposable.dispose();
|
||||
store.dispose();
|
||||
});
|
||||
}
|
||||
export function autorunDelta(observable, handler) {
|
||||
let _lastValue;
|
||||
return autorunOpts({ debugReferenceFn: handler }, (reader) => {
|
||||
const newValue = observable.read(reader);
|
||||
const lastValue = _lastValue;
|
||||
_lastValue = newValue;
|
||||
handler({ lastValue, newValue });
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=autorun.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,210 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { assertFn, BugIndicatingError, DisposableStore, markAsDisposed, onBugIndicatingError, trackDisposable } from '../commonFacade/deps.js';
|
||||
import { getLogger } from '../logging/logging.js';
|
||||
function autorunStateToString(state) {
|
||||
switch (state) {
|
||||
case 1 /* AutorunState.dependenciesMightHaveChanged */: return 'dependenciesMightHaveChanged';
|
||||
case 2 /* AutorunState.stale */: return 'stale';
|
||||
case 3 /* AutorunState.upToDate */: return 'upToDate';
|
||||
default: return '<unknown>';
|
||||
}
|
||||
}
|
||||
export class AutorunObserver {
|
||||
get debugName() {
|
||||
return this._debugNameData.getDebugName(this) ?? '(anonymous)';
|
||||
}
|
||||
constructor(_debugNameData, _runFn, _changeTracker, debugLocation) {
|
||||
this._debugNameData = _debugNameData;
|
||||
this._runFn = _runFn;
|
||||
this._changeTracker = _changeTracker;
|
||||
this._state = 2 /* AutorunState.stale */;
|
||||
this._updateCount = 0;
|
||||
this._disposed = false;
|
||||
this._dependencies = new Set();
|
||||
this._dependenciesToBeRemoved = new Set();
|
||||
this._isRunning = false;
|
||||
this._store = undefined;
|
||||
this._delayedStore = undefined;
|
||||
this._changeSummary = this._changeTracker?.createChangeSummary(undefined);
|
||||
getLogger()?.handleAutorunCreated(this, debugLocation);
|
||||
this._run();
|
||||
trackDisposable(this);
|
||||
}
|
||||
dispose() {
|
||||
if (this._disposed) {
|
||||
return;
|
||||
}
|
||||
this._disposed = true;
|
||||
for (const o of this._dependencies) {
|
||||
o.removeObserver(this); // Warning: external call!
|
||||
}
|
||||
this._dependencies.clear();
|
||||
if (this._store !== undefined) {
|
||||
this._store.dispose();
|
||||
}
|
||||
if (this._delayedStore !== undefined) {
|
||||
this._delayedStore.dispose();
|
||||
}
|
||||
getLogger()?.handleAutorunDisposed(this);
|
||||
markAsDisposed(this);
|
||||
}
|
||||
_run() {
|
||||
const emptySet = this._dependenciesToBeRemoved;
|
||||
this._dependenciesToBeRemoved = this._dependencies;
|
||||
this._dependencies = emptySet;
|
||||
this._state = 3 /* AutorunState.upToDate */;
|
||||
try {
|
||||
if (!this._disposed) {
|
||||
getLogger()?.handleAutorunStarted(this);
|
||||
const changeSummary = this._changeSummary;
|
||||
const delayedStore = this._delayedStore;
|
||||
if (delayedStore !== undefined) {
|
||||
this._delayedStore = undefined;
|
||||
}
|
||||
try {
|
||||
this._isRunning = true;
|
||||
if (this._changeTracker) {
|
||||
this._changeTracker.beforeUpdate?.(this, changeSummary);
|
||||
this._changeSummary = this._changeTracker.createChangeSummary(changeSummary); // Warning: external call!
|
||||
}
|
||||
if (this._store !== undefined) {
|
||||
this._store.dispose();
|
||||
this._store = undefined;
|
||||
}
|
||||
this._runFn(this, changeSummary); // Warning: external call!
|
||||
}
|
||||
catch (e) {
|
||||
onBugIndicatingError(e);
|
||||
}
|
||||
finally {
|
||||
this._isRunning = false;
|
||||
if (delayedStore !== undefined) {
|
||||
delayedStore.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (!this._disposed) {
|
||||
getLogger()?.handleAutorunFinished(this);
|
||||
}
|
||||
// We don't want our observed observables to think that they are (not even temporarily) not being observed.
|
||||
// Thus, we only unsubscribe from observables that are definitely not read anymore.
|
||||
for (const o of this._dependenciesToBeRemoved) {
|
||||
o.removeObserver(this); // Warning: external call!
|
||||
}
|
||||
this._dependenciesToBeRemoved.clear();
|
||||
}
|
||||
}
|
||||
toString() {
|
||||
return `Autorun<${this.debugName}>`;
|
||||
}
|
||||
// IObserver implementation
|
||||
beginUpdate(_observable) {
|
||||
if (this._state === 3 /* AutorunState.upToDate */) {
|
||||
this._state = 1 /* AutorunState.dependenciesMightHaveChanged */;
|
||||
}
|
||||
this._updateCount++;
|
||||
}
|
||||
endUpdate(_observable) {
|
||||
try {
|
||||
if (this._updateCount === 1) {
|
||||
do {
|
||||
if (this._state === 1 /* AutorunState.dependenciesMightHaveChanged */) {
|
||||
this._state = 3 /* AutorunState.upToDate */;
|
||||
for (const d of this._dependencies) {
|
||||
d.reportChanges(); // Warning: external call!
|
||||
if (this._state === 2 /* AutorunState.stale */) {
|
||||
// The other dependencies will refresh on demand
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this._state !== 3 /* AutorunState.upToDate */) {
|
||||
this._run(); // Warning: indirect external call!
|
||||
}
|
||||
} while (this._state !== 3 /* AutorunState.upToDate */);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this._updateCount--;
|
||||
}
|
||||
assertFn(() => this._updateCount >= 0);
|
||||
}
|
||||
handlePossibleChange(observable) {
|
||||
if (this._state === 3 /* AutorunState.upToDate */ && this._isDependency(observable)) {
|
||||
this._state = 1 /* AutorunState.dependenciesMightHaveChanged */;
|
||||
}
|
||||
}
|
||||
handleChange(observable, change) {
|
||||
if (this._isDependency(observable)) {
|
||||
getLogger()?.handleAutorunDependencyChanged(this, observable, change);
|
||||
try {
|
||||
// Warning: external call!
|
||||
const shouldReact = this._changeTracker ? this._changeTracker.handleChange({
|
||||
changedObservable: observable,
|
||||
change,
|
||||
didChange: (o) => o === observable,
|
||||
}, this._changeSummary) : true;
|
||||
if (shouldReact) {
|
||||
this._state = 2 /* AutorunState.stale */;
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
onBugIndicatingError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
_isDependency(observable) {
|
||||
return this._dependencies.has(observable) && !this._dependenciesToBeRemoved.has(observable);
|
||||
}
|
||||
// IReader implementation
|
||||
_ensureNoRunning() {
|
||||
if (!this._isRunning) {
|
||||
throw new BugIndicatingError('The reader object cannot be used outside its compute function!');
|
||||
}
|
||||
}
|
||||
readObservable(observable) {
|
||||
this._ensureNoRunning();
|
||||
// In case the run action disposes the autorun
|
||||
if (this._disposed) {
|
||||
return observable.get(); // warning: external call!
|
||||
}
|
||||
observable.addObserver(this); // warning: external call!
|
||||
const value = observable.get(); // warning: external call!
|
||||
this._dependencies.add(observable);
|
||||
this._dependenciesToBeRemoved.delete(observable);
|
||||
return value;
|
||||
}
|
||||
get store() {
|
||||
this._ensureNoRunning();
|
||||
if (this._disposed) {
|
||||
throw new BugIndicatingError('Cannot access store after dispose');
|
||||
}
|
||||
if (this._store === undefined) {
|
||||
this._store = new DisposableStore();
|
||||
}
|
||||
return this._store;
|
||||
}
|
||||
debugGetState() {
|
||||
return {
|
||||
isRunning: this._isRunning,
|
||||
updateCount: this._updateCount,
|
||||
dependencies: this._dependencies,
|
||||
state: this._state,
|
||||
stateStr: autorunStateToString(this._state),
|
||||
};
|
||||
}
|
||||
debugRerun() {
|
||||
if (!this._isRunning) {
|
||||
this._run();
|
||||
}
|
||||
else {
|
||||
this._state = 2 /* AutorunState.stale */;
|
||||
}
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=autorunImpl.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,107 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { handleBugIndicatingErrorRecovery } from './base.js';
|
||||
import { getFunctionName } from './debugName.js';
|
||||
import { getLogger } from './logging/logging.js';
|
||||
/**
|
||||
* Starts a transaction in which many observables can be changed at once.
|
||||
* {@link fn} should start with a JS Doc using `@description` to give the transaction a debug name.
|
||||
* Reaction run on demand or when the transaction ends.
|
||||
*/
|
||||
export function transaction(fn, getDebugName) {
|
||||
const tx = new TransactionImpl(fn, getDebugName);
|
||||
try {
|
||||
fn(tx);
|
||||
}
|
||||
finally {
|
||||
tx.finish();
|
||||
}
|
||||
}
|
||||
let _globalTransaction = undefined;
|
||||
export function globalTransaction(fn) {
|
||||
if (_globalTransaction) {
|
||||
fn(_globalTransaction);
|
||||
}
|
||||
else {
|
||||
const tx = new TransactionImpl(fn, undefined);
|
||||
_globalTransaction = tx;
|
||||
try {
|
||||
fn(tx);
|
||||
}
|
||||
finally {
|
||||
tx.finish(); // During finish, more actions might be added to the transaction.
|
||||
// Which is why we only clear the global transaction after finish.
|
||||
_globalTransaction = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
/** @deprecated */
|
||||
export async function asyncTransaction(fn, getDebugName) {
|
||||
const tx = new TransactionImpl(fn, getDebugName);
|
||||
try {
|
||||
await fn(tx);
|
||||
}
|
||||
finally {
|
||||
tx.finish();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Allows to chain transactions.
|
||||
*/
|
||||
export function subtransaction(tx, fn, getDebugName) {
|
||||
if (!tx) {
|
||||
transaction(fn, getDebugName);
|
||||
}
|
||||
else {
|
||||
fn(tx);
|
||||
}
|
||||
}
|
||||
export class TransactionImpl {
|
||||
constructor(_fn, _getDebugName) {
|
||||
this._fn = _fn;
|
||||
this._getDebugName = _getDebugName;
|
||||
this._updatingObservers = [];
|
||||
getLogger()?.handleBeginTransaction(this);
|
||||
}
|
||||
getDebugName() {
|
||||
if (this._getDebugName) {
|
||||
return this._getDebugName();
|
||||
}
|
||||
return getFunctionName(this._fn);
|
||||
}
|
||||
updateObserver(observer, observable) {
|
||||
if (!this._updatingObservers) {
|
||||
// This happens when a transaction is used in a callback or async function.
|
||||
// If an async transaction is used, make sure the promise awaits all users of the transaction (e.g. no race).
|
||||
handleBugIndicatingErrorRecovery('Transaction already finished!');
|
||||
// Error recovery
|
||||
transaction(tx => {
|
||||
tx.updateObserver(observer, observable);
|
||||
});
|
||||
return;
|
||||
}
|
||||
// When this gets called while finish is active, they will still get considered
|
||||
this._updatingObservers.push({ observer, observable });
|
||||
observer.beginUpdate(observable);
|
||||
}
|
||||
finish() {
|
||||
const updatingObservers = this._updatingObservers;
|
||||
if (!updatingObservers) {
|
||||
handleBugIndicatingErrorRecovery('transaction.finish() has already been called!');
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < updatingObservers.length; i++) {
|
||||
const { observer, observable } = updatingObservers[i];
|
||||
observer.endUpdate(observable);
|
||||
}
|
||||
// Prevent anyone from updating observers from now on.
|
||||
this._updatingObservers = null;
|
||||
getLogger()?.handleEndTransaction(this);
|
||||
}
|
||||
debugGetUpdatingObservers() {
|
||||
return this._updatingObservers;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=transaction.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,54 @@
|
||||
import { transaction } from '../transaction.js';
|
||||
import { observableValue } from '../observables/observableValue.js';
|
||||
/**
|
||||
* A promise whose state is observable.
|
||||
*/
|
||||
export class ObservablePromise {
|
||||
constructor(promise) {
|
||||
this._value = observableValue(this, undefined);
|
||||
/**
|
||||
* The current state of the promise.
|
||||
* Is `undefined` if the promise didn't resolve yet.
|
||||
*/
|
||||
this.promiseResult = this._value;
|
||||
this.promise = promise.then(value => {
|
||||
transaction(tx => {
|
||||
/** @description onPromiseResolved */
|
||||
this._value.set(new PromiseResult(value, undefined), tx);
|
||||
});
|
||||
return value;
|
||||
}, error => {
|
||||
transaction(tx => {
|
||||
/** @description onPromiseRejected */
|
||||
this._value.set(new PromiseResult(undefined, error), tx);
|
||||
});
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
}
|
||||
export class PromiseResult {
|
||||
constructor(
|
||||
/**
|
||||
* The value of the resolved promise.
|
||||
* Undefined if the promise rejected.
|
||||
*/
|
||||
data,
|
||||
/**
|
||||
* The error in case of a rejected promise.
|
||||
* Undefined if the promise resolved.
|
||||
*/
|
||||
error) {
|
||||
this.data = data;
|
||||
this.error = error;
|
||||
}
|
||||
/**
|
||||
* Returns the value if the promise resolved, otherwise throws the error.
|
||||
*/
|
||||
getDataOrThrow() {
|
||||
if (this.error) {
|
||||
throw this.error;
|
||||
}
|
||||
return this.data;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=promise.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,57 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { cancelOnDispose } from '../commonFacade/cancellation.js';
|
||||
import { DisposableStore } from '../commonFacade/deps.js';
|
||||
import { autorunWithStoreHandleChanges } from '../reactions/autorun.js';
|
||||
export function runOnChange(observable, cb) {
|
||||
let _previousValue;
|
||||
let _firstRun = true;
|
||||
return autorunWithStoreHandleChanges({
|
||||
changeTracker: {
|
||||
createChangeSummary: () => ({ deltas: [], didChange: false }),
|
||||
handleChange: (context, changeSummary) => {
|
||||
if (context.didChange(observable)) {
|
||||
const e = context.change;
|
||||
if (e !== undefined) {
|
||||
changeSummary.deltas.push(e);
|
||||
}
|
||||
changeSummary.didChange = true;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
}
|
||||
}, (reader, changeSummary) => {
|
||||
const value = observable.read(reader);
|
||||
const previousValue = _previousValue;
|
||||
if (changeSummary.didChange) {
|
||||
_previousValue = value;
|
||||
// didChange can never be true on the first autorun, so we know previousValue is defined
|
||||
cb(value, previousValue, changeSummary.deltas);
|
||||
}
|
||||
if (_firstRun) {
|
||||
_firstRun = false;
|
||||
_previousValue = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
export function runOnChangeWithStore(observable, cb) {
|
||||
const store = new DisposableStore();
|
||||
const disposable = runOnChange(observable, (value, previousValue, deltas) => {
|
||||
store.clear();
|
||||
cb(value, previousValue, deltas, store);
|
||||
});
|
||||
return {
|
||||
dispose() {
|
||||
disposable.dispose();
|
||||
store.dispose();
|
||||
}
|
||||
};
|
||||
}
|
||||
export function runOnChangeWithCancellationToken(observable, cb) {
|
||||
return runOnChangeWithStore(observable, (value, previousValue, deltas, store) => {
|
||||
cb(value, previousValue, deltas, cancelOnDispose(store));
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=runOnChange.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,190 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { autorun } from '../reactions/autorun.js';
|
||||
import { DisposableStore, toDisposable } from '../commonFacade/deps.js';
|
||||
import { derived, derivedOpts } from '../observables/derived.js';
|
||||
import { observableFromEvent } from '../observables/observableFromEvent.js';
|
||||
import { observableSignal } from '../observables/observableSignal.js';
|
||||
import { _setKeepObserved, _setRecomputeInitiallyAndOnChange } from '../observables/baseObservable.js';
|
||||
/**
|
||||
* Creates an observable that debounces the input observable.
|
||||
*/
|
||||
export function debouncedObservable(observable, debounceMs) {
|
||||
let hasValue = false;
|
||||
let lastValue;
|
||||
let timeout = undefined;
|
||||
return observableFromEvent(cb => {
|
||||
const d = autorun(reader => {
|
||||
const value = observable.read(reader);
|
||||
if (!hasValue) {
|
||||
hasValue = true;
|
||||
lastValue = value;
|
||||
}
|
||||
else {
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
timeout = setTimeout(() => {
|
||||
lastValue = value;
|
||||
cb();
|
||||
}, debounceMs);
|
||||
}
|
||||
});
|
||||
return {
|
||||
dispose() {
|
||||
d.dispose();
|
||||
hasValue = false;
|
||||
lastValue = undefined;
|
||||
},
|
||||
};
|
||||
}, () => {
|
||||
if (hasValue) {
|
||||
return lastValue;
|
||||
}
|
||||
else {
|
||||
return observable.get();
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* This makes sure the observable is being observed and keeps its cache alive.
|
||||
*/
|
||||
export function keepObserved(observable) {
|
||||
const o = new KeepAliveObserver(false, undefined);
|
||||
observable.addObserver(o);
|
||||
return toDisposable(() => {
|
||||
observable.removeObserver(o);
|
||||
});
|
||||
}
|
||||
_setKeepObserved(keepObserved);
|
||||
/**
|
||||
* This converts the given observable into an autorun.
|
||||
*/
|
||||
export function recomputeInitiallyAndOnChange(observable, handleValue) {
|
||||
const o = new KeepAliveObserver(true, handleValue);
|
||||
observable.addObserver(o);
|
||||
try {
|
||||
o.beginUpdate(observable);
|
||||
}
|
||||
finally {
|
||||
o.endUpdate(observable);
|
||||
}
|
||||
return toDisposable(() => {
|
||||
observable.removeObserver(o);
|
||||
});
|
||||
}
|
||||
_setRecomputeInitiallyAndOnChange(recomputeInitiallyAndOnChange);
|
||||
export class KeepAliveObserver {
|
||||
constructor(_forceRecompute, _handleValue) {
|
||||
this._forceRecompute = _forceRecompute;
|
||||
this._handleValue = _handleValue;
|
||||
this._counter = 0;
|
||||
}
|
||||
beginUpdate(observable) {
|
||||
this._counter++;
|
||||
}
|
||||
endUpdate(observable) {
|
||||
if (this._counter === 1 && this._forceRecompute) {
|
||||
if (this._handleValue) {
|
||||
this._handleValue(observable.get());
|
||||
}
|
||||
else {
|
||||
observable.reportChanges();
|
||||
}
|
||||
}
|
||||
this._counter--;
|
||||
}
|
||||
handlePossibleChange(observable) {
|
||||
// NO OP
|
||||
}
|
||||
handleChange(observable, change) {
|
||||
// NO OP
|
||||
}
|
||||
}
|
||||
export function derivedObservableWithCache(owner, computeFn) {
|
||||
let lastValue = undefined;
|
||||
const observable = derivedOpts({ owner, debugReferenceFn: computeFn }, reader => {
|
||||
lastValue = computeFn(reader, lastValue);
|
||||
return lastValue;
|
||||
});
|
||||
return observable;
|
||||
}
|
||||
export function derivedObservableWithWritableCache(owner, computeFn) {
|
||||
let lastValue = undefined;
|
||||
const onChange = observableSignal('derivedObservableWithWritableCache');
|
||||
const observable = derived(owner, reader => {
|
||||
onChange.read(reader);
|
||||
lastValue = computeFn(reader, lastValue);
|
||||
return lastValue;
|
||||
});
|
||||
return Object.assign(observable, {
|
||||
clearCache: (tx) => {
|
||||
lastValue = undefined;
|
||||
onChange.trigger(tx);
|
||||
},
|
||||
setCache: (newValue, tx) => {
|
||||
lastValue = newValue;
|
||||
onChange.trigger(tx);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* When the items array changes, referential equal items are not mapped again.
|
||||
*/
|
||||
export function mapObservableArrayCached(owner, items, map, keySelector) {
|
||||
let m = new ArrayMap(map, keySelector);
|
||||
const self = derivedOpts({
|
||||
debugReferenceFn: map,
|
||||
owner,
|
||||
onLastObserverRemoved: () => {
|
||||
m.dispose();
|
||||
m = new ArrayMap(map);
|
||||
}
|
||||
}, (reader) => {
|
||||
m.setItems(items.read(reader));
|
||||
return m.getItems();
|
||||
});
|
||||
return self;
|
||||
}
|
||||
class ArrayMap {
|
||||
constructor(_map, _keySelector) {
|
||||
this._map = _map;
|
||||
this._keySelector = _keySelector;
|
||||
this._cache = new Map();
|
||||
this._items = [];
|
||||
}
|
||||
dispose() {
|
||||
this._cache.forEach(entry => entry.store.dispose());
|
||||
this._cache.clear();
|
||||
}
|
||||
setItems(items) {
|
||||
const newItems = [];
|
||||
const itemsToRemove = new Set(this._cache.keys());
|
||||
for (const item of items) {
|
||||
const key = this._keySelector ? this._keySelector(item) : item;
|
||||
let entry = this._cache.get(key);
|
||||
if (!entry) {
|
||||
const store = new DisposableStore();
|
||||
const out = this._map(item, store);
|
||||
entry = { out, store };
|
||||
this._cache.set(key, entry);
|
||||
}
|
||||
else {
|
||||
itemsToRemove.delete(key);
|
||||
}
|
||||
newItems.push(entry.out);
|
||||
}
|
||||
for (const item of itemsToRemove) {
|
||||
const entry = this._cache.get(item);
|
||||
entry.store.dispose();
|
||||
this._cache.delete(item);
|
||||
}
|
||||
this._items = newItems;
|
||||
}
|
||||
getItems() {
|
||||
return this._items;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=utils.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,60 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { CancellationError } from '../commonFacade/cancellation.js';
|
||||
import { autorun } from '../reactions/autorun.js';
|
||||
export function waitForState(observable, predicate, isError, cancellationToken) {
|
||||
if (!predicate) {
|
||||
predicate = state => state !== null && state !== undefined;
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
let isImmediateRun = true;
|
||||
let shouldDispose = false;
|
||||
const stateObs = observable.map(state => {
|
||||
/** @description waitForState.state */
|
||||
return {
|
||||
isFinished: predicate(state),
|
||||
error: isError ? isError(state) : false,
|
||||
state
|
||||
};
|
||||
});
|
||||
const d = autorun(reader => {
|
||||
/** @description waitForState */
|
||||
const { isFinished, error, state } = stateObs.read(reader);
|
||||
if (isFinished || error) {
|
||||
if (isImmediateRun) {
|
||||
// The variable `d` is not initialized yet
|
||||
shouldDispose = true;
|
||||
}
|
||||
else {
|
||||
d.dispose();
|
||||
}
|
||||
if (error) {
|
||||
reject(error === true ? state : error);
|
||||
}
|
||||
else {
|
||||
resolve(state);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (cancellationToken) {
|
||||
const dc = cancellationToken.onCancellationRequested(() => {
|
||||
d.dispose();
|
||||
dc.dispose();
|
||||
reject(new CancellationError());
|
||||
});
|
||||
if (cancellationToken.isCancellationRequested) {
|
||||
d.dispose();
|
||||
dc.dispose();
|
||||
reject(new CancellationError());
|
||||
return;
|
||||
}
|
||||
}
|
||||
isImmediateRun = false;
|
||||
if (shouldDispose) {
|
||||
d.dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=utilsCancellation.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,24 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { Event } from '../commonFacade/deps.js';
|
||||
import { observableFromEvent } from '../observables/observableFromEvent.js';
|
||||
export class ValueWithChangeEventFromObservable {
|
||||
constructor(observable) {
|
||||
this.observable = observable;
|
||||
}
|
||||
get onDidChange() {
|
||||
return Event.fromObservableLight(this.observable);
|
||||
}
|
||||
get value() {
|
||||
return this.observable.get();
|
||||
}
|
||||
}
|
||||
export function observableFromValueWithChangeEvent(owner, value) {
|
||||
if (value instanceof ValueWithChangeEventFromObservable) {
|
||||
return value.observable;
|
||||
}
|
||||
return observableFromEvent(owner, value.onDidChange, () => value.value);
|
||||
}
|
||||
//# sourceMappingURL=valueWithChangeEvent.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/observableInternal/utils/valueWithChangeEvent.ts","vs/base/common/observableInternal/utils/valueWithChangeEvent.ts"],"names":[],"mappings":"AAAA;;;gGAGgG;AAGhG,OAAO,EAAE,KAAK,EAAyB,MAAM,yBAAyB,CAAC;AAEvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AAE5E,MAAM,OAAO,kCAAkC;IAC9C,YAA4B,UAA0B;QAA1B,eAAU,GAAV,UAAU,CAAgB;IACtD,CAAC;IAED,IAAI,WAAW;QACd,OAAO,KAAK,CAAC,mBAAmB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACnD,CAAC;IAED,IAAI,KAAK;QACR,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC;IAC9B,CAAC;CACD;AAED,MAAM,UAAU,kCAAkC,CAAI,KAAiB,EAAE,KAA+B;IACvG,IAAI,KAAK,YAAY,kCAAkC,EAAE,CAAC;QACzD,OAAO,KAAK,CAAC,UAAU,CAAC;IACzB,CAAC;IACD,OAAO,mBAAmB,CAAC,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACzE,CAAC","file":"valueWithChangeEvent.js","sourceRoot":"file:///mnt/vss/_work/1/s/dependencies/vscode/out-editor-src","sourcesContent":["/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { IObservable } from '../base.js';\nimport { Event, IValueWithChangeEvent } from '../commonFacade/deps.js';\nimport { DebugOwner } from '../debugName.js';\nimport { observableFromEvent } from '../observables/observableFromEvent.js';\n\nexport class ValueWithChangeEventFromObservable<T> implements IValueWithChangeEvent<T> {\n\tconstructor(public readonly observable: IObservable<T>) {\n\t}\n\n\tget onDidChange(): Event<void> {\n\t\treturn Event.fromObservableLight(this.observable);\n\t}\n\n\tget value(): T {\n\t\treturn this.observable.get();\n\t}\n}\n\nexport function observableFromValueWithChangeEvent<T>(owner: DebugOwner, value: IValueWithChangeEvent<T>): IObservable<T> {\n\tif (value instanceof ValueWithChangeEventFromObservable) {\n\t\treturn value.observable;\n\t}\n\treturn observableFromEvent(owner, value.onDidChange, () => value.value);\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n\nimport { IObservable } from '../base.js';\nimport { Event, IValueWithChangeEvent } from '../commonFacade/deps.js';\nimport { DebugOwner } from '../debugName.js';\nimport { observableFromEvent } from '../observables/observableFromEvent.js';\n\nexport class ValueWithChangeEventFromObservable<T> implements IValueWithChangeEvent<T> {\n\tconstructor(public readonly observable: IObservable<T>) {\n\t}\n\n\tget onDidChange(): Event<void> {\n\t\treturn Event.fromObservableLight(this.observable);\n\t}\n\n\tget value(): T {\n\t\treturn this.observable.get();\n\t}\n}\n\nexport function observableFromValueWithChangeEvent<T>(owner: DebugOwner, value: IValueWithChangeEvent<T>): IObservable<T> {\n\tif (value instanceof ValueWithChangeEventFromObservable) {\n\t\treturn value.observable;\n\t}\n\treturn observableFromEvent(owner, value.onDidChange, () => value.value);\n}\n"]}
|
||||
Reference in New Issue
Block a user