@quick-game/cli
Version:
Command line interface for rapid qg development
942 lines • 37.6 kB
JavaScript
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
export class RemoteObject {
/**
* This may not be an interface due to "instanceof RemoteObject" checks in the code.
*/
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromLocalObject(value) {
return new LocalJSONObject(value);
}
static type(remoteObject) {
if (remoteObject === null) {
return 'null';
}
const type = typeof remoteObject;
if (type !== 'object' && type !== 'function') {
return type;
}
return remoteObject.type;
}
static isNullOrUndefined(remoteObject) {
if (remoteObject === undefined) {
return true;
}
switch (remoteObject.type) {
case "object" /* Protocol.Runtime.RemoteObjectType.Object */:
return remoteObject.subtype === "null" /* Protocol.Runtime.RemoteObjectSubtype.Null */;
case "undefined" /* Protocol.Runtime.RemoteObjectType.Undefined */:
return true;
default:
return false;
}
}
static arrayNameFromDescription(description) {
return description.replace(_descriptionLengthParenRegex, '').replace(_descriptionLengthSquareRegex, '');
}
static arrayLength(object) {
if (object.subtype !== 'array' && object.subtype !== 'typedarray') {
return 0;
}
// Array lengths in V8-generated descriptions switched from square brackets to parentheses.
// Both formats are checked in case the front end is dealing with an old version of V8.
const parenMatches = object.description && object.description.match(_descriptionLengthParenRegex);
const squareMatches = object.description && object.description.match(_descriptionLengthSquareRegex);
return parenMatches ? parseInt(parenMatches[1], 10) : (squareMatches ? parseInt(squareMatches[1], 10) : 0);
}
static arrayBufferByteLength(object) {
if (object.subtype !== 'arraybuffer') {
return 0;
}
const matches = object.description && object.description.match(_descriptionLengthParenRegex);
return matches ? parseInt(matches[1], 10) : 0;
}
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static unserializableDescription(object) {
const type = typeof object;
if (type === 'number') {
const description = String(object);
if (object === 0 && 1 / object < 0) {
return "-0" /* UnserializableNumber.Negative0 */;
}
if (description === "NaN" /* UnserializableNumber.NaN */ || description === "Infinity" /* UnserializableNumber.Infinity */ ||
description === "-Infinity" /* UnserializableNumber.NegativeInfinity */) {
return description;
}
}
if (type === 'bigint') {
return object + 'n';
}
return null;
}
static toCallArgument(object) {
const type = typeof object;
if (type === 'undefined') {
return {};
}
const unserializableDescription = RemoteObject.unserializableDescription(object);
if (type === 'number') {
if (unserializableDescription !== null) {
return { unserializableValue: unserializableDescription };
}
return { value: object };
}
if (type === 'bigint') {
return { unserializableValue: unserializableDescription };
}
if (type === 'string' || type === 'boolean') {
return { value: object };
}
if (!object) {
return { value: null };
}
// The unserializableValue is a function on RemoteObject's and a simple property on
// Protocol.Runtime.RemoteObject's.
const objectAsProtocolRemoteObject = object;
if (object instanceof RemoteObject) {
const unserializableValue = object.unserializableValue();
if (unserializableValue !== undefined) {
return { unserializableValue: unserializableValue };
}
}
else if (objectAsProtocolRemoteObject.unserializableValue !== undefined) {
return { unserializableValue: objectAsProtocolRemoteObject.unserializableValue };
}
if (typeof objectAsProtocolRemoteObject.objectId !== 'undefined') {
return { objectId: objectAsProtocolRemoteObject.objectId };
}
return { value: objectAsProtocolRemoteObject.value };
}
static async loadFromObjectPerProto(object, generatePreview, nonIndexedPropertiesOnly = false) {
const result = await Promise.all([
object.getAllProperties(true /* accessorPropertiesOnly */, generatePreview, nonIndexedPropertiesOnly),
object.getOwnProperties(generatePreview, nonIndexedPropertiesOnly),
]);
const accessorProperties = result[0].properties;
const ownProperties = result[1].properties;
const internalProperties = result[1].internalProperties;
if (!ownProperties || !accessorProperties) {
return { properties: null, internalProperties: null };
}
const propertiesMap = new Map();
const propertySymbols = [];
for (let i = 0; i < accessorProperties.length; i++) {
const property = accessorProperties[i];
if (property.symbol) {
propertySymbols.push(property);
}
else if (property.isOwn || property.name !== '__proto__') {
// TODO(crbug/1076820): Eventually we should move away from
// showing accessor #properties directly on the receiver.
propertiesMap.set(property.name, property);
}
}
for (let i = 0; i < ownProperties.length; i++) {
const property = ownProperties[i];
if (property.isAccessorProperty()) {
continue;
}
if (property.private || property.symbol) {
propertySymbols.push(property);
}
else {
propertiesMap.set(property.name, property);
}
}
return {
properties: [...propertiesMap.values()].concat(propertySymbols),
internalProperties: internalProperties ? internalProperties : null,
};
}
customPreview() {
return null;
}
get objectId() {
// TODO(crbug.com/1226471): Return undefined here.
return 'Not implemented';
}
get type() {
throw 'Not implemented';
}
get subtype() {
throw 'Not implemented';
}
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
// eslint-disable-next-line @typescript-eslint/no-explicit-any
get value() {
throw 'Not implemented';
}
unserializableValue() {
throw 'Not implemented';
}
get description() {
throw 'Not implemented';
}
set description(description) {
throw 'Not implemented';
}
get hasChildren() {
throw 'Not implemented';
}
get preview() {
return undefined;
}
get className() {
return null;
}
arrayLength() {
throw 'Not implemented';
}
arrayBufferByteLength() {
throw 'Not implemented';
}
getOwnProperties(_generatePreview, _nonIndexedPropertiesOnly) {
throw 'Not implemented';
}
getAllProperties(_accessorPropertiesOnly, _generatePreview, _nonIndexedPropertiesOnly) {
throw 'Not implemented';
}
async deleteProperty(_name) {
throw 'Not implemented';
}
async setPropertyValue(_name, _value) {
throw 'Not implemented';
}
callFunction(_functionDeclaration, _args) {
throw 'Not implemented';
}
callFunctionJSON(_functionDeclaration, _args) {
throw 'Not implemented';
}
release() {
}
debuggerModel() {
throw new Error('DebuggerModel-less object');
}
runtimeModel() {
throw new Error('RuntimeModel-less object');
}
isNode() {
return false;
}
webIdl;
}
export class RemoteObjectImpl extends RemoteObject {
runtimeModelInternal;
#runtimeAgent;
#typeInternal;
#subtypeInternal;
#objectIdInternal;
#descriptionInternal;
hasChildrenInternal;
#previewInternal;
#unserializableValueInternal;
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
// eslint-disable-next-line @typescript-eslint/no-explicit-any
#valueInternal;
#customPreviewInternal;
#classNameInternal;
constructor(runtimeModel, objectId, type,
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
// eslint-disable-next-line @typescript-eslint/no-explicit-any
subtype, value, unserializableValue, description, preview, customPreview, className) {
super();
this.runtimeModelInternal = runtimeModel;
this.#runtimeAgent = runtimeModel.target().runtimeAgent();
this.#typeInternal = type;
this.#subtypeInternal = subtype;
if (objectId) {
// handle
this.#objectIdInternal = objectId;
this.#descriptionInternal = description;
this.hasChildrenInternal = (type !== 'symbol');
this.#previewInternal = preview;
}
else {
this.#descriptionInternal = description;
if (!this.description && unserializableValue) {
this.#descriptionInternal = unserializableValue;
}
if (!this.#descriptionInternal && (typeof value !== 'object' || value === null)) {
this.#descriptionInternal = String(value);
}
this.hasChildrenInternal = false;
if (typeof unserializableValue === 'string') {
this.#unserializableValueInternal = unserializableValue;
if (unserializableValue === "Infinity" /* UnserializableNumber.Infinity */ ||
unserializableValue === "-Infinity" /* UnserializableNumber.NegativeInfinity */ ||
unserializableValue === "-0" /* UnserializableNumber.Negative0 */ ||
unserializableValue === "NaN" /* UnserializableNumber.NaN */) {
this.#valueInternal = Number(unserializableValue);
}
else if (type === 'bigint' && unserializableValue.endsWith('n')) {
this.#valueInternal = BigInt(unserializableValue.substring(0, unserializableValue.length - 1));
}
else {
this.#valueInternal = unserializableValue;
}
}
else {
this.#valueInternal = value;
}
}
this.#customPreviewInternal = customPreview || null;
this.#classNameInternal = typeof className === 'string' ? className : null;
}
customPreview() {
return this.#customPreviewInternal;
}
get objectId() {
return this.#objectIdInternal;
}
get type() {
return this.#typeInternal;
}
get subtype() {
return this.#subtypeInternal;
}
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
// eslint-disable-next-line @typescript-eslint/no-explicit-any
get value() {
return this.#valueInternal;
}
unserializableValue() {
return this.#unserializableValueInternal;
}
get description() {
return this.#descriptionInternal;
}
set description(description) {
this.#descriptionInternal = description;
}
get hasChildren() {
return this.hasChildrenInternal;
}
get preview() {
return this.#previewInternal;
}
get className() {
return this.#classNameInternal;
}
getOwnProperties(generatePreview, nonIndexedPropertiesOnly = false) {
return this.doGetProperties(true, false, nonIndexedPropertiesOnly, generatePreview);
}
getAllProperties(accessorPropertiesOnly, generatePreview, nonIndexedPropertiesOnly = false) {
return this.doGetProperties(false, accessorPropertiesOnly, nonIndexedPropertiesOnly, generatePreview);
}
async createRemoteObject(object) {
return this.runtimeModelInternal.createRemoteObject(object);
}
async doGetProperties(ownProperties, accessorPropertiesOnly, nonIndexedPropertiesOnly, generatePreview) {
if (!this.#objectIdInternal) {
return { properties: null, internalProperties: null };
}
const response = await this.#runtimeAgent.invoke_getProperties({
objectId: this.#objectIdInternal,
ownProperties,
accessorPropertiesOnly,
nonIndexedPropertiesOnly,
generatePreview,
});
if (response.getError()) {
return { properties: null, internalProperties: null };
}
if (response.exceptionDetails) {
this.runtimeModelInternal.exceptionThrown(Date.now(), response.exceptionDetails);
return { properties: null, internalProperties: null };
}
const { result: properties = [], internalProperties = [], privateProperties = [] } = response;
const result = [];
for (const property of properties) {
const propertyValue = property.value ? await this.createRemoteObject(property.value) : null;
const propertySymbol = property.symbol ? this.runtimeModelInternal.createRemoteObject(property.symbol) : null;
const remoteProperty = new RemoteObjectProperty(property.name, propertyValue, Boolean(property.enumerable), Boolean(property.writable), Boolean(property.isOwn), Boolean(property.wasThrown), propertySymbol);
if (typeof property.value === 'undefined') {
if (property.get && property.get.type !== 'undefined') {
remoteProperty.getter = this.runtimeModelInternal.createRemoteObject(property.get);
}
if (property.set && property.set.type !== 'undefined') {
remoteProperty.setter = this.runtimeModelInternal.createRemoteObject(property.set);
}
}
result.push(remoteProperty);
}
for (const property of privateProperties) {
const propertyValue = property.value ? this.runtimeModelInternal.createRemoteObject(property.value) : null;
const remoteProperty = new RemoteObjectProperty(property.name, propertyValue, true, true, true, false, undefined, false, undefined, true);
if (typeof property.value === 'undefined') {
if (property.get && property.get.type !== 'undefined') {
remoteProperty.getter = this.runtimeModelInternal.createRemoteObject(property.get);
}
if (property.set && property.set.type !== 'undefined') {
remoteProperty.setter = this.runtimeModelInternal.createRemoteObject(property.set);
}
}
result.push(remoteProperty);
}
const internalPropertiesResult = [];
for (const property of internalProperties) {
if (!property.value) {
continue;
}
if (property.name === '[[StableObjectId]]') {
continue;
}
const propertyValue = this.runtimeModelInternal.createRemoteObject(property.value);
internalPropertiesResult.push(new RemoteObjectProperty(property.name, propertyValue, true, false, undefined, undefined, undefined, true));
}
return { properties: result, internalProperties: internalPropertiesResult };
}
async setPropertyValue(name, value) {
if (!this.#objectIdInternal) {
return 'Can’t set a property of non-object.';
}
const response = await this.#runtimeAgent.invoke_evaluate({ expression: value, silent: true });
if (response.getError() || response.exceptionDetails) {
return response.getError() ||
(response.result.type !== 'string' ? response.result.description : response.result.value);
}
if (typeof name === 'string') {
name = RemoteObject.toCallArgument(name);
}
const resultPromise = this.doSetObjectPropertyValue(response.result, name);
if (response.result.objectId) {
void this.#runtimeAgent.invoke_releaseObject({ objectId: response.result.objectId });
}
return resultPromise;
}
async doSetObjectPropertyValue(result, name) {
// This assignment may be for a regular (data) property, and for an accessor property (with getter/setter).
// Note the sensitive matter about accessor property: the property may be physically defined in some proto object,
// but logically it is bound to the object in question. JavaScript passes this object to getters/setters, not the object
// where property was defined; so do we.
const setPropertyValueFunction = 'function(a, b) { this[a] = b; }';
const argv = [name, RemoteObject.toCallArgument(result)];
const response = await this.#runtimeAgent.invoke_callFunctionOn({
objectId: this.#objectIdInternal,
functionDeclaration: setPropertyValueFunction,
arguments: argv,
silent: true,
});
const error = response.getError();
return error || response.exceptionDetails ? error || response.result.description : undefined;
}
async deleteProperty(name) {
if (!this.#objectIdInternal) {
return 'Can’t delete a property of non-object.';
}
const deletePropertyFunction = 'function(a) { delete this[a]; return !(a in this); }';
const response = await this.#runtimeAgent.invoke_callFunctionOn({
objectId: this.#objectIdInternal,
functionDeclaration: deletePropertyFunction,
arguments: [name],
silent: true,
});
if (response.getError() || response.exceptionDetails) {
return response.getError() || response.result.description;
}
if (!response.result.value) {
return 'Failed to delete property.';
}
return undefined;
}
async callFunction(functionDeclaration, args) {
const response = await this.#runtimeAgent.invoke_callFunctionOn({
objectId: this.#objectIdInternal,
functionDeclaration: functionDeclaration.toString(),
arguments: args,
silent: true,
});
if (response.getError()) {
return { object: null, wasThrown: false };
}
// TODO: release exceptionDetails object
return {
object: this.runtimeModelInternal.createRemoteObject(response.result),
wasThrown: Boolean(response.exceptionDetails),
};
}
async callFunctionJSON(functionDeclaration, args) {
const response = await this.#runtimeAgent.invoke_callFunctionOn({
objectId: this.#objectIdInternal,
functionDeclaration: functionDeclaration.toString(),
arguments: args,
silent: true,
returnByValue: true,
});
return response.getError() || response.exceptionDetails ? null : response.result.value;
}
release() {
if (!this.#objectIdInternal) {
return;
}
void this.#runtimeAgent.invoke_releaseObject({ objectId: this.#objectIdInternal });
}
arrayLength() {
return RemoteObject.arrayLength(this);
}
arrayBufferByteLength() {
return RemoteObject.arrayBufferByteLength(this);
}
debuggerModel() {
return this.runtimeModelInternal.debuggerModel();
}
runtimeModel() {
return this.runtimeModelInternal;
}
isNode() {
return Boolean(this.#objectIdInternal) && this.type === 'object' && this.subtype === 'node';
}
}
export class ScopeRemoteObject extends RemoteObjectImpl {
#scopeRef;
#savedScopeProperties;
constructor(runtimeModel, objectId, scopeRef, type,
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
// eslint-disable-next-line @typescript-eslint/no-explicit-any
subtype, value, unserializableValue, description, preview) {
super(runtimeModel, objectId, type, subtype, value, unserializableValue, description, preview);
this.#scopeRef = scopeRef;
this.#savedScopeProperties = undefined;
}
async doGetProperties(ownProperties, accessorPropertiesOnly, _generatePreview) {
if (accessorPropertiesOnly) {
return { properties: [], internalProperties: [] };
}
if (this.#savedScopeProperties) {
// No need to reload scope variables, as the remote object never
// changes its #properties. If variable is updated, the #properties
// array is patched locally.
return { properties: this.#savedScopeProperties.slice(), internalProperties: null };
}
const allProperties = await super.doGetProperties(ownProperties, accessorPropertiesOnly, false /* nonIndexedPropertiesOnly */, true /* generatePreview */);
if (this.#scopeRef && Array.isArray(allProperties.properties)) {
this.#savedScopeProperties = allProperties.properties.slice();
if (!this.#scopeRef.callFrameId) {
for (const property of this.#savedScopeProperties) {
property.writable = false;
}
}
}
return allProperties;
}
async doSetObjectPropertyValue(result, argumentName) {
const name = argumentName.value;
const error = await this.debuggerModel().setVariableValue(this.#scopeRef.number, name, RemoteObject.toCallArgument(result), this.#scopeRef.callFrameId);
if (error) {
return error;
}
if (this.#savedScopeProperties) {
for (const property of this.#savedScopeProperties) {
if (property.name === name) {
property.value = this.runtimeModel().createRemoteObject(result);
}
}
}
return;
}
}
export class ScopeRef {
number;
callFrameId;
constructor(number, callFrameId) {
this.number = number;
this.callFrameId = callFrameId;
}
}
export class RemoteObjectProperty {
name;
value;
enumerable;
writable;
isOwn;
wasThrown;
symbol;
synthetic;
syntheticSetter;
private;
getter;
setter;
webIdl;
constructor(name, value, enumerable, writable, isOwn, wasThrown, symbol, synthetic, syntheticSetter, isPrivate) {
this.name = name;
this.value = value !== null ? value : undefined;
this.enumerable = typeof enumerable !== 'undefined' ? enumerable : true;
const isNonSyntheticOrSyntheticWritable = !synthetic || Boolean(syntheticSetter);
this.writable = typeof writable !== 'undefined' ? writable : isNonSyntheticOrSyntheticWritable;
this.isOwn = Boolean(isOwn);
this.wasThrown = Boolean(wasThrown);
if (symbol) {
this.symbol = symbol;
}
this.synthetic = Boolean(synthetic);
if (syntheticSetter) {
this.syntheticSetter = syntheticSetter;
}
this.private = Boolean(isPrivate);
}
async setSyntheticValue(expression) {
if (!this.syntheticSetter) {
return false;
}
const result = await this.syntheticSetter(expression);
if (result) {
this.value = result;
}
return Boolean(result);
}
isAccessorProperty() {
return Boolean(this.getter || this.setter);
}
match({ includeNullOrUndefinedValues, regex }) {
if (regex !== null) {
if (!regex.test(this.name) && !regex.test(this.value?.description ?? '')) {
return false;
}
}
if (!includeNullOrUndefinedValues) {
if (!this.isAccessorProperty() && RemoteObject.isNullOrUndefined(this.value)) {
return false;
}
}
return true;
}
cloneWithNewName(newName) {
const property = new RemoteObjectProperty(newName, this.value ?? null, this.enumerable, this.writable, this.isOwn, this.wasThrown, this.symbol, this.synthetic, this.syntheticSetter, this.private);
property.getter = this.getter;
property.setter = this.setter;
return property;
}
}
// Below is a wrapper around a local object that implements the RemoteObject interface,
// which can be used by the UI code (primarily ObjectPropertiesSection).
// Note that only JSON-compliant objects are currently supported, as there's no provision
// for traversing prototypes, extracting class names via constructor, handling #properties
// or functions.
export class LocalJSONObject extends RemoteObject {
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
// eslint-disable-next-line @typescript-eslint/no-explicit-any
valueInternal;
#cachedDescription;
#cachedChildren;
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
// eslint-disable-next-line @typescript-eslint/no-explicit-any
constructor(value) {
super();
this.valueInternal = value;
}
get objectId() {
return undefined;
}
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
// eslint-disable-next-line @typescript-eslint/no-explicit-any
get value() {
return this.valueInternal;
}
unserializableValue() {
const unserializableDescription = RemoteObject.unserializableDescription(this.valueInternal);
return unserializableDescription || undefined;
}
get description() {
if (this.#cachedDescription) {
return this.#cachedDescription;
}
function formatArrayItem(property) {
return this.formatValue(property.value || null);
}
function formatObjectItem(property) {
let name = property.name;
if (/^\s|\s$|^$|\n/.test(name)) {
name = '"' + name.replace(/\n/g, '\u21B5') + '"';
}
return name + ': ' + this.formatValue(property.value || null);
}
if (this.type === 'object') {
switch (this.subtype) {
case 'array':
this.#cachedDescription = this.concatenate('[', ']', formatArrayItem.bind(this));
break;
case 'date':
this.#cachedDescription = String(this.valueInternal);
break;
case 'null':
this.#cachedDescription = 'null';
break;
default:
this.#cachedDescription = this.concatenate('{', '}', formatObjectItem.bind(this));
}
}
else {
this.#cachedDescription = String(this.valueInternal);
}
return this.#cachedDescription;
}
formatValue(value) {
if (!value) {
return 'undefined';
}
const description = value.description || '';
if (value.type === 'string') {
return '"' + description.replace(/\n/g, '\u21B5') + '"';
}
return description;
}
concatenate(prefix, suffix, formatProperty) {
const previewChars = 100;
let buffer = prefix;
const children = this.children();
for (let i = 0; i < children.length; ++i) {
const itemDescription = formatProperty(children[i]);
if (buffer.length + itemDescription.length > previewChars) {
buffer += ',…';
break;
}
if (i) {
buffer += ', ';
}
buffer += itemDescription;
}
buffer += suffix;
return buffer;
}
get type() {
return typeof this.valueInternal;
}
get subtype() {
if (this.valueInternal === null) {
return 'null';
}
if (Array.isArray(this.valueInternal)) {
return 'array';
}
if (this.valueInternal instanceof Date) {
return 'date';
}
return undefined;
}
get hasChildren() {
if ((typeof this.valueInternal !== 'object') || (this.valueInternal === null)) {
return false;
}
return Boolean(Object.keys(this.valueInternal).length);
}
async getOwnProperties(_generatePreview, nonIndexedPropertiesOnly = false) {
function isArrayIndex(name) {
const index = Number(name) >>> 0;
return String(index) === name;
}
let properties = this.children();
if (nonIndexedPropertiesOnly) {
properties = properties.filter(property => !isArrayIndex(property.name));
}
return { properties, internalProperties: null };
}
async getAllProperties(accessorPropertiesOnly, generatePreview, nonIndexedPropertiesOnly = false) {
if (accessorPropertiesOnly) {
return { properties: [], internalProperties: null };
}
return await this.getOwnProperties(generatePreview, nonIndexedPropertiesOnly);
}
children() {
if (!this.hasChildren) {
return [];
}
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const value = this.valueInternal;
function buildProperty(propName) {
let propValue = value[propName];
if (!(propValue instanceof RemoteObject)) {
propValue = RemoteObject.fromLocalObject(propValue);
}
return new RemoteObjectProperty(propName, propValue);
}
if (!this.#cachedChildren) {
this.#cachedChildren = Object.keys(value).map(buildProperty);
}
return this.#cachedChildren;
}
arrayLength() {
return Array.isArray(this.valueInternal) ? this.valueInternal.length : 0;
}
async callFunction(functionDeclaration, args) {
const target = this.valueInternal;
const rawArgs = args ? args.map(arg => arg.value) : [];
let result;
let wasThrown = false;
try {
result = functionDeclaration.apply(target, rawArgs);
}
catch (e) {
wasThrown = true;
}
const object = RemoteObject.fromLocalObject(result);
return { object, wasThrown };
}
async callFunctionJSON(functionDeclaration, args) {
const target = this.valueInternal;
const rawArgs = args ? args.map(arg => arg.value) : [];
let result;
try {
result = functionDeclaration.apply(target, rawArgs);
}
catch (e) {
result = null;
}
return result;
}
}
export class RemoteArrayBuffer {
#objectInternal;
constructor(object) {
if (object.type !== 'object' || object.subtype !== 'arraybuffer') {
throw new Error('Object is not an arraybuffer');
}
this.#objectInternal = object;
}
byteLength() {
return this.#objectInternal.arrayBufferByteLength();
}
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async bytes(start = 0, end = this.byteLength()) {
if (start < 0 || start >= this.byteLength()) {
throw new RangeError('start is out of range');
}
if (end < start || end > this.byteLength()) {
throw new RangeError('end is out of range');
}
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
// @ts-expect-error
return await this.#objectInternal.callFunctionJSON(bytes, [{ value: start }, { value: end - start }]);
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function bytes(offset, length) {
return [...new Uint8Array(this, offset, length)];
}
}
object() {
return this.#objectInternal;
}
}
export class RemoteArray {
#objectInternal;
constructor(object) {
this.#objectInternal = object;
}
static objectAsArray(object) {
if (!object || object.type !== 'object' || (object.subtype !== 'array' && object.subtype !== 'typedarray')) {
throw new Error('Object is empty or not an array');
}
return new RemoteArray(object);
}
static createFromRemoteObjects(objects) {
if (!objects.length) {
throw new Error('Input array is empty');
}
const objectArguments = [];
for (let i = 0; i < objects.length; ++i) {
objectArguments.push(RemoteObject.toCallArgument(objects[i]));
}
return objects[0].callFunction(createArray, objectArguments).then(returnRemoteArray);
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function createArray() {
if (arguments.length > 1) {
return new Array(arguments);
}
return [arguments[0]];
}
function returnRemoteArray(result) {
if (result.wasThrown || !result.object) {
throw new Error('Call function throws exceptions or returns empty value');
}
return RemoteArray.objectAsArray(result.object);
}
}
at(index) {
if (index < 0 || index > this.#objectInternal.arrayLength()) {
throw new Error('Out of range');
}
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
// @ts-expect-error
return this.#objectInternal.callFunction(at, [RemoteObject.toCallArgument(index)]).then(assertCallFunctionResult);
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function at(index) {
return this[index];
}
function assertCallFunctionResult(result) {
if (result.wasThrown || !result.object) {
throw new Error('Exception in callFunction or result value is empty');
}
return result.object;
}
}
length() {
return this.#objectInternal.arrayLength();
}
map(func) {
const promises = [];
for (let i = 0; i < this.length(); ++i) {
promises.push(this.at(i).then(func));
}
return Promise.all(promises);
}
object() {
return this.#objectInternal;
}
}
export class RemoteFunction {
#objectInternal;
constructor(object) {
this.#objectInternal = object;
}
static objectAsFunction(object) {
if (!object || object.type !== 'function') {
throw new Error('Object is empty or not a function');
}
return new RemoteFunction(object);
}
targetFunction() {
return this.#objectInternal.getOwnProperties(false /* generatePreview */).then(targetFunction.bind(this));
function targetFunction(ownProperties) {
if (!ownProperties.internalProperties) {
return this.#objectInternal;
}
const internalProperties = ownProperties.internalProperties;
for (const property of internalProperties) {
if (property.name === '[[TargetFunction]]') {
return property.value;
}
}
return this.#objectInternal;
}
}
targetFunctionDetails() {
return this.targetFunction().then(functionDetails.bind(this));
function functionDetails(targetFunction) {
const boundReleaseFunctionDetails = releaseTargetFunction.bind(null, this.#objectInternal !== targetFunction ? targetFunction : null);
return targetFunction.debuggerModel().functionDetailsPromise(targetFunction).then(boundReleaseFunctionDetails);
}
function releaseTargetFunction(targetFunction, functionDetails) {
if (targetFunction) {
targetFunction.release();
}
return functionDetails;
}
}
object() {
return this.#objectInternal;
}
}
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
// eslint-disable-next-line @typescript-eslint/naming-convention
const _descriptionLengthParenRegex = /\(([0-9]+)\)/;
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
// eslint-disable-next-line @typescript-eslint/naming-convention
const _descriptionLengthSquareRegex = /\[([0-9]+)\]/;
//# sourceMappingURL=RemoteObject.js.map