refactor(frontend): fix base template component

This commit is contained in:
Rachel Powers
2024-05-30 17:53:48 -07:00
parent 7b6909a323
commit 10997d4185
10 changed files with 495 additions and 125 deletions

View File

@@ -123,14 +123,14 @@ export class VMICControls extends VMActiveICMixin(BaseElement) {
${ics.map(
([id, device], _index) =>
html`<sl-option
name=${device.name}
prefabName=${device.prefabName}
name=${device.obj_info.name}
prefabName=${device.obj_info.prefab}
value=${id}
>
${device.name
? html`<span slot="suffix">${device.prefabName}</span>`
${device.obj_info.name
? html`<span slot="suffix">${device.obj_info.prefab}</span>`
: ""}
Device:${id} ${device.name ?? device.prefabName}
Device:${id} ${device.obj_info.name ?? device.obj_info.prefab}
</sl-option>`,
)}
</sl-select>
@@ -156,13 +156,16 @@ export class VMICControls extends VMActiveICMixin(BaseElement) {
<span>Errors</span>
${this.errors.map(
(err) =>
html`<div class="hstack">
<span>
Line: ${err.ParseError.line} -
${err.ParseError.start}:${err.ParseError.end}
</span>
<span class="ms-auto">${err.ParseError.msg}</span>
</div>`,
typeof err === "object"
&& "ParseError" in err
? html`<div class="hstack">
<span>
Line: ${err.ParseError.line} -
${"ParseError" in err ? err.ParseError.start : "N/A"}:${err.ParseError.end}
</span>
<span class="ms-auto">${err.ParseError.msg}</span>
</div>`
: html`${JSON.stringify(err)}`,
)}
</div>
</div>

View File

@@ -432,7 +432,7 @@ export class VMDeviceCard extends VMTemplateDBMixin(
const val = parseIntWithHexOrBinary(input.value);
if (!isNaN(val)) {
window.VM.get().then((vm) => {
if (!vm.changeDeviceID(this.objectID, val)) {
if (!vm.changeObjectID(this.objectID, val)) {
input.value = this.objectID.toString();
}
});

View File

@@ -1,16 +1,58 @@
import { Connection } from "ic10emu_wasm";
import { DeviceDBConnection } from "../device_db";
const CableNetworkTypes: readonly string[] = Object.freeze(["Power", "Data", "PowerAndData"]);
export function connectionFromDeviceDBConnection(conn: DeviceDBConnection): Connection {
if (CableNetworkTypes.includes(conn.typ)) {
return {
import {
Connection,
ConnectionInfo,
CableConnectionType,
} from "ic10emu_wasm";
export function connectionFromConnectionInfo(conn: ConnectionInfo): Connection {
let connection: Connection = "None";
if (
conn.typ === "Power" ||
conn.typ === "Data" ||
conn.typ === "PowerAndData"
) {
connection = {
CableNetwork: {
net: window.VM.vm.ic10vm.defaultNetwork,
typ: conn.typ
}
net: window.VM.vm.defaultNetwork,
typ: conn.typ as CableConnectionType,
role: conn.role,
},
};
} else if (conn.typ === "Pipe") {
connection = {
Pipe: {
role: conn.role,
},
};
} else if (conn.typ === "PipeLiquid") {
connection = {
PipeLiquid: {
role: conn.role,
},
};
} else if (conn.typ === "Chute") {
connection = {
Chute: {
role: conn.role,
},
};
} else if (conn.typ === "Elevator") {
connection = {
Elevator: {
role: conn.role,
},
};
} else if (conn.typ === "LaunchPad") {
connection = {
LaunchPad: {
role: conn.role,
},
};
} else if (conn.typ === "LandingPad") {
connection = {
LandingPad: {
role: conn.role,
},
};
} else {
return "Other";
}
return connection;
}

View File

@@ -4,18 +4,42 @@ import type {
LogicField,
LogicType,
Slot,
Class,
FrozenObject,
MemoryAccess,
SlotInfo,
ConnectionInfo,
ObjectID,
CableConnectionType,
ConnectionRole,
ObjectInfo,
SlotOccupantInfo,
} from "ic10emu_wasm";
import { html, css, HTMLTemplateResult } from "lit";
import { customElement, property, query, state } from "lit/decorators.js";
import { BaseElement, defaultCss } from "components";
import { connectionFromDeviceDBConnection } from "./dbutils";
import { connectionFromConnectionInfo } from "./dbutils";
import { crc32, displayNumber, parseNumber } from "utils";
import SlInput from "@shoelace-style/shoelace/dist/components/input/input.component.js";
import SlSelect from "@shoelace-style/shoelace/dist/components/select/select.component.js";
import { VMDeviceCard } from "./card";
import { VMTemplateDBMixin } from "virtual_machine/base_device";
export interface SlotTemplate {
typ: Class
quantity: number,
occupant?: FrozenObject,
}
export interface ConnectionCableNetwork {
CableNetwork: {
net: ObjectID | undefined;
typ: CableConnectionType;
role: ConnectionRole;
};
}
@customElement("vm-device-template")
export class VmObjectTemplate extends VMTemplateDBMixin(BaseElement) {
@@ -51,11 +75,12 @@ export class VmObjectTemplate extends VMTemplateDBMixin(BaseElement) {
`,
];
@state() fields: { [key in LogicType]?: LogicField };
@state() fields: Map<LogicType, number>;
@state() slots: SlotTemplate[];
@state() template: ObjectTemplate;
@state() device_id: number | undefined;
@state() device_name: string | undefined;
@state() pins: (ObjectID | undefined)[];
@state() template: FrozenObject;
@state() objectId: number | undefined;
@state() objectName: string | undefined;
@state() connections: Connection[];
constructor() {
@@ -63,41 +88,61 @@ export class VmObjectTemplate extends VMTemplateDBMixin(BaseElement) {
this.templateDB = window.VM.vm.templateDB;
}
private _prefab_name: string;
private _prefabName: string;
private _prefabHash: number;
get prefab_name(): string {
return this._prefab_name;
get prefabName(): string {
return this._prefabName;
}
get prefabHash(): number {
return this._prefabHash;
}
@property({ type: String })
set prefab_name(val: string) {
this._prefab_name = val;
set prefabName(val: string) {
this._prefabName = val;
this._prefabHash = crc32(this._prefabName);
this.setupState();
}
get dbTemplate(): ObjectTemplate {
return this.templateDB.get( crc32(this.prefab_name));
return this.templateDB.get(this._prefabHash);
}
setupState() {
const dbTemplate = this.dbTemplate;
this.fields = Object.fromEntries(
Object.entries(this.dbTemplate?.logic ?? {}).map(([lt, ft]) => {
const value = lt === "PrefabHash" ? this.dbTemplate.prefab.prefab_hash : 0.0;
return [lt, { field_type: ft, value } as LogicField];
this.fields = new Map(
(
Array.from(
"logic" in dbTemplate
? dbTemplate.logic.logic_types.entries() ?? []
: [],
) as [LogicType, MemoryAccess][]
).map(([lt, access]) => {
const value =
lt === "PrefabHash" ? this.dbTemplate.prefab.prefab_hash : 0.0;
return [lt, value];
}),
);
this.slots = (this.dbTemplate?.slots ?? []).map(
this.slots = (
("slots" in dbTemplate ? dbTemplate.slots ?? [] : []) as SlotInfo[]
).map(
(slot, _index) =>
({
typ: slot.typ,
quantity: 0,
}) as SlotTemplate,
);
const connections = Object.entries(this.dbTemplate?.conn ?? {}).map(
([index, conn]) =>
[index, connectionFromDeviceDBConnection(conn)] as const,
const connections = (
"device" in dbTemplate
? dbTemplate.device.connection_list
: ([] as ConnectionInfo[])
).map(
(conn, index) => [index, connectionFromConnectionInfo(conn)] as const,
);
connections.sort((a, b) => {
if (a[0] < b[0]) {
@@ -110,12 +155,15 @@ export class VmObjectTemplate extends VMTemplateDBMixin(BaseElement) {
});
this.connections = connections.map((conn) => conn[1]);
const numPins = "device" in dbTemplate ? dbTemplate.device.device_pins_length : 0;
this.pins = new Array(numPins).fill(undefined);
}
renderFields(): HTMLTemplateResult {
const fields = Object.entries(this.fields);
return html`
${fields.map(([name, field], _index, _fields) => {
return html`
return html`
<sl-input
key="${name}"
value="${displayNumber(field.value)}"
@@ -127,7 +175,7 @@ export class VmObjectTemplate extends VMTemplateDBMixin(BaseElement) {
<span slot="suffix">${field.field_type}</span>
</sl-input>
`;
})}
})}
`;
}
@@ -135,9 +183,9 @@ export class VmObjectTemplate extends VMTemplateDBMixin(BaseElement) {
const input = e.target as SlInput;
const field = input.getAttribute("key")! as LogicType;
const val = parseNumber(input.value);
this.fields[field].value = val;
this.fields.set(field, val);
if (field === "ReferenceId" && val !== 0) {
this.device_id = val;
this.objectId = val;
}
this.requestUpdate();
}
@@ -161,9 +209,11 @@ export class VmObjectTemplate extends VMTemplateDBMixin(BaseElement) {
return html`
<div class="networks">
${connections.map((connection, index, _conns) => {
const conn =
typeof connection === "object" ? connection.CableNetwork : null;
return html`
const conn =
typeof connection === "object" && "CableNetwork" in connection
? connection.CableNetwork
: null;
return html`
<sl-select
hoist
placement="top"
@@ -175,13 +225,13 @@ export class VmObjectTemplate extends VMTemplateDBMixin(BaseElement) {
>
<span slot="prefix">Connection:${index} </span>
${vmNetworks.map(
(net) =>
html`<sl-option value=${net}>Network ${net}</sl-option>`,
)}
(net) =>
html`<sl-option value=${net}>Network ${net}</sl-option>`,
)}
<span slot="prefix"> ${conn?.typ} </span>
</sl-select>
`;
})}
})}
</div>
`;
}
@@ -195,8 +245,48 @@ export class VmObjectTemplate extends VMTemplateDBMixin(BaseElement) {
}
renderPins(): HTMLTemplateResult {
const device = this.templateDB.db[this.prefab_name];
return html`<div class="pins"></div>`;
const networks = this.connections.flatMap((connection, index) => {
return typeof connection === "object" && "CableNetwork" in connection
? [connection.CableNetwork.net]
: [];
});
const visibleDeviceIds = [
...new Set(
networks.flatMap((net) => window.VM.vm.networkDataDevices(net)),
),
];
const visibleDevices = visibleDeviceIds.map((id) =>
window.VM.vm.objects.get(id),
);
const pinsHtml = this.pins?.map(
(pin, index) =>
html` <sl-select
hoist
placement="top"
clearable
key=${index}
.value=${pin}
@sl-change=${this._handleChangePin}
>
<span slot="prefix">d${index}</span>
${visibleDevices.map(
(device, _index) => html`
<sl-option value=${device.obj_info.id.toString()}>
Device ${device.obj_info.id} :
${device.obj_info.name ?? device.obj_info.prefab}
</sl-option>
`,
)}
</sl-select>`,
);
return html`<div class="pins">${pinsHtml}</div>`;
}
_handleChangePin(e: CustomEvent) {
const select = e.target as SlSelect;
const pin = parseInt(select.getAttribute("key")!);
const val = select.value ? parseInt(select.value as string) : undefined;
this.pins[pin] = val
}
render() {
@@ -204,17 +294,17 @@ export class VmObjectTemplate extends VMTemplateDBMixin(BaseElement) {
return html`
<sl-card class="template-card">
<div class="header h-20 w-96" slot="header">
<sl-tooltip content="${device?.name}">
<sl-tooltip content="${device?.prefab.prefab_name}">
<img
class="image me-2"
src="img/stationpedia/${device?.name}.png"
src="img/stationpedia/${device?.prefab.prefab_name}.png"
onerror="this.src = '${VMDeviceCard.transparentImg}'"
/>
</sl-tooltip>
<div class="vstack">
<span class="prefab-title">${device.title}</span>
<span class="prefab-name"><small>${device?.name}</small></span>
<span class="prefab-hash"><small>${device?.hash}</small></span>
<span>${device.prefab.name}</span>
<span><small>${device?.prefab.prefab_name}</small></span>
<span><small>${device?.prefab.prefab_hash}</small></span>
</div>
<sl-button
class="ms-auto mt-auto mb-auto"
@@ -244,19 +334,68 @@ export class VmObjectTemplate extends VMTemplateDBMixin(BaseElement) {
</sl-card>
`;
}
_handleAddButtonClick() {
async _handleAddButtonClick() {
this.dispatchEvent(
new CustomEvent("add-device-template", { bubbles: true }),
);
const template: DeviceTemplate = {
id: this.device_id,
name: this.device_name,
prefab_name: this.prefab_name,
slots: this.slots,
connections: this.connections,
fields: this.fields,
// Typescript doesn't like fileds defined as `X | undefined` not being present, hence cast
const objInfo: ObjectInfo = {
id: this.objectId,
name: this.objectName,
prefab: this.prefabName
} as ObjectInfo;
if (this.slots.length > 0) {
const slotOccupants: [FrozenObject, number][] = this.slots.flatMap((slot, index) => {
return typeof slot.occupant !== "undefined" ? [[slot.occupant, index]] : [];
})
let slotOccupantTemplates: FrozenObject[] | null = null;
let slotOccupantObjectIds: ObjectID[] | null = null;
let slotOccupantIdsMap: Map<number, number> = new Map();
if (slotOccupants.length > 0) {
slotOccupantTemplates = slotOccupants.map(([slot, _]) => slot);
slotOccupantObjectIds = await window.VM.vm.addObjectsFrozen(slotOccupantTemplates);
slotOccupantIdsMap = new Map(slotOccupants.map((_, index) => {
return [index, slotOccupantObjectIds[index]];
}))
}
objInfo.slots = new Map(this.slots.flatMap((slot, index) => {
const occupantId = slotOccupantIdsMap.get(index);
if (typeof occupantId !== "undefined") {
const info: SlotOccupantInfo = {
id: occupantId,
quantity: slot.quantity
};
return [[index, info]] as [number, SlotOccupantInfo][];
} else {
return [] as [number, SlotOccupantInfo][];
}
}))
}
if (this.connections.length > 0) {
objInfo.connections = new Map(
this.connections.flatMap((conn, index) => {
return typeof conn === "object" &&
"CableNetwork" in conn &&
typeof conn.CableNetwork.net !== "undefined"
? ([[index, conn.CableNetwork.net]] as [number, number][])
: ([] as [number, number][]);
}),
);
}
if (this.fields.size > 0) {
objInfo.logic_values = new Map(this.fields)
}
const template: FrozenObject = {
obj_info: objInfo,
database_template: true,
template: undefined,
};
window.VM.vm.addDeviceFromTemplate(template);
await window.VM.vm.addObjectFrozen(template);
// reset state for new device
this.setupState();

View File

@@ -8,6 +8,7 @@ import type {
TemplateDatabase,
FrozenCableNetwork,
FrozenObjectFull,
ObjectID,
} from "ic10emu_wasm";
import * as Comlink from "comlink";
import "./base_device";
@@ -29,6 +30,8 @@ export interface VirtualMachinEventMap {
"vm-objects-modified": CustomEvent<number>;
"vm-run-ic": CustomEvent<number>;
"vm-object-id-change": CustomEvent<{ old: number; new: number }>;
"vm-networks-update": CustomEvent<number[]>;
"vm-networks-removed": CustomEvent<number[]>;
}
class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEventMap>) {
@@ -62,6 +65,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
this.templateDBPromise.then((db) => this.setupTemplateDatabase(db));
this.updateObjects();
this.updateNetworks();
this.updateCode();
}
@@ -113,11 +117,65 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
return ids;
}
async updateNetworks() {
let updateFlag = false;
const removedNetworks = [];
let networkIds: Uint32Array;
let frozenNetworks: FrozenCableNetwork[];
try {
networkIds = await this.ic10vm.networks;
frozenNetworks = await this.ic10vm.freezeNetworks(networkIds);
} catch (e) {
this.handleVmError(e);
return;
}
const updatedNetworks: ObjectID[] = [];
for (const [index, id] of networkIds.entries()) {
if (!this._networks.has(id)) {
this._networks.set(id, frozenNetworks[index]);
updateFlag = true;
updatedNetworks.push(id);
} else {
if (!structuralEqual(this._networks.get(id), frozenNetworks[index])) {
this._networks.set(id, frozenNetworks[index]);
updatedNetworks.push(id);
updateFlag = true;
}
}
}
for (const id of this._networks.keys()) {
if (!networkIds.includes(id)) {
this._networks.delete(id);
updateFlag = true;
removedNetworks.push(id);
}
}
if (updateFlag) {
const ids = Array.from(updatedNetworks);
ids.sort();
this.dispatchEvent(
new CustomEvent("vm-networks-update", {
detail: ids,
}),
);
if (removedNetworks.length > 0) {
this.dispatchEvent(
new CustomEvent("vm-networks-removed", {
detail: removedNetworks,
}),
);
}
this.app.session.save();
}
}
async updateObjects() {
let updateFlag = false;
const removedObjects = [];
let objectIds;
let frozenObjects;
let objectIds: Uint32Array;
let frozenObjects: FrozenObjectFull[];
try {
objectIds = await this.ic10vm.objects;
frozenObjects = await this.ic10vm.freezeObjects(objectIds);
@@ -125,7 +183,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
this.handleVmError(e);
return;
}
const updatedObjects = [];
const updatedObjects: ObjectID[] = [];
for (const [index, id] of objectIds.entries()) {
if (!this._objects.has(id)) {
@@ -267,17 +325,18 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
async update(save: boolean = true) {
await this.updateObjects();
await this.updateNetworks();
const lastModified = await this.ic10vm.lastOperationModified;
lastModified.forEach((id, _index, _modifiedIds) => {
if (this.objects.has(id)) {
this.updateDevice(id, false);
this.updateObject(id, false);
}
}, this);
this.updateDevice(this.activeIC.obj_info.id, false);
this.updateObject(this.activeIC.obj_info.id, false);
if (save) this.app.session.save();
}
async updateDevice(id: number, save: boolean = true) {
async updateObject(id: number, save: boolean = true) {
let frozen;
try {
frozen = await this.ic10vm.freezeObject(id);
@@ -287,7 +346,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
}
const device = this._objects.get(id);
this.dispatchEvent(
new CustomEvent("vm-device-modified", { detail: device.obj_info.id }),
new CustomEvent("vm-object-modified", { detail: device.obj_info.id }),
);
if (typeof device.obj_info.socketed_ic !== "undefined") {
const ic = this._objects.get(device.obj_info.socketed_ic);
@@ -309,7 +368,12 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
this.dispatchEvent(new CustomEvent("vm-message", { detail: message }));
}
async changeDeviceID(oldID: number, newID: number): Promise<boolean> {
// return the data connected oject ids for a network
networkDataDevices(network: ObjectID): number[] {
return this._networks.get(network)?.devices ?? []
}
async changeObjectID(oldID: number, newID: number): Promise<boolean> {
try {
await this.ic10vm.changeDeviceId(oldID, newID);
if (this.app.session.activeIC === oldID) {
@@ -336,7 +400,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
const ic = this.activeIC!;
try {
await this.ic10vm.setRegister(ic.obj_info.id, index, val);
this.updateDevice(ic.obj_info.id);
this.updateObject(ic.obj_info.id);
return true;
} catch (err) {
this.handleVmError(err);
@@ -348,7 +412,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
const ic = this.activeIC!;
try {
await this.ic10vm.setMemory(ic.obj_info.id, addr, val);
this.updateDevice(ic.obj_info.id);
this.updateObject(ic.obj_info.id);
return true;
} catch (err) {
this.handleVmError(err);
@@ -361,7 +425,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
if (obj) {
try {
await this.ic10vm.setObjectName(obj.obj_info.id, name);
this.updateDevice(obj.obj_info.id);
this.updateObject(obj.obj_info.id);
this.app.session.save();
return true;
} catch (e) {
@@ -382,7 +446,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
if (obj) {
try {
await this.ic10vm.setLogicField(obj.obj_info.id, field, val, force);
this.updateDevice(obj.obj_info.id);
this.updateObject(obj.obj_info.id);
return true;
} catch (err) {
this.handleVmError(err);
@@ -409,7 +473,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
val,
force,
);
this.updateDevice(obj.obj_info.id);
this.updateObject(obj.obj_info.id);
return true;
} catch (err) {
this.handleVmError(err);
@@ -427,7 +491,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
if (typeof device !== "undefined") {
try {
await this.ic10vm.setDeviceConnection(id, conn, val);
this.updateDevice(device.obj_info.id);
this.updateObject(device.obj_info.id);
return true;
} catch (err) {
this.handleVmError(err);
@@ -445,7 +509,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
if (typeof device !== "undefined") {
try {
await this.ic10vm.setPin(id, pin, val);
this.updateDevice(device.obj_info.id);
this.updateObject(device.obj_info.id);
return true;
} catch (err) {
this.handleVmError(err);
@@ -462,10 +526,10 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
);
}
async addObjectFromFrozen(frozen: FrozenObject): Promise<boolean> {
async addObjectFrozen(frozen: FrozenObject): Promise<ObjectID | undefined> {
try {
console.log("adding device", frozen);
const id = await this.ic10vm.addObjectFromFrozen(frozen);
const id = await this.ic10vm.addObjectFrozen(frozen);
const refrozen = await this.ic10vm.freezeObject(id);
this._objects.set(id, refrozen);
const device_ids = await this.ic10vm.objects;
@@ -475,10 +539,32 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
}),
);
this.app.session.save();
return true;
return id;
} catch (err) {
this.handleVmError(err);
return false;
return undefined;
}
}
async addObjectsFrozen(frozenObjects: FrozenObject[]): Promise<ObjectID[] | undefined> {
try {
console.log("adding devices", frozenObjects);
const ids = await this.ic10vm.addObjectsFrozen(frozenObjects);
const refrozen = await this.ic10vm.freezeObjects(ids);
ids.forEach((id, index) => {
this._objects.set(id, refrozen[index]);
})
const device_ids = await this.ic10vm.objects;
this.dispatchEvent(
new CustomEvent("vm-objects-update", {
detail: Array.from(device_ids),
}),
);
this.app.session.save();
return Array.from(ids);
} catch (err) {
this.handleVmError(err);
return undefined;
}
}
@@ -504,7 +590,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
try {
console.log("setting slot occupant", frozen);
await this.ic10vm.setSlotOccupant(id, index, frozen, quantity);
this.updateDevice(device.obj_info.id);
this.updateObject(device.obj_info.id);
return true;
} catch (err) {
this.handleVmError(err);
@@ -518,7 +604,7 @@ class VirtualMachine extends (EventTarget as TypedEventTarget<VirtualMachinEvent
if (typeof device !== "undefined") {
try {
this.ic10vm.removeSlotOccupant(id, index);
this.updateDevice(device.obj_info.id);
this.updateObject(device.obj_info.id);
return true;
} catch (err) {
this.handleVmError(err);

View File

@@ -44,17 +44,16 @@ export class VMICRegisters extends VMActiveICMixin(BaseElement) {
}
protected render() {
const registerAliases: [string, number][] = (
(
[...(this.aliases ?? [])].filter(
([_alias, target]) =>
"RegisterSpec" in target && target.RegisterSpec.indirection === 0,
) as [string, RegisterSpec][]
).map(([alias, target]) => [alias, target.RegisterSpec.target]) as [
string,
number,
][]
).concat(VMICRegisters.defaultAliases);
const registerAliases: [string, number][] =
[...(Array.from(this.aliases?.entries() ?? []))].flatMap(
([alias, target]) => {
if ("RegisterSpec" in target && target.RegisterSpec.indirection === 0) {
return [[alias, target.RegisterSpec.target]] as [string, number][];
} else {
return [] as [string, number][];
}
}
).concat(VMICRegisters.defaultAliases);
return html`
<sl-card class="card">
<div class="card-body">