prepack
Version:
Execute a JS bundle, serialize global state and side effects to a snapshot that can be quickly restored.
260 lines (205 loc) • 7.76 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.VariableManager = void 0;
var _ReferenceMap = require("./ReferenceMap.js");
var _environment = require("./../../environment.js");
var _index = require("./../../values/index.js");
var _invariant = _interopRequireDefault(require("./../common/invariant.js"));
var _is = require("./../../methods/is.js");
var _DebuggerError = require("./../common/DebuggerError.js");
var _singletons = require("./../../singletons.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
/* strict-local */
// This class manages the handling of variable requests in the debugger
// The DebugProtocol specifies collections of variables are to be fetched using a
// unique reference ID called a variablesReference. This class can generate new
// variablesReferences to pass to the UI and then perform lookups for those
// variablesReferences when they are requested.
class VariableManager {
constructor(realm) {
this._containerCache = new Map();
this._referenceMap = new _ReferenceMap.ReferenceMap();
this._realm = realm;
} // cache for created references
// Given a container, either returns a cached reference for that container if
// it exists or return a new reference
getReferenceForValue(value) {
let cachedRef = this._containerCache.get(value);
if (cachedRef !== undefined) {
return cachedRef;
}
let varRef = this._referenceMap.add(value);
this._containerCache.set(value, varRef);
return varRef;
} // The entry point for retrieving a collection of variables by a reference
getVariablesByReference(reference) {
let container = this._referenceMap.get(reference);
if (!container) return [];
if (container instanceof _environment.LexicalEnvironment) {
return this._getVariablesFromEnvRecord(container.environmentRecord);
} else if (container instanceof _index.ObjectValue) {
return this._getVariablesFromObject(container);
} else if (container instanceof _index.AbstractValue) {
return this._getAbstractValueContent(container);
} else {
(0, _invariant.default)(false, "Invalid variable container");
}
}
_getVariablesFromObject(object) {
let variables = [];
let names = object.properties.keys();
for (let name of names) {
let binding = object.properties.get(name);
(0, _invariant.default)(binding !== undefined);
if (binding.descriptor) {
if ((0, _is.IsDataDescriptor)(this._realm, binding.descriptor)) {
let value = binding.descriptor.value;
if (value instanceof _index.Value) {
let variable = this._getVariableFromValue(name, value);
variables.push(variable);
}
}
}
}
return variables;
}
_getAbstractValueContent(value) {
let kindVar = {
name: "kind",
value: value.kind || "undefined",
variablesReference: 0
};
let contents = [kindVar];
let argCount = 1;
for (let arg of value.args) {
contents.push(this._getVariableFromValue("arg-" + argCount, arg));
argCount++;
}
return contents;
}
_getVariablesFromEnvRecord(envRecord) {
if (envRecord instanceof _environment.DeclarativeEnvironmentRecord) {
return this._getVariablesFromDeclarativeEnv(envRecord);
} else if (envRecord instanceof _environment.ObjectEnvironmentRecord) {
if (envRecord.object instanceof _index.ObjectValue) {
return this._getVariablesFromObject(envRecord.object);
} else if (envRecord.object instanceof _index.AbstractObjectValue) {
// TODO: call _getVariablesFromAbstractObject when it is implemented
return [];
} else {
(0, _invariant.default)(false, "Invalid type of object environment record");
}
} else if (envRecord instanceof _environment.GlobalEnvironmentRecord) {
let declVars = this._getVariablesFromEnvRecord(envRecord.$DeclarativeRecord);
let objVars = this._getVariablesFromEnvRecord(envRecord.$ObjectRecord);
return declVars.concat(objVars);
} else {
(0, _invariant.default)(false, "Invalid type of environment record");
}
}
_getVariablesFromDeclarativeEnv(env) {
let variables = [];
let bindings = env.bindings;
for (let name in bindings) {
let binding = bindings[name];
if (binding.value) {
let variable = this._getVariableFromValue(name, binding.value);
variables.push(variable);
}
}
return variables;
}
_getVariableFromValue(name, value) {
if (value instanceof _index.ConcreteValue) {
return this._getVariableFromConcreteValue(name, value);
} else if (value instanceof _index.AbstractValue) {
return this._getVariableFromAbstractValue(name, value);
} else {
(0, _invariant.default)(false, "Value is neither concrete nor abstract");
}
}
_getVariableFromAbstractValue(name, value) {
let variable = {
name: name,
value: this._getAbstractValueDisplay(value),
variablesReference: this.getReferenceForValue(value)
};
return variable;
}
_getAbstractValueDisplay(value) {
if (value.intrinsicName !== undefined && !value.intrinsicName.startsWith("_")) {
return value.intrinsicName;
}
return "Abstract " + value.types.getType().name;
}
_getVariableFromConcreteValue(name, value) {
if (value instanceof _index.PrimitiveValue) {
let variable = {
name: name,
value: value.toDisplayString(),
variablesReference: 0
};
return variable;
} else if (value instanceof _index.ObjectValue) {
let variable = {
name: name,
value: value.getKind(),
variablesReference: this.getReferenceForValue(value)
};
return variable;
} else {
(0, _invariant.default)(false, "Concrete value must be primitive or object");
}
}
evaluate(frameId, expression) {
let evalRealm = this._realm;
let isDirect = false;
let isStrict = false;
if (frameId !== undefined) {
if (frameId < 0 || frameId >= this._realm.contextStack.length) {
throw new _DebuggerError.DebuggerError("Invalid command", "Invalid value for frame ID");
} // frameId's are in reverse order of context stack
let stackIndex = this._realm.contextStack.length - 1 - frameId;
let context = this._realm.contextStack[stackIndex];
isDirect = true;
isStrict = true;
evalRealm = context.realm;
}
let evalString = new _index.StringValue(this._realm, expression);
try {
let value = _singletons.Functions.PerformEval(this._realm, evalString, evalRealm, isStrict, isDirect);
let varInfo = this._getVariableFromValue(expression, value);
let result = {
kind: "evaluate",
displayValue: varInfo.value,
type: value.getType().name,
variablesReference: varInfo.variablesReference
};
return result;
} catch (e) {
let result = {
kind: "evaluate",
displayValue: `Failed to evaluate: ${expression}`,
type: "unknown",
variablesReference: 0
};
return result;
}
}
clean() {
this._containerCache = new Map();
this._referenceMap.clean();
}
}
exports.VariableManager = VariableManager;
//# sourceMappingURL=VariableManager.js.map