@lit-labs/task
Advanced tools
Comparing version 1.0.0-pre.1 to 1.0.0-pre.2
@@ -20,2 +20,15 @@ # Change Log | ||
## 1.0.0-pre.2 - 2021-03-31 | ||
### Changed | ||
- Added result and dependency type arguments to Task | ||
### Added | ||
- Added an `initialState` sentinal value that task functions can return to reset the task state to INITIAL. | ||
<!-- ### Removed --> | ||
<!-- ### Fixed --> | ||
## [1.0.0-pre.1] - 2021-02-11 | ||
@@ -25,2 +38,2 @@ | ||
- Adds `Task` controller which can be used to perform tasks when a host element updates. When the task completes, an update is requested on the host element and the task value can be used as desired ([#1489](https://github.com/Polymer/lit-html/pulls/1489)). | ||
- Adds `Task` controller which can be used to perform tasks when a host element updates. When the task completes, an update is requested on the host element and the task value can be used as desired ([#1489](https://github.com/Polymer/lit-html/pulls/1489)). |
/** | ||
* @license | ||
* Copyright (c) 2017 The Polymer Project Authors. All rights reserved. | ||
* This code may only be used under the BSD style license found at | ||
* http://polymer.github.io/LICENSE.txt | ||
* The complete set of authors may be found at | ||
* http://polymer.github.io/AUTHORS.txt | ||
* The complete set of contributors may be found at | ||
* http://polymer.github.io/CONTRIBUTORS.txt | ||
* Code distributed by Google as part of the polymer project is also | ||
* subject to an additional IP rights grant found at | ||
* http://polymer.github.io/PATENTS.txt | ||
* Copyright 2017 Google LLC | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
*/ | ||
export * from './task.js'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -1,2 +0,2 @@ | ||
export{Task,TaskStatus}from"./task.js"; | ||
export{Task,TaskStatus,initialState}from"./task.js"; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@lit-labs/task", | ||
"version": "1.0.0-pre.1", | ||
"version": "1.0.0-pre.2", | ||
"description": "A controller for Lit that renders asynchronous tasks.", | ||
@@ -28,7 +28,8 @@ "license": "BSD-3-Clause", | ||
"scripts": { | ||
"build": "npm run clean && tsc --build && rollup -c", | ||
"build": "npm run clean && npm run build:ts --build && rollup -c", | ||
"build:watch": "rollup -c --watch", | ||
"build:ts": "tsc --build && treemirror development . '**/*.d.ts{,.map}'", | ||
"build:ts:watch": "tsc --build --watch", | ||
"clean": "rm -rf {index,task}.{js,js.map,d.ts} development/ test/ *.tsbuildinfo", | ||
"dev": "scripts/dev.sh", | ||
"build:ts": "tsc", | ||
"build:ts:watch": "tsc --watch", | ||
"test": "npm run test:dev && npm run test:prod", | ||
@@ -41,7 +42,7 @@ "test:dev": "cd ../../tests && npx wtr '../labs/task/development/**/*_test.js'", | ||
}, | ||
"author": "The Polymer Authors", | ||
"author": "Google LLC", | ||
"devDependencies": { | ||
"@esm-bundle/chai": "^4.1.5", | ||
"@types/chai": "^4.0.1", | ||
"@types/mocha": "^8.0.3", | ||
"@types/chai": "^4.0.1", | ||
"@types/trusted-types": "^1.0.1", | ||
@@ -53,6 +54,7 @@ "@web/test-runner-mocha": "^0.3.5", | ||
"rollup": "^2.28.2", | ||
"typescript": "^4.1.3" | ||
"typescript": "^4.1.3", | ||
"internal-scripts": "^1.0.0" | ||
}, | ||
"dependencies": { | ||
"@lit/reactive-element": "^1.0.0-pre.2" | ||
"@lit/reactive-element": "^1.0.0-pre.3" | ||
}, | ||
@@ -59,0 +61,0 @@ "publishConfig": { |
/** | ||
* @license | ||
* Copyright (c) 2017 The Polymer Project Authors. All rights reserved. | ||
* This code may only be used under the BSD style license found at | ||
* http://polymer.github.io/LICENSE.txt | ||
* The complete set of authors may be found at | ||
* http://polymer.github.io/AUTHORS.txt | ||
* The complete set of contributors may be found at | ||
* http://polymer.github.io/CONTRIBUTORS.txt | ||
* Code distributed by Google as part of the polymer project is also | ||
* subject to an additional IP rights grant found at | ||
* http://polymer.github.io/PATENTS.txt | ||
* Copyright 2017 Google LLC | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
*/ | ||
export * from './task.js'; |
/** | ||
* @license | ||
* Copyright (c) 2017 The Polymer Project Authors. All rights reserved. | ||
* This code may only be used under the BSD style license found at | ||
* http://polymer.github.io/LICENSE.txt | ||
* The complete set of authors may be found at | ||
* http://polymer.github.io/AUTHORS.txt | ||
* The complete set of contributors may be found at | ||
* http://polymer.github.io/CONTRIBUTORS.txt | ||
* Code distributed by Google as part of the polymer project is also | ||
* subject to an additional IP rights grant found at | ||
* http://polymer.github.io/PATENTS.txt | ||
* Copyright 2017 Google LLC | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
*/ | ||
@@ -17,5 +9,7 @@ import {notEqual} from '@lit/reactive-element'; | ||
export type TaskFunction = (args: Array<unknown>) => unknown; | ||
export type Deps = Array<unknown>; | ||
export type DepsFunction = () => Deps; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
export type TaskFunction<D extends [...unknown[]], R = any> = ( | ||
args: D | ||
) => R | typeof initialState | Promise<R | typeof initialState>; | ||
export type DepsFunction<D extends [...unknown[]]> = () => D; | ||
@@ -32,8 +26,14 @@ /** | ||
/** | ||
* A special value that can be returned from task functions to reset the task | ||
* status to INITIAL. | ||
*/ | ||
export const initialState = Symbol(); | ||
export type TaskStatus = typeof TaskStatus[keyof typeof TaskStatus]; | ||
export type StatusRenderer = { | ||
export type StatusRenderer<R> = { | ||
initial?: () => unknown; | ||
pending?: () => unknown; | ||
complete?: (value: unknown) => unknown; | ||
complete?: (value: R) => unknown; | ||
error?: (error: unknown) => unknown; | ||
@@ -89,16 +89,27 @@ }; | ||
*/ | ||
export class Task { | ||
private _previousDeps: Deps = []; | ||
private _task: TaskFunction; | ||
private _getDependencies: DepsFunction; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
export class Task<T extends [...unknown[]] = any, R = any> { | ||
private _previousDeps: T = ([] as unknown) as T; | ||
private _task: TaskFunction<T, R>; | ||
private _getDependencies: DepsFunction<T>; | ||
private _callId = 0; | ||
private _host: ReactiveControllerHost; | ||
private _value?: unknown; | ||
private _value?: R; | ||
private _error?: unknown; | ||
status: TaskStatus = TaskStatus.INITIAL; | ||
/** | ||
* A Promise that resolve when the current task run is complete. | ||
* | ||
* If a new task run is started while a previous run is pending, the Promise | ||
* is kept and only resolved when the new run is completed. | ||
*/ | ||
taskComplete!: Promise<R>; | ||
private _resolveTaskComplete!: (value: R) => void; | ||
private _rejectTaskComplete!: (e: unknown) => void; | ||
constructor( | ||
host: ReactiveControllerHost, | ||
task: TaskFunction, | ||
getDependencies: DepsFunction | ||
task: TaskFunction<T, R>, | ||
getDependencies: DepsFunction<T> | ||
) { | ||
@@ -109,2 +120,6 @@ this._host = host; | ||
this._getDependencies = getDependencies; | ||
this.taskComplete = new Promise((res, rej) => { | ||
this._resolveTaskComplete = res; | ||
this._rejectTaskComplete = rej; | ||
}); | ||
} | ||
@@ -119,6 +134,15 @@ | ||
if (this._isDirty(deps)) { | ||
if ( | ||
this.status === TaskStatus.COMPLETE || | ||
this.status === TaskStatus.ERROR | ||
) { | ||
this.taskComplete = new Promise((res, rej) => { | ||
this._resolveTaskComplete = res; | ||
this._rejectTaskComplete = rej; | ||
}); | ||
} | ||
this.status = TaskStatus.PENDING; | ||
this._error = undefined; | ||
this._value = undefined; | ||
let value: unknown; | ||
let result!: R | typeof initialState; | ||
let error: unknown; | ||
@@ -129,3 +153,3 @@ // Request an update to report pending state. | ||
try { | ||
value = await this._task(deps); | ||
result = await this._task(deps); | ||
} catch (e) { | ||
@@ -136,6 +160,15 @@ error = e; | ||
if (this._callId === key) { | ||
this.status = | ||
error === undefined ? TaskStatus.COMPLETE : TaskStatus.ERROR; | ||
this._value = value; | ||
this._error = error; | ||
if (result === initialState) { | ||
this.status = TaskStatus.INITIAL; | ||
} else { | ||
if (error === undefined) { | ||
this.status = TaskStatus.COMPLETE; | ||
this._resolveTaskComplete(result as R); | ||
} else { | ||
this.status = TaskStatus.ERROR; | ||
this._rejectTaskComplete(error); | ||
} | ||
this._value = result as R; | ||
this._error = error; | ||
} | ||
// Request an update with the final value. | ||
@@ -155,3 +188,3 @@ this._host.requestUpdate(); | ||
render(renderer: StatusRenderer) { | ||
render(renderer: StatusRenderer<R>) { | ||
switch (this.status) { | ||
@@ -163,9 +196,12 @@ case TaskStatus.INITIAL: | ||
case TaskStatus.COMPLETE: | ||
return renderer.complete?.(this.value); | ||
return renderer.complete?.(this.value!); | ||
case TaskStatus.ERROR: | ||
return renderer.error?.(this.error); | ||
default: | ||
// exhaustiveness check | ||
this.status as void; | ||
} | ||
} | ||
private _isDirty(deps: Deps) { | ||
private _isDirty(deps: T) { | ||
let i = 0; | ||
@@ -172,0 +208,0 @@ const previousDeps = this._previousDeps; |
import { ReactiveControllerHost } from '@lit/reactive-element/reactive-controller.js'; | ||
export declare type TaskFunction = (args: Array<unknown>) => unknown; | ||
export declare type Deps = Array<unknown>; | ||
export declare type DepsFunction = () => Deps; | ||
export declare type TaskFunction<D extends [...unknown[]], R = any> = (args: D) => R | typeof initialState | Promise<R | typeof initialState>; | ||
export declare type DepsFunction<D extends [...unknown[]]> = () => D; | ||
/** | ||
@@ -14,7 +13,12 @@ * States for task status | ||
}; | ||
/** | ||
* A special value that can be returned from task functions to reset the task | ||
* status to INITIAL. | ||
*/ | ||
export declare const initialState: unique symbol; | ||
export declare type TaskStatus = typeof TaskStatus[keyof typeof TaskStatus]; | ||
export declare type StatusRenderer = { | ||
export declare type StatusRenderer<R> = { | ||
initial?: () => unknown; | ||
pending?: () => unknown; | ||
complete?: (value: unknown) => unknown; | ||
complete?: (value: R) => unknown; | ||
error?: (error: unknown) => unknown; | ||
@@ -53,3 +57,3 @@ }; | ||
*/ | ||
export declare class Task { | ||
export declare class Task<T extends [...unknown[]] = any, R = any> { | ||
private _previousDeps; | ||
@@ -63,10 +67,19 @@ private _task; | ||
status: TaskStatus; | ||
constructor(host: ReactiveControllerHost, task: TaskFunction, getDependencies: DepsFunction); | ||
/** | ||
* A Promise that resolve when the current task run is complete. | ||
* | ||
* If a new task run is started while a previous run is pending, the Promise | ||
* is kept and only resolved when the new run is completed. | ||
*/ | ||
taskComplete: Promise<R>; | ||
private _resolveTaskComplete; | ||
private _rejectTaskComplete; | ||
constructor(host: ReactiveControllerHost, task: TaskFunction<T, R>, getDependencies: DepsFunction<T>); | ||
hostUpdated(): void; | ||
private _completeTask; | ||
get value(): unknown; | ||
get value(): R | undefined; | ||
get error(): unknown; | ||
render(renderer: StatusRenderer): unknown; | ||
render(renderer: StatusRenderer<R>): unknown; | ||
private _isDirty; | ||
} | ||
//# sourceMappingURL=task.d.ts.map |
14
task.js
import{notEqual as t}from"@lit/reactive-element"; | ||
/** | ||
* @license | ||
* Copyright (c) 2017 The Polymer Project Authors. All rights reserved. | ||
* This code may only be used under the BSD style license found at | ||
* http://polymer.github.io/LICENSE.txt | ||
* The complete set of authors may be found at | ||
* http://polymer.github.io/AUTHORS.txt | ||
* The complete set of contributors may be found at | ||
* http://polymer.github.io/CONTRIBUTORS.txt | ||
* Code distributed by Google as part of the polymer project is also | ||
* subject to an additional IP rights grant found at | ||
* http://polymer.github.io/PATENTS.txt | ||
*/const s={INITIAL:0,PENDING:1,COMPLETE:2,ERROR:3};class i{constructor(t,s,i){this.t=[],this.i=0,this.status=0,this.h=t,this.h.addController(this),this.o=s,this.u=i}hostUpdated(){this.l()}async l(){const t=this.u();if(this.v(t)){let s,i;this.status=1,this.m=void 0,this.p=void 0,this.h.requestUpdate();const h=++this.i;try{s=await this.o(t)}catch(t){i=t}this.i===h&&(this.status=void 0===i?2:3,this.p=s,this.m=i,this.h.requestUpdate())}}get value(){return this.p}get error(){return this.m}render(t){switch(this.status){case 0:return t.initial?.();case 1:return t.pending?.();case 2:return t.complete?.(this.value);case 3:return t.error?.(this.error)}}v(s){let i=0;const h=this.t;this.t=s;for(const r of s){if(t(r,h[i]))return!0;i++}return!1}}export{i as Task,s as TaskStatus}; | ||
* Copyright 2017 Google LLC | ||
* SPDX-License-Identifier: BSD-3-Clause | ||
*/const i={INITIAL:0,PENDING:1,COMPLETE:2,ERROR:3},s=Symbol();class h{constructor(t,i,s){this.t=[],this.i=0,this.status=0,this.h=t,this.h.addController(this),this.o=i,this.l=s,this.taskComplete=new Promise(((t,i)=>{this.u=t,this.v=i}))}hostUpdated(){this.m()}async m(){const t=this.l();if(this.p(t)){let i,h;2!==this.status&&3!==this.status||(this.taskComplete=new Promise(((t,i)=>{this.u=t,this.v=i}))),this.status=1,this.g=void 0,this._=void 0,this.h.requestUpdate();const e=++this.i;try{i=await this.o(t)}catch(t){h=t}this.i===e&&(i===s?this.status=0:(void 0===h?(this.status=2,this.u(i)):(this.status=3,this.v(h)),this._=i,this.g=h),this.h.requestUpdate())}}get value(){return this._}get error(){return this.g}render(t){var i,s,h,e;switch(this.status){case 0:return null===(i=t.initial)||void 0===i?void 0:i.call(t);case 1:return null===(s=t.pending)||void 0===s?void 0:s.call(t);case 2:return null===(h=t.complete)||void 0===h?void 0:h.call(t,this.value);case 3:return null===(e=t.error)||void 0===e?void 0:e.call(t,this.error);default:this.status}}p(i){let s=0;const h=this.t;this.t=i;for(const e of i){if(t(e,h[s]))return!0;s++}return!1}}export{h as Task,i as TaskStatus,s as initialState}; | ||
//# sourceMappingURL=task.js.map |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
28381
14
300
11