diff --git a/.changeset/smart-pianos-kick.md b/.changeset/smart-pianos-kick.md new file mode 100644 index 0000000000..437c92fced --- /dev/null +++ b/.changeset/smart-pianos-kick.md @@ -0,0 +1,10 @@ +--- +'@lit/task': patch +--- + +Make `status` of Task a readonly property + +So far `status` was writable which allowed for setting status of task form outside. Doing so did cause rendering of +expected template but the task was becoming internally incoherent. + +Now attempt to assign `status` will end up in throwing a `TypeError`. diff --git a/packages/task/src/task.ts b/packages/task/src/task.ts index 7c4ad85ada..b87b5f0b0c 100644 --- a/packages/task/src/task.ts +++ b/packages/task/src/task.ts @@ -180,7 +180,7 @@ export class Task< private _abortController?: AbortController; private _onComplete?: (result: R) => unknown; private _onError?: (error: unknown) => unknown; - status: TaskStatus = TaskStatus.INITIAL; + private _status: TaskStatus = TaskStatus.INITIAL; /** * Determines if the task is run automatically when arguments change after a @@ -206,13 +206,13 @@ export class Task< // Generate an in-progress promise if the status is pending and has been // cleared by .run(). - if (this.status === TaskStatus.PENDING) { + if (this._status === TaskStatus.PENDING) { this._taskComplete = new Promise((res, rej) => { this._resolveTaskComplete = res; this._rejectTaskComplete = rej; }); // If the status is error, return a rejected promise. - } else if (this.status === TaskStatus.ERROR) { + } else if (this._status === TaskStatus.ERROR) { this._taskComplete = Promise.reject(this._error); // Otherwise we are at a task run's completion or this is the first // request and we are not in the middle of a task (i.e. INITIAL). @@ -251,7 +251,7 @@ export class Task< // args immediately so it only runs when they change again. if ('initialValue' in taskConfig) { this._value = taskConfig.initialValue; - this.status = TaskStatus.COMPLETE; + this._status = TaskStatus.COMPLETE; this._previousArgs = this._getArgs?.(); } } @@ -318,7 +318,7 @@ export class Task< // TODO (justinfagnani): add test this._previousArgs = args; - if (this.status === TaskStatus.PENDING) { + if (this._status === TaskStatus.PENDING) { this._abortController?.abort(); } else { // Clear the last complete task run in INITIAL because it may be a resolved @@ -329,7 +329,7 @@ export class Task< this._rejectTaskComplete = undefined; } - this.status = TaskStatus.PENDING; + this._status = TaskStatus.PENDING; let result!: R | typeof initialState; let error: unknown; @@ -353,7 +353,7 @@ export class Task< // If this is the most recent task call, process this value. if (this._callId === key) { if (result === initialState) { - this.status = TaskStatus.INITIAL; + this._status = TaskStatus.INITIAL; } else { if (errored === false) { try { @@ -361,7 +361,7 @@ export class Task< } catch { // Ignore user errors from onComplete. } - this.status = TaskStatus.COMPLETE; + this._status = TaskStatus.COMPLETE; this._resolveTaskComplete?.(result as R); } else { try { @@ -369,7 +369,7 @@ export class Task< } catch { // Ignore user errors from onError. } - this.status = TaskStatus.ERROR; + this._status = TaskStatus.ERROR; this._rejectTaskComplete?.(error); } this._value = result as R; @@ -399,7 +399,7 @@ export class Task< * `AbortController.abort()`. */ abort(reason?: unknown) { - if (this.status === TaskStatus.PENDING) { + if (this._status === TaskStatus.PENDING) { this._abortController?.abort(reason); } } @@ -423,8 +423,12 @@ export class Task< return this._error; } + get status() { + return this._status; + } + render>(renderer: T) { - switch (this.status) { + switch (this._status) { case TaskStatus.INITIAL: return renderer.initial?.() as MaybeReturnType; case TaskStatus.PENDING: @@ -436,7 +440,7 @@ export class Task< case TaskStatus.ERROR: return renderer.error?.(this.error) as MaybeReturnType; default: - throw new Error(`Unexpected status: ${this.status}`); + throw new Error(`Unexpected status: ${this._status}`); } } } diff --git a/packages/task/src/test/task_test.ts b/packages/task/src/test/task_test.ts index cbc0f8528d..62ec26ef62 100644 --- a/packages/task/src/test/task_test.ts +++ b/packages/task/src/test/task_test.ts @@ -411,6 +411,18 @@ suite('Task', () => { assert.equal(el.taskValue, `a1,b`); }); + test('task `status` is not settable', async () => { + const el = getTestElement({args: () => [el.a, el.b], autoRun: false}); + await renderElement(el); + await tasksUpdateComplete(); + assert.equal(el.task.status, TaskStatus.INITIAL); + + assert.throws(() => { + // @ts-expect-error for test + el.task.status = TaskStatus.ERROR; + }, TypeError); + }); + test('task runs when `run` called', async () => { const el = getTestElement({args: () => [el.a, el.b], autoRun: false}); await renderElement(el);