mirror of
https://github.com/react/react-native-devtools-frontend.git
synced 2026-09-28 13:13:37 +08:00
Add one more deps "@typescript-eslint/utils" to top level to be used in our own custom rules (also needed override if I didn't). Bug: none Change-Id: I130415d1ec5f096ca51200df3eb688dadd963d0f Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6343232 Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Commit-Queue: Nikolay Vitkov <nvitkov@chromium.org>
251 lines
8.3 KiB
TypeScript
251 lines
8.3 KiB
TypeScript
// Copyright 2023 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.
|
|
|
|
import type {Chrome} from '../../../extension-api/ExtensionAPI.js';
|
|
import type {Value, WasmInterface} from '../src/CustomFormatters.js';
|
|
import {WorkerPlugin} from '../src/DevToolsPluginHost.js';
|
|
import type {WasmValue} from '../src/WasmTypes.js';
|
|
import type {HostInterface} from '../src/WorkerRPC.js';
|
|
|
|
import type {Debugger} from './RealBackend.js';
|
|
|
|
export class TestHostInterface implements HostInterface {
|
|
getWasmLinearMemory(_offset: number, _length: number, _stopId: unknown): ArrayBuffer {
|
|
throw new Error('Method not implemented.');
|
|
}
|
|
getWasmLocal(_local: number, _stopId: unknown): WasmValue {
|
|
throw new Error('Method not implemented.');
|
|
}
|
|
getWasmGlobal(_global: number, _stopId: unknown): WasmValue {
|
|
throw new Error('Method not implemented.');
|
|
}
|
|
getWasmOp(_op: number, _stopId: unknown): WasmValue {
|
|
throw new Error('Method not implemented.');
|
|
}
|
|
reportResourceLoad(
|
|
_resourceUrl: string,
|
|
_status: {success: boolean, errorMessage?: string|undefined, size?: number|undefined}): Promise<void> {
|
|
return Promise.resolve();
|
|
}
|
|
}
|
|
|
|
export function makeURL(path: string): string {
|
|
return new URL(path, document.baseURI).href;
|
|
}
|
|
|
|
export async function createWorkerPlugin(debug?: Debugger): Promise<Chrome.DevTools.LanguageExtensionPlugin> {
|
|
return await WorkerPlugin.create([], true).then(p => {
|
|
if (debug) {
|
|
p.getWasmLinearMemory = debug.getWasmLinearMemory.bind(debug);
|
|
p.getWasmLocal = debug.getWasmLocal.bind(debug);
|
|
p.getWasmGlobal = debug.getWasmGlobal.bind(debug);
|
|
p.getWasmOp = debug.getWasmOp.bind(debug);
|
|
}
|
|
/* eslint-disable-next-line no-debugger */
|
|
debugger; // Halt in the debugger to let developers set breakpoints in C++.
|
|
return p;
|
|
});
|
|
}
|
|
|
|
export function relativePathname(url: URL, base: URL): string {
|
|
const baseSplit = base.pathname.split('/');
|
|
const urlSplit = url.pathname.split('/');
|
|
|
|
let i = 0;
|
|
for (; i < Math.min(baseSplit.length, urlSplit.length); ++i) {
|
|
if (baseSplit[i] !== urlSplit[i]) {
|
|
break;
|
|
}
|
|
}
|
|
const result = new Array(baseSplit.length - i);
|
|
result.fill('..');
|
|
result.push(...urlSplit.slice(i).filter(p => p.length > 0));
|
|
|
|
return result.join('/');
|
|
}
|
|
|
|
export function nonNull<T>(value: T|null|undefined): T {
|
|
assert.exists(value);
|
|
return value as T;
|
|
}
|
|
|
|
export function remoteObject(value: Chrome.DevTools.RemoteObject|Chrome.DevTools.ForeignObject|null):
|
|
Chrome.DevTools.RemoteObject {
|
|
assert.exists(value);
|
|
assert(value.type !== 'reftype');
|
|
return value;
|
|
}
|
|
|
|
export class TestWasmInterface implements WasmInterface {
|
|
memory = new ArrayBuffer(0);
|
|
locals = new Map<number, WasmValue>();
|
|
globals = new Map<number, WasmValue>();
|
|
stack = new Map<number, WasmValue>();
|
|
|
|
readMemory(offset: number, length: number): Uint8Array<ArrayBuffer> {
|
|
return new Uint8Array(this.memory, offset, length);
|
|
}
|
|
getOp(op: number): WasmValue {
|
|
const val = this.stack.get(op);
|
|
if (val !== undefined) {
|
|
return val;
|
|
}
|
|
throw new Error(`No stack entry ${op}`);
|
|
}
|
|
getLocal(local: number): WasmValue {
|
|
const val = this.locals.get(local);
|
|
if (val !== undefined) {
|
|
return val;
|
|
}
|
|
throw new Error(`No local ${local}`);
|
|
}
|
|
getGlobal(global: number): WasmValue {
|
|
const val = this.globals.get(global);
|
|
if (val !== undefined) {
|
|
return val;
|
|
}
|
|
throw new Error(`No global ${global}`);
|
|
}
|
|
}
|
|
|
|
export class TestValue implements Value {
|
|
private dataView: DataView<ArrayBuffer>;
|
|
members: {[key: string]: TestValue, [key: number]: TestValue};
|
|
location: number;
|
|
size: number;
|
|
typeNames: string[];
|
|
|
|
static fromInt8(value: number, typeName = 'int8_t'): TestValue {
|
|
const content = new DataView(new ArrayBuffer(1));
|
|
content.setInt8(0, value);
|
|
return new TestValue(content, typeName);
|
|
}
|
|
static fromInt16(value: number, typeName = 'int16_t'): TestValue {
|
|
const content = new DataView(new ArrayBuffer(2));
|
|
content.setInt16(0, value, true);
|
|
return new TestValue(content, typeName);
|
|
}
|
|
static fromInt32(value: number, typeName = 'int32_t'): TestValue {
|
|
const content = new DataView(new ArrayBuffer(4));
|
|
content.setInt32(0, value, true);
|
|
return new TestValue(content, typeName);
|
|
}
|
|
static fromInt64(value: bigint, typeName = 'int64_t'): TestValue {
|
|
const content = new DataView(new ArrayBuffer(8));
|
|
content.setBigInt64(0, value, true);
|
|
return new TestValue(content, typeName);
|
|
}
|
|
static fromUint8(value: number, typeName = 'uint8_t'): TestValue {
|
|
const content = new DataView(new ArrayBuffer(1));
|
|
content.setUint8(0, value);
|
|
return new TestValue(content, typeName);
|
|
}
|
|
static fromUint16(value: number, typeName = 'uint16_t'): TestValue {
|
|
const content = new DataView(new ArrayBuffer(2));
|
|
content.setUint16(0, value, true);
|
|
return new TestValue(content, typeName);
|
|
}
|
|
static fromUint32(value: number, typeName = 'uint32_t'): TestValue {
|
|
const content = new DataView(new ArrayBuffer(4));
|
|
content.setUint32(0, value, true);
|
|
return new TestValue(content, typeName);
|
|
}
|
|
static fromUint64(value: bigint, typeName = 'uint64_t'): TestValue {
|
|
const content = new DataView(new ArrayBuffer(8));
|
|
content.setBigUint64(0, value, true);
|
|
return new TestValue(content, typeName);
|
|
}
|
|
static fromFloat32(value: number, typeName = 'float'): TestValue {
|
|
const content = new DataView(new ArrayBuffer(4));
|
|
content.setFloat32(0, value, true);
|
|
return new TestValue(content, typeName);
|
|
}
|
|
static fromFloat64(value: number, typeName = 'double'): TestValue {
|
|
const content = new DataView(new ArrayBuffer(8));
|
|
content.setFloat64(0, value, true);
|
|
return new TestValue(content, typeName);
|
|
}
|
|
static pointerTo(pointeeOrElements: TestValue|TestValue[], address?: number): TestValue {
|
|
const content = new DataView(new ArrayBuffer(4));
|
|
const elements = Array.isArray(pointeeOrElements) ? pointeeOrElements : [pointeeOrElements];
|
|
address = address ?? elements[0].location;
|
|
content.setUint32(0, address, true);
|
|
const space = elements[0].typeNames[0].endsWith('*') ? '' : ' ';
|
|
const members: {[key: string|number]: TestValue} = {'*': elements[0]};
|
|
for (let i = 0; i < elements.length; ++i) {
|
|
members[i] = elements[i];
|
|
}
|
|
const value = new TestValue(content, `${elements[0].typeNames[0]}${space}*`, members);
|
|
return value;
|
|
}
|
|
static fromMembers(typeName: string, members: {[key: string]: TestValue, [key: number]: TestValue}): TestValue {
|
|
return new TestValue(new DataView(new ArrayBuffer(0)), typeName, members);
|
|
}
|
|
|
|
asInt8(): number {
|
|
return this.dataView.getInt8(0);
|
|
}
|
|
asInt16(): number {
|
|
return this.dataView.getInt16(0, true);
|
|
}
|
|
asInt32(): number {
|
|
return this.dataView.getInt32(0, true);
|
|
}
|
|
asInt64(): bigint {
|
|
return this.dataView.getBigInt64(0, true);
|
|
}
|
|
asUint8(): number {
|
|
return this.dataView.getUint8(0);
|
|
}
|
|
asUint16(): number {
|
|
return this.dataView.getUint16(0, true);
|
|
}
|
|
asUint32(): number {
|
|
return this.dataView.getUint32(0, true);
|
|
}
|
|
asUint64(): bigint {
|
|
return this.dataView.getBigUint64(0, true);
|
|
}
|
|
asFloat32(): number {
|
|
return this.dataView.getFloat32(0, true);
|
|
}
|
|
asFloat64(): number {
|
|
return this.dataView.getFloat64(0, true);
|
|
}
|
|
asDataView(offset?: number, size?: number): DataView<ArrayBuffer> {
|
|
offset = this.location + (offset ?? 0);
|
|
size = Math.min(size ?? this.size, this.size - Math.max(0, offset));
|
|
return new DataView(this.dataView.buffer, offset, size);
|
|
}
|
|
getMembers(): string[] {
|
|
return Object.keys(this.members);
|
|
}
|
|
|
|
$(member: string|number): Value {
|
|
if (typeof member === 'number' || !member.includes('.')) {
|
|
return this.members[member];
|
|
}
|
|
let value = this as Value;
|
|
for (const prop of member.split('.')) {
|
|
value = value.$(prop);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
constructor(
|
|
content: DataView<ArrayBuffer>, typeName: string,
|
|
members?: {[key: string]: TestValue, [key: number]: TestValue}) {
|
|
this.location = 0;
|
|
this.size = content.byteLength;
|
|
this.typeNames = [typeName];
|
|
this.members = members || {};
|
|
this.dataView = content;
|
|
}
|
|
}
|
|
|
|
declare global {
|
|
/* eslint-disable-next-line @typescript-eslint/naming-convention */
|
|
let __karma__: unknown;
|
|
}
|