diff --git a/functions.ts b/functions.ts index 017eb9eb..278ff9d3 100644 --- a/functions.ts +++ b/functions.ts @@ -140,7 +140,9 @@ export function map(iterable: Iterable< onNewEntry: (v,k) => { (mapped as U[])[k] = v }, - onEmpty: () => (mapped as U[]).length = 0 + onEmpty: () => { + (mapped as U[]).length = 0 + } }) } @@ -197,7 +199,7 @@ export const select = toggle; * @param a input value * @param b input value */ -export function equals(a:RefLike|T, b: RefLike|V): T extends V ? (V extends T ? Datex.Pointer : Datex.Pointer) : Datex.Pointer { +export function equals(a:RefLike|T, b: RefLike|V): Datex.Pointer { return transform([a, b], (a,b) => Datex.Ref.collapseValue(a, true, true) === Datex.Ref.collapseValue(b, true, true), // dx transforms not working correctly (with uix) /*`always (${Runtime.valueToDatexString(a)} === ${Runtime.valueToDatexString(b)})`*/) as any; diff --git a/runtime/runtime.ts b/runtime/runtime.ts index b3648527..66115cba 100644 --- a/runtime/runtime.ts +++ b/runtime/runtime.ts @@ -5165,7 +5165,7 @@ export class Runtime { }).filter(o => o && !(o.equals(Runtime.endpoint) || o.equals(SCOPE.sender)))) ]; if (origins.length > 1) { - logger.debug("pre-fetching online state for "+ origins.length + " endpoints", content) + logger.debug("pre-fetching online state for "+ origins.length + " endpoints") await Promise.race([ Promise.all(origins.map(origin => origin.isOnline())), new Promise(resolve => setTimeout(resolve, 10_000)) diff --git a/runtime/storage.ts b/runtime/storage.ts index 1f95f190..fad97073 100644 --- a/runtime/storage.ts +++ b/runtime/storage.ts @@ -899,7 +899,7 @@ export namespace Storage { // @ts-ignore NO_INIT if (!globalThis.NO_INIT) { - addEventListener("unload", ()=>Storage.handleExit(), {capture: true}); + if (client_type == "deno") addEventListener("unload", ()=>Storage.handleExit(), {capture: true}); addEventListener("beforeunload", ()=>Storage.handleExit(), {capture: true}); // @ts-ignore document if (globalThis.document) addEventListener("visibilitychange", ()=>{ diff --git a/types/function-utils.ts b/types/function-utils.ts index dabfdf50..5e94fb70 100644 --- a/types/function-utils.ts +++ b/types/function-utils.ts @@ -116,7 +116,7 @@ export async function getDeclaredExternalVariablesAsync(fn: (...args:unknown[])= export function getSourceWithoutUsingDeclaration(fn: (...args:unknown[])=>unknown) { let fnSource = fn.toString(); // object methods check if 'this' context is component context; - if (isObjectMethod(fnSource)) { + if (!isNormalFunction(fnSource) && !isArrowFunction(fnSource) && isObjectMethod(fnSource)) { if (fnSource.startsWith("async")) fnSource = fnSource.replace("async", "async function") else fnSource = "function " + fnSource } @@ -124,9 +124,16 @@ export function getSourceWithoutUsingDeclaration(fn: (...args:unknown[])=>unknow .replace(/(?<=(?:(?:[\w\s*])+\(.*\)\s*{|\(.*\)\s*=>\s*{?|.*\s*=>\s*{?)\s*)(use\s*\((?:[\s\S]*?)\))/, 'true /*$1*/') } -function isObjectMethod(fnSrc:string) { +const isObjectMethod = (fnSrc:string) => { return !!fnSrc.match(/^(async\s+)?[^\s(]+ *(\(|\*)/) } +const isNormalFunction = (fnSrc:string) => { + return !!fnSrc.match(/^(async\s+)?function(\(| |\*)/) +} +const isArrowFunction = (fnSrc:string) => { + return !!fnSrc.match(/^(async\s+)?\([^)]*\)\s*=>/) +} + /** * Create a new function from JS source code with injected dependency variables diff --git a/utils/iterable-handler.ts b/utils/iterable-handler.ts index ed76c516..1268943b 100644 --- a/utils/iterable-handler.ts +++ b/utils/iterable-handler.ts @@ -6,14 +6,14 @@ export class IterableHandler { private map: ((value: T, index: number, array: Iterable) => U) | undefined private onNewEntry: (entry:U, key:number,) => void private onEntryRemoved: (entry:U, key:number,) => void - private onEmpty: () => void + private onEmpty?: () => void constructor(private iterable: Datex.RefOrValue>, callbacks: { map?: (value: T, index: number, array: Iterable) => U, onNewEntry: (this: IterableHandler, entry:U, key:number) => void onEntryRemoved: (entry: U, key:number) => void, - onEmpty: () => void + onEmpty?: () => void }) { this.map = callbacks.map; this.onNewEntry = callbacks.onNewEntry; @@ -102,10 +102,17 @@ export class IterableHandler { // single property update if (type == Datex.Ref.UPDATE_TYPE.SET) this.handleNewEntry(value, key) else if (type == Datex.Ref.UPDATE_TYPE.ADD) this.handleNewEntry(value, this.getPseudoIndex(key, value)); - // property removed + // clear all else if (type == Datex.Ref.UPDATE_TYPE.CLEAR) { - for (const [key,] of this.#entries??[]) { - this.handleRemoveEntry(key); + // handle onEmpty + if (this.onEmpty) { + this.onEmpty.call ? this.onEmpty.call(this) : this.onEmpty(); + } + // alternative: delete all entries individually + else { + for (const [key,] of [...this.#entries??[]].toReversed()) { + this.handleRemoveEntry(key); + } } } else if (type == Datex.Ref.UPDATE_TYPE.BEFORE_DELETE) this.handleRemoveEntry(key); @@ -130,7 +137,8 @@ export class IterableHandler { const entry = this.valueToEntry(value, key) if (key != undefined) { - if (this.entries.has(key)) this.handleRemoveEntry(key) // entry is overridden + // TODO: is this correct + if (!this.isPseudoIndex() && this.entries.has(key)) this.handleRemoveEntry(key) // entry is overridden this.entries.set(key, entry); } this.onNewEntry.call ? this.onNewEntry.call(this, entry, Number(key)) : this.onNewEntry(entry, Number(key)); // new entry handler @@ -142,11 +150,12 @@ export class IterableHandler { const entry = this.entries.get(key)!; this.deleteEntry(key); this.onEntryRemoved.call ? this.onEntryRemoved.call(this, entry, key) : this.onEntryRemoved(entry, key); + this.checkEmpty(); } private checkEmpty() { - if (this.#entries?.size == 0) this.onEmpty.call ? this.onEmpty.call(this) : this.onEmpty(); + if (this.onEmpty && this.#entries?.size == 0) this.onEmpty.call ? this.onEmpty.call(this) : this.onEmpty(); } } \ No newline at end of file