mirror of
https://github.com/koush/scrypted.git
synced 2026-05-05 22:00:27 +01:00
plugin: add type assertions for strictNullChecks in plugin core modules
Fix strictNullChecks: - device.ts: add assertions for storage and nativeIds access - endpoint.ts: add assertions for device and handler access - plugin-api.ts: add definite assignment for callback properties - plugin-host-api.ts: add assertions for findPluginDevice results, consolidate plugin assertions at declarations - plugin-lazy-remote.ts: add assertion for getFile result - system.ts: add definite assignment for manager properties, add assertions for state access
This commit is contained in:
@@ -7,7 +7,7 @@ import { SystemManagerImpl } from './system';
|
||||
class DeviceLogger implements Logger {
|
||||
nativeId: ScryptedNativeId;
|
||||
api: PluginAPI;
|
||||
logger: Promise<PluginLogger>;
|
||||
logger!: Promise<PluginLogger>;
|
||||
|
||||
constructor(api: PluginAPI, nativeId: ScryptedNativeId, public console: any) {
|
||||
this.api = api;
|
||||
@@ -65,12 +65,12 @@ export class DeviceStateProxyHandler implements ProxyHandler<any> {
|
||||
return { id: this.id }
|
||||
if (p === 'setState')
|
||||
return this.setState;
|
||||
return this.deviceManager.systemManager.state[this.id][p as string]?.value;
|
||||
return this.deviceManager.systemManager.state[this.id]![p as string]?.value;
|
||||
}
|
||||
|
||||
set?(target: any, p: PropertyKey, value: any, receiver: any) {
|
||||
checkProperty(p.toString(), value);
|
||||
this.deviceManager.systemManager.state[this.id][p as string] = {
|
||||
this.deviceManager.systemManager.state[this.id]![p as string] = {
|
||||
value,
|
||||
};
|
||||
this.setState(p.toString(), value);
|
||||
@@ -84,7 +84,7 @@ interface DeviceManagerDevice {
|
||||
}
|
||||
|
||||
export class DeviceManagerImpl implements DeviceManager {
|
||||
api: PluginAPI;
|
||||
api!: PluginAPI;
|
||||
nativeIds = new Map<ScryptedNativeId, DeviceManagerDevice>();
|
||||
deviceStorage = new Map<ScryptedNativeId, StorageImpl>();
|
||||
mixinStorage = new Map<ScryptedNativeId, Map<string, StorageImpl>>();
|
||||
@@ -103,7 +103,7 @@ export class DeviceManagerImpl implements DeviceManager {
|
||||
}
|
||||
|
||||
getDeviceState(nativeId?: any): DeviceState {
|
||||
const handler = new DeviceStateProxyHandler(this, this.nativeIds.get(nativeId).id,
|
||||
const handler = new DeviceStateProxyHandler(this, this.nativeIds.get(nativeId)!.id,
|
||||
(property, value) => this.api.setState(nativeId, property, value));
|
||||
return new Proxy(handler, handler);
|
||||
}
|
||||
@@ -136,7 +136,7 @@ export class DeviceManagerImpl implements DeviceManager {
|
||||
}
|
||||
pruneMixinStorage() {
|
||||
for (const nativeId of this.nativeIds.keys()) {
|
||||
const storage = this.nativeIds.get(nativeId).storage;
|
||||
const storage = this.nativeIds.get(nativeId)!.storage;
|
||||
for (const key of Object.keys(storage)) {
|
||||
if (!key.startsWith('mixin:'))
|
||||
continue;
|
||||
@@ -219,20 +219,20 @@ export class StorageImpl implements Storage {
|
||||
}
|
||||
|
||||
get storage(): { [key: string]: any } {
|
||||
return this.deviceManager.nativeIds.get(this.nativeId).storage;
|
||||
return this.deviceManager.nativeIds.get(this.nativeId)!.storage;
|
||||
}
|
||||
|
||||
get length(): number {
|
||||
return Object.keys(this.storage).filter(key => key.startsWith(this.prefix)).length;
|
||||
return Object.keys(this.storage).filter(key => key.startsWith(this.prefix!)).length;
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
if (!this.prefix) {
|
||||
this.deviceManager.nativeIds.get(this.nativeId).storage = {};
|
||||
this.deviceManager.nativeIds.get(this.nativeId)!.storage = {};
|
||||
}
|
||||
else {
|
||||
const storage = this.storage;
|
||||
Object.keys(this.storage).filter(key => key.startsWith(this.prefix)).forEach(key => delete storage[key]);
|
||||
Object.keys(this.storage).filter(key => key.startsWith(this.prefix!)).forEach(key => delete storage[key]);
|
||||
}
|
||||
this.api.setStorage(this.nativeId, this.storage);
|
||||
}
|
||||
@@ -242,9 +242,9 @@ export class StorageImpl implements Storage {
|
||||
}
|
||||
key(index: number): string {
|
||||
if (!this.prefix) {
|
||||
return Object.keys(this.storage)[index];
|
||||
return Object.keys(this.storage)[index]!;
|
||||
}
|
||||
return Object.keys(this.storage).filter(key => key.startsWith(this.prefix))[index].substring(this.prefix.length);
|
||||
return Object.keys(this.storage).filter(key => key.startsWith(this.prefix!))[index]!.substring(this.prefix!.length);
|
||||
}
|
||||
removeItem(key: string): void {
|
||||
delete this.storage[this.prefix + key];
|
||||
|
||||
@@ -3,10 +3,10 @@ import type { DeviceManagerImpl } from "./device";
|
||||
import type { PluginAPI } from "./plugin-api";
|
||||
|
||||
export class EndpointManagerImpl implements EndpointManager {
|
||||
deviceManager: DeviceManagerImpl;
|
||||
api: PluginAPI;
|
||||
pluginId: string;
|
||||
mediaManager: MediaManager;
|
||||
deviceManager!: DeviceManagerImpl;
|
||||
api!: PluginAPI;
|
||||
pluginId!: string;
|
||||
mediaManager!: MediaManager;
|
||||
|
||||
getEndpoint(nativeId?: ScryptedNativeId) {
|
||||
if (!nativeId)
|
||||
|
||||
@@ -69,7 +69,7 @@ export class PluginAPIManagedListeners {
|
||||
}
|
||||
|
||||
export class PluginAPIProxy extends PluginAPIManagedListeners implements PluginAPI {
|
||||
acl: AccessControls;
|
||||
acl!: AccessControls;
|
||||
|
||||
constructor(public api: PluginAPI, public mediaManager?: MediaManager) {
|
||||
super();
|
||||
|
||||
@@ -12,9 +12,9 @@ import { checkProperty } from './plugin-state-check';
|
||||
|
||||
export class PluginHostAPI extends PluginAPIManagedListeners implements PluginAPI {
|
||||
pluginId: string;
|
||||
typesVersion: string;
|
||||
descriptors: { [scryptedInterface: string]: ScryptedInterfaceDescriptor };
|
||||
propertyInterfaces: ReturnType<typeof getPropertyInterfaces>;
|
||||
typesVersion!: string;
|
||||
descriptors!: { [scryptedInterface: string]: ScryptedInterfaceDescriptor };
|
||||
propertyInterfaces!: ReturnType<typeof getPropertyInterfaces>;
|
||||
|
||||
[RpcPeer.PROPERTY_PROXY_ONEWAY_METHODS] = [
|
||||
'onMixinEvent',
|
||||
@@ -131,7 +131,7 @@ export class PluginHostAPI extends PluginAPIManagedListeners implements PluginAP
|
||||
}
|
||||
|
||||
async setStorage(nativeId: ScryptedNativeId, storage: { [key: string]: string }) {
|
||||
const device = this.scrypted.findPluginDevice(this.pluginId, nativeId)
|
||||
const device = this.scrypted.findPluginDevice(this.pluginId, nativeId)!;
|
||||
device.storage = storage;
|
||||
this.scrypted.datastore.upsert(device);
|
||||
}
|
||||
@@ -168,12 +168,12 @@ export class PluginHostAPI extends PluginAPIManagedListeners implements PluginAP
|
||||
}
|
||||
|
||||
async onDeviceRemoved(nativeId: string) {
|
||||
await this.scrypted.removeDevice(this.scrypted.findPluginDevice(this.pluginId, nativeId))
|
||||
await this.scrypted.removeDevice(this.scrypted.findPluginDevice(this.pluginId, nativeId)!)
|
||||
}
|
||||
|
||||
async onDeviceEvent(nativeId: any, eventInterface: any, eventData?: any) {
|
||||
const plugin = this.scrypted.findPluginDevice(this.pluginId, nativeId);
|
||||
this.scrypted.stateManager.notifyInterfaceEventFromMixin(plugin!, eventInterface, eventData, plugin!._id);
|
||||
const plugin = this.scrypted.findPluginDevice(this.pluginId, nativeId)!;
|
||||
this.scrypted.stateManager.notifyInterfaceEventFromMixin(plugin, eventInterface, eventData, plugin._id);
|
||||
}
|
||||
|
||||
async getDeviceById<T>(id: string): Promise<T & ScryptedDevice> {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { PluginRemote, PluginRemoteLoadZipOptions, PluginZipAPI } from './plugin
|
||||
* execution order of state reporting may fail.
|
||||
*/
|
||||
export class LazyRemote implements PluginRemote {
|
||||
remote: PluginRemote;
|
||||
remote!: PluginRemote;
|
||||
|
||||
constructor(public remotePromise: Promise<PluginRemote>, public remoteReadyPromise: Promise<PluginRemote>) {
|
||||
this.remoteReadyPromise = (async () => {
|
||||
|
||||
@@ -10,8 +10,8 @@ function newDeviceProxy(id: string, systemManager: SystemManagerImpl) {
|
||||
}
|
||||
|
||||
class DeviceProxyHandler implements PrimitiveProxyHandler<any> {
|
||||
customProperties: Map<string | number | symbol, any>;
|
||||
device: Promise<ScryptedDevice>;
|
||||
customProperties!: Map<string | number | symbol, any>;
|
||||
device!: Promise<ScryptedDevice | undefined>;
|
||||
constructor(public id: string, public systemManager: SystemManagerImpl) {
|
||||
}
|
||||
|
||||
@@ -20,14 +20,14 @@ class DeviceProxyHandler implements PrimitiveProxyHandler<any> {
|
||||
}
|
||||
|
||||
ownKeys(target: any): ArrayLike<string | symbol> {
|
||||
const interfaces = new Set<string>(this.systemManager.state[this.id].interfaces.value);
|
||||
const interfaces = new Set<string>(this.systemManager.state[this.id]!.interfaces!.value);
|
||||
const methods = getInterfaceMethods(this.systemManager.descriptors || ScryptedInterfaceDescriptors, interfaces);
|
||||
const properties = getInterfaceProperties(this.systemManager.descriptors || ScryptedInterfaceDescriptors, interfaces);
|
||||
return [...methods, ...properties];
|
||||
}
|
||||
|
||||
getOwnPropertyDescriptor(target: any, p: string | symbol): PropertyDescriptor | undefined {
|
||||
const interfaces = new Set<string>(this.systemManager.state[this.id].interfaces.value);
|
||||
const interfaces = new Set<string>(this.systemManager.state[this.id]!.interfaces!.value);
|
||||
const methods = getInterfaceMethods(this.systemManager.descriptors || ScryptedInterfaceDescriptors, interfaces);
|
||||
const prop = p.toString();
|
||||
if (methods.includes(prop)) {
|
||||
@@ -39,7 +39,7 @@ class DeviceProxyHandler implements PrimitiveProxyHandler<any> {
|
||||
if (properties.includes(prop)) {
|
||||
return {
|
||||
configurable: true,
|
||||
value: this.systemManager.state[this.id][prop]?.value
|
||||
value: this.systemManager.state[this.id]![prop]?.value
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
@@ -77,19 +77,19 @@ class DeviceProxyHandler implements PrimitiveProxyHandler<any> {
|
||||
if (handled)
|
||||
return handled;
|
||||
|
||||
const interfaces = new Set<string>(this.systemManager.state[this.id].interfaces?.value || []);
|
||||
const interfaces = new Set<string>(this.systemManager.state[this.id]!.interfaces?.value || []);
|
||||
const prop = p.toString();
|
||||
const isValidProperty = this.systemManager.propertyInterfaces?.[prop] || propertyInterfaces[prop];
|
||||
|
||||
// this will also return old properties that should not exist on a device. ie, a disabled mixin provider.
|
||||
// should this change?
|
||||
if (isValidProperty)
|
||||
return (this.systemManager.state[this.id] as any)?.[p]?.value;
|
||||
return (this.systemManager.state[this.id]! as any)?.[p]?.value;
|
||||
|
||||
if (!isValidInterfaceMethod(this.systemManager.descriptors || ScryptedInterfaceDescriptors, interfaces, prop))
|
||||
return;
|
||||
|
||||
if (ScryptedInterfaceDescriptors[ScryptedInterface.ScryptedDevice].methods.includes(prop))
|
||||
if (ScryptedInterfaceDescriptors[ScryptedInterface.ScryptedDevice]!.methods.includes(prop))
|
||||
return (this as any)[p].bind(this);
|
||||
|
||||
return new Proxy(() => p, this);
|
||||
@@ -98,7 +98,7 @@ class DeviceProxyHandler implements PrimitiveProxyHandler<any> {
|
||||
ensureDevice() {
|
||||
if (!this.device)
|
||||
this.device = this.systemManager.api.getDeviceById(this.id);
|
||||
return this.device;
|
||||
return this.device!;
|
||||
}
|
||||
|
||||
async apply(target: any, thisArg: any, argArray?: any) {
|
||||
@@ -133,7 +133,7 @@ class DeviceProxyHandler implements PrimitiveProxyHandler<any> {
|
||||
|
||||
|
||||
class EventListenerRegisterImpl implements EventListenerRegister {
|
||||
promise: Promise<EventListenerRegister>;
|
||||
promise: Promise<EventListenerRegister> | undefined;
|
||||
constructor(promise: Promise<EventListenerRegister>) {
|
||||
this.promise = promise;
|
||||
}
|
||||
@@ -152,21 +152,21 @@ class EventListenerRegisterImpl implements EventListenerRegister {
|
||||
function makeOneWayCallback<T>(input: T): T {
|
||||
const f: any = input;
|
||||
const oneways: string[] = f[RpcPeer.PROPERTY_PROXY_ONEWAY_METHODS] || [];
|
||||
if (!oneways.includes(null))
|
||||
oneways.push(null);
|
||||
if (!oneways.includes(null!))
|
||||
oneways.push(null!);
|
||||
f[RpcPeer.PROPERTY_PROXY_ONEWAY_METHODS] = oneways;
|
||||
return input;
|
||||
}
|
||||
|
||||
export class SystemManagerImpl implements SystemManager {
|
||||
api: PluginAPI;
|
||||
state: { [id: string]: { [property: string]: SystemDeviceState } };
|
||||
api!: PluginAPI;
|
||||
state!: { [id: string]: { [property: string]: SystemDeviceState } };
|
||||
deviceProxies: { [id: string]: ScryptedDevice } = {};
|
||||
log: Logger;
|
||||
log!: Logger;
|
||||
events = new EventRegistry();
|
||||
typesVersion: string;
|
||||
descriptors: { [scryptedInterface: string]: ScryptedInterfaceDescriptor };
|
||||
propertyInterfaces: ReturnType<typeof getPropertyInterfaces>;
|
||||
typesVersion!: string;
|
||||
descriptors!: { [scryptedInterface: string]: ScryptedInterfaceDescriptor };
|
||||
propertyInterfaces!: ReturnType<typeof getPropertyInterfaces>;
|
||||
|
||||
getDeviceState(id: string) {
|
||||
return this.state[id];
|
||||
@@ -197,9 +197,9 @@ export class SystemManagerImpl implements SystemManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!id)
|
||||
if (!id!)
|
||||
return;
|
||||
let proxy = this.deviceProxies[id];
|
||||
let proxy = this.deviceProxies[id!];
|
||||
if (!proxy)
|
||||
proxy = this.deviceProxies[id] = newDeviceProxy(id, this);
|
||||
return proxy;
|
||||
@@ -207,10 +207,10 @@ export class SystemManagerImpl implements SystemManager {
|
||||
|
||||
getDeviceByName(name: string): any {
|
||||
for (const id of Object.keys(this.state)) {
|
||||
const s = this.state[id];
|
||||
const s = this.state[id]!;
|
||||
if ((s.interfaces?.value as string[])?.includes(ScryptedInterface.ScryptedPlugin) && s.pluginId?.value === name)
|
||||
return this.getDeviceById(id);
|
||||
if (s.name.value === name)
|
||||
if (s.name!.value === name)
|
||||
return this.getDeviceById(id);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user