monaco-editor-core
Version:
A browser based code editor
333 lines • 10.8 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* 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 = [];
// eslint-disable-next-line local/code-no-any-casts
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