style: format state subscriptions and their adopted controls

This commit is contained in:
Sameh Khamis committed 2026-09-13 05:43:05 -07:00
1 parent 45d97376d0
commit e0652b19f2
12 files changed
+299 -88

No files matched your search

+77 -14
View File
@@ -2,16 +2,50 @@ import { createStateChannel } from '../app/stateChannel.js';
/** One cancellable place lookup at a time, under the caller's camera authority. */
export class LocationSearch {
constructor({ input, begin, isCurrent, beforeFly, search, onStart, onResult, onMissing, onError, onSettled }) {
Object.assign(this, { input, begin, isCurrent, beforeFly, search, onStart, onResult, onMissing, onError, onSettled });
constructor({
input,
begin,
isCurrent,
beforeFly,
search,
onStart,
onResult,
onMissing,
onError,
onSettled,
}) {
Object.assign(this, {
input,
begin,
isCurrent,
beforeFly,
search,
onStart,
onResult,
onMissing,
onError,
onSettled,
});
this.controller = null;
this.generation = 0;
this.destroyed = false;
this.state = { status: 'idle', searching: false, query: '', generation: null, requestId: 0, destination: null, error: null };
this.state = {
status: 'idle',
searching: false,
query: '',
generation: null,
requestId: 0,
destination: null,
error: null,
};
this.channel = createStateChannel(() => this.state);
}
getState() { return this.channel.getSnapshot(); }
subscribe(listener, options) { return this.channel.subscribe(listener, options); }
getState() {
return this.channel.getSnapshot();
}
subscribe(listener, options) {
return this.channel.subscribe(listener, options);
}
async run(query) {
query = String(query || '').trim();
if (!query || this.destroyed) return;
@@ -25,9 +59,25 @@ export class LocationSearch {
const controller = new AbortController();
this.controller = controller;
const generation = ++this.generation;
const current = () => !this.destroyed && generation === this.generation && this.isCurrent(authority);
const change = (type) => ({ type, generation: authority, requestId: generation, query });
this.state = { status: 'searching', searching: true, query, generation: authority, requestId: generation, destination: null, error: null };
const current = () =>
!this.destroyed &&
generation === this.generation &&
this.isCurrent(authority);
const change = (type) => ({
type,
generation: authority,
requestId: generation,
query,
});
this.state = {
status: 'searching',
searching: true,
query,
generation: authority,
requestId: generation,
destination: null,
error: null,
};
try {
this.onStart?.(authority);
if (!current() || controller.signal.aborted) return;
@@ -43,7 +93,11 @@ export class LocationSearch {
if (destination) {
this.onResult?.(destination, query);
if (!current() || controller.signal.aborted) return;
this.state = { ...this.state, status: 'found', destination: { ...destination } };
this.state = {
...this.state,
status: 'found',
destination: { ...destination },
};
this.channel.publish(change('found'));
} else {
this.onMissing?.();
@@ -55,15 +109,24 @@ export class LocationSearch {
if (controller.signal.aborted || !current()) return;
this.onError?.(error);
if (!current() || controller.signal.aborted) return;
this.state = { ...this.state, status: 'failed', error: { message: String(error?.message || error) } };
this.state = {
...this.state,
status: 'failed',
error: { message: String(error?.message || error) },
};
this.channel.publish(change('failed'));
} finally {
if (this.controller === controller) this.controller = null;
if (!this.destroyed) {
if (generation === this.generation) this.state = {
...this.state, searching: false,
status: this.state.status === 'searching' ? 'cancelled' : this.state.status,
};
if (generation === this.generation)
this.state = {
...this.state,
searching: false,
status:
this.state.status === 'searching'
? 'cancelled'
: this.state.status,
};
this.onSettled?.(authority);
this.channel.publish(change('settled'));
}