New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@lit-labs/task

Package Overview
Dependencies
Maintainers
11
Versions
21
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@lit-labs/task - npm Package Compare versions

Comparing version 3.0.2 to 3.1.0-pre.0

29

deep-equals.d.ts

@@ -6,20 +6,17 @@ /**

*/
export declare const deepArrayEquals: <T extends readonly unknown[]>(oldArgs: T, newArgs: T) => boolean;
/**
* Recursively checks two objects for equality.
*
* This function handles the following cases:
* - Primitives: primitives compared with Object.is()
* - Objects: to be equal, two objects must:
* - have the same constructor
* - have same set of own property names
* - have each own property be deeply equal
* - Arrays, Maps, Sets, and RegExps
* - Objects with custom valueOf() (ex: Date)
* - Objects with custom toString() (ex: URL)
*
* Important: Objects must be free of cycles, otherwise this function will
* run infinitely!
* You can import directly from @lit/task/deep-equals.js now.
* @deprecated
*/
export declare const deepEquals: (a: unknown, b: unknown) => boolean;
export {
/**
* You can import directly from @lit/task/deep-equals.js now.
* @deprecated
*/
deepArrayEquals,
/**
* You can import directly from @lit/task/deep-equals.js now.
* @deprecated
*/
deepEquals, } from '@lit/task/deep-equals.js';
//# sourceMappingURL=deep-equals.d.ts.map

@@ -1,7 +0,2 @@

/**
* @license
* Copyright 2023 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
const r=(r,t)=>r===t||r.length===t.length&&r.every(((r,e)=>i(r,t[e]))),t=Object.prototype.valueOf,e=Object.prototype.toString,{keys:n}=Object,{isArray:f}=Array,i=(r,o)=>{if(Object.is(r,o))return!0;if(null!==r&&null!==o&&"object"==typeof r&&"object"==typeof o){if(r.constructor!==o.constructor)return!1;if(f(r))return r.length===o.length&&r.every(((r,t)=>i(r,o[t])));if(r.valueOf!==t)return r.valueOf()===o.valueOf();if(r.toString!==e)return r.toString()===o.toString();if(r instanceof Map&&o instanceof Map){if(r.size!==o.size)return!1;for(const[t,e]of r.entries())if(!1===i(e,o.get(t))||void 0===e&&!1===o.has(t))return!1;return!0}if(r instanceof Set&&o instanceof Set){if(r.size!==o.size)return!1;for(const t of r.keys())if(!1===o.has(t))return!1;return!0}if(r instanceof RegExp)return r.source===o.source&&r.flags===o.flags;const u=n(r);if(u.length!==n(o).length)return!1;for(const t of u)if(!o.hasOwnProperty(t)||!i(r[t],o[t]))return!1;return!0}return!1};export{r as deepArrayEquals,i as deepEquals};
export{deepArrayEquals,deepEquals}from"@lit/task/deep-equals.js";
//# sourceMappingURL=deep-equals.js.map

@@ -6,20 +6,17 @@ /**

*/
export declare const deepArrayEquals: <T extends readonly unknown[]>(oldArgs: T, newArgs: T) => boolean;
/**
* Recursively checks two objects for equality.
*
* This function handles the following cases:
* - Primitives: primitives compared with Object.is()
* - Objects: to be equal, two objects must:
* - have the same constructor
* - have same set of own property names
* - have each own property be deeply equal
* - Arrays, Maps, Sets, and RegExps
* - Objects with custom valueOf() (ex: Date)
* - Objects with custom toString() (ex: URL)
*
* Important: Objects must be free of cycles, otherwise this function will
* run infinitely!
* You can import directly from @lit/task/deep-equals.js now.
* @deprecated
*/
export declare const deepEquals: (a: unknown, b: unknown) => boolean;
export {
/**
* You can import directly from @lit/task/deep-equals.js now.
* @deprecated
*/
deepArrayEquals,
/**
* You can import directly from @lit/task/deep-equals.js now.
* @deprecated
*/
deepEquals, } from '@lit/task/deep-equals.js';
//# sourceMappingURL=deep-equals.d.ts.map

@@ -6,96 +6,17 @@ /**

*/
export const deepArrayEquals = (oldArgs, newArgs) => oldArgs === newArgs ||
(oldArgs.length === newArgs.length &&
oldArgs.every((v, i) => deepEquals(v, newArgs[i])));
const objectValueOf = Object.prototype.valueOf;
const objectToString = Object.prototype.toString;
const { keys: objectKeys } = Object;
const { isArray } = Array;
/**
* Recursively checks two objects for equality.
*
* This function handles the following cases:
* - Primitives: primitives compared with Object.is()
* - Objects: to be equal, two objects must:
* - have the same constructor
* - have same set of own property names
* - have each own property be deeply equal
* - Arrays, Maps, Sets, and RegExps
* - Objects with custom valueOf() (ex: Date)
* - Objects with custom toString() (ex: URL)
*
* Important: Objects must be free of cycles, otherwise this function will
* run infinitely!
* You can import directly from @lit/task/deep-equals.js now.
* @deprecated
*/
export const deepEquals = (a, b) => {
if (Object.is(a, b)) {
return true;
}
if (a !== null &&
b !== null &&
typeof a === 'object' &&
typeof b === 'object') {
// Object must have the same prototype / constructor
if (a.constructor !== b.constructor) {
return false;
}
// Arrays must have the same length and recursively equal items
if (isArray(a)) {
if (a.length !== b.length) {
return false;
}
return a.every((v, i) => deepEquals(v, b[i]));
}
// Defer to custom valueOf implementations. This handles Dates which return
// ms since epoch: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/valueOf
if (a.valueOf !== objectValueOf) {
return a.valueOf() === b.valueOf();
}
// Defer to custom toString implementations. This should handle
// TrustedTypes, URLs, and such. This might be a bit risky, but
// fast-deep-equals does it.
if (a.toString !== objectToString) {
return a.toString() === b.toString();
}
if (a instanceof Map && b instanceof Map) {
if (a.size !== b.size) {
return false;
}
for (const [k, v] of a.entries()) {
if (deepEquals(v, b.get(k)) === false ||
(v === undefined && b.has(k) === false)) {
return false;
}
}
return true;
}
if (a instanceof Set && b instanceof Set) {
if (a.size !== b.size) {
return false;
}
for (const k of a.keys()) {
if (b.has(k) === false) {
return false;
}
}
return true;
}
if (a instanceof RegExp) {
return (a.source === b.source && a.flags === b.flags);
}
// We have two objects, check every key
const keys = objectKeys(a);
if (keys.length !== objectKeys(b).length) {
return false;
}
for (const key of keys) {
if (!b.hasOwnProperty(key) || !deepEquals(a[key], b[key])) {
return false;
}
}
// All keys in the two objects have been compared!
return true;
}
return false;
};
export {
/**
* You can import directly from @lit/task/deep-equals.js now.
* @deprecated
*/
deepArrayEquals,
/**
* You can import directly from @lit/task/deep-equals.js now.
* @deprecated
*/
deepEquals, } from '@lit/task/deep-equals.js';
//# sourceMappingURL=deep-equals.js.map

@@ -1,215 +0,61 @@

import { ReactiveControllerHost } from '@lit/reactive-element/reactive-controller.js';
export interface TaskFunctionOptions {
signal: AbortSignal;
}
export declare type TaskFunction<D extends ReadonlyArray<unknown>, R = unknown> = (args: D, options: TaskFunctionOptions) => R | typeof initialState | Promise<R | typeof initialState>;
export declare type ArgsFunction<D extends ReadonlyArray<unknown>> = () => D;
export { ArgsFunction as DepsFunction };
/**
* States for task status
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
export declare const TaskStatus: {
readonly INITIAL: 0;
readonly PENDING: 1;
readonly COMPLETE: 2;
readonly ERROR: 3;
};
/**
* A special value that can be returned from task functions to reset the task
* status to INITIAL.
* You can import directly from @lit/task now.
* @deprecated
*/
export declare const initialState: unique symbol;
export declare type TaskStatus = (typeof TaskStatus)[keyof typeof TaskStatus];
export declare type StatusRenderer<R> = {
initial?: () => unknown;
pending?: () => unknown;
complete?: (value: R) => unknown;
error?: (error: unknown) => unknown;
};
export interface TaskConfig<T extends ReadonlyArray<unknown>, R> {
task: TaskFunction<T, R>;
args?: ArgsFunction<T>;
/**
* Determines if the task is run automatically when arguments change after a
* host update. Default to `true`.
*
* If `true`, the task checks arguments during the host update (after
* `willUpdate()` and before `update()` in Lit) and runs if they change. For
* a task to see argument changes they must be done in `willUpdate()` or
* earlier. The host element can see task status changes caused by its own
* current update.
*
* If `'afterUpdate'`, the task checks arguments and runs _after_ the host
* update. This means that the task can see host changes done in update, such
* as rendered DOM. The host element can not see task status changes caused
* by its own update, so the task must trigger a second host update to make
* those changes renderable.
*
* Note: `'afterUpdate'` is unlikely to be SSR compatible in the future.
*
* If `false`, the task is not run automatically, and must be run with the
* {@linkcode run} method.
*/
autoRun?: boolean | 'afterUpdate';
/**
* A function that determines if the current arg and previous args arrays are
* equal. If the argsEqual function returns true, the task will not auto-run.
*
* The default is {@linkcode shallowArrayEquals}. {@linkcode deepArrayEquals}
* is also available.
*/
argsEqual?: (oldArgs: T, newArgs: T) => boolean;
/**
* If initialValue is provided, the task is initialized to the COMPLETE
* status and the value is set to initialData.
*
* Initial args should be coherent with the initialValue, since they are
* assumed to be the args that would produce that value. When autoRun is
* `true` the task will not auto-run again until the args change.
*/
initialValue?: R;
onComplete?: (value: R) => unknown;
onError?: (error: unknown) => unknown;
}
export {
/**
* A controller that performs an asynchronous task (like a fetch) when its
* host element updates.
*
* Task requests an update on the host element when the task starts and
* completes so that the host can render the task status, value, and error as
* the task runs.
*
* The task function must be supplied and can take a list of arguments. The
* arguments are given to the Task as a function that returns a list of values,
* which is run and checked for changes on every host update.
*
* The `value` property reports the completed value, and the `error` property
* an error state if one occurs. The `status` property can be checked for
* status and is of type `TaskStatus` which has states for initial, pending,
* complete, and error.
*
* The `render` method accepts an object with optional methods corresponding
* to the task statuses to easily render different templates for each task
* status.
*
* The task is run automatically when its arguments change; however, this can
* be customized by setting `autoRun` to false and calling `run` explicitly
* to run the task.
*
* For a task to see state changes in the current update pass of the host
* element, those changes must be made in `willUpdate()`. State changes in
* `update()` or `updated()` will not be visible to the task until the next
* update pass.
*
* @example
*
* ```ts
* class MyElement extends LitElement {
* url = 'example.com/api';
* id = 0;
*
* task = new Task(
* this,
* {
* task: async ([url, id]) => {
* const response = await fetch(`${this.url}?id=${this.id}`);
* if (!response.ok) {
* throw new Error(response.statusText);
* }
* return response.json();
* },
* args: () => [this.id, this.url],
* }
* );
*
* render() {
* return this.task.render({
* pending: () => html`<p>Loading...</p>`,
* complete: (value) => html`<p>Result: ${value}</p>`
* });
* }
* }
* ```
* You can import directly from @lit/task now.
* @deprecated
*/
export declare class Task<T extends ReadonlyArray<unknown> = ReadonlyArray<unknown>, R = unknown> {
private _previousArgs?;
private _task;
private _argsFn?;
private _argsEqual;
private _callId;
private _host;
private _value?;
private _error?;
private _abortController?;
private _onComplete?;
private _onError?;
status: TaskStatus;
/**
* Determines if the task is run automatically when arguments change after a
* host update. Default to `true`.
*
* @see {@link TaskConfig.autoRun} for more information.
*/
autoRun: boolean | 'afterUpdate';
/**
* 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.
*/
get taskComplete(): Promise<R>;
private _resolveTaskComplete?;
private _rejectTaskComplete?;
private _taskComplete?;
constructor(host: ReactiveControllerHost, task: TaskFunction<T, R>, args?: ArgsFunction<T>);
constructor(host: ReactiveControllerHost, task: TaskConfig<T, R>);
hostUpdate(): void;
hostUpdated(): void;
private _getArgs;
/**
* Determines if the task should run when it's triggered because of a
* host update, and runs the task if it should.
*
* A task should run when its arguments change from the previous run, based on
* the args equality function.
*
* This method is side-effectful: it stores the new args as the previous args.
*/
private _performTask;
/**
* Runs a task manually.
*
* This can be useful for running tasks in response to events as opposed to
* automatically running when host element state changes.
*
* @param args an optional set of arguments to use for this task run. If args
* is not given, the args function is called to get the arguments for
* this run.
*/
run(args?: T): Promise<void>;
/**
* Aborts the currently pending task run by aborting the AbortSignal
* passed to the task function.
*
* Aborting a task does nothing if the task is not running: ie, in the
* complete, error, or initial states.
*
* Aborting a task does not automatically cancel the task function. The task
* function must be written to accept the AbortSignal and either forward it
* to other APIs like `fetch()`, or handle cancellation manually by using
* [`signal.throwIfAborted()`]{@link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/throwIfAborted}
* or the
* [`abort`]{@link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/abort_event}
* event.
*
* @param reason The reason for aborting. Passed to
* `AbortController.abort()`.
*/
abort(reason?: unknown): void;
get value(): R | undefined;
get error(): unknown;
render<T extends StatusRenderer<R>>(renderer: T): MaybeReturnType<T["initial"]> | MaybeReturnType<T["pending"]> | MaybeReturnType<T["complete"]> | MaybeReturnType<T["error"]>;
}
declare type MaybeReturnType<F> = F extends (...args: never[]) => infer R ? R : undefined;
export declare const shallowArrayEquals: <T extends readonly unknown[]>(oldArgs: T, newArgs: T) => boolean;
ArgsFunction,
/**
* You can import directly from @lit/task now.
* @deprecated
*/
DepsFunction,
/**
* You can import directly from @lit/task now.
* @deprecated
*/
StatusRenderer,
/**
* You can import directly from @lit/task now.
* @deprecated
*/
Task,
/**
* You can import directly from @lit/task now.
* @deprecated
*/
TaskConfig,
/**
* You can import directly from @lit/task now.
* @deprecated
*/
TaskFunction,
/**
* You can import directly from @lit/task now.
* @deprecated
*/
TaskFunctionOptions,
/**
* You can import directly from @lit/task now.
* @deprecated
*/
TaskStatus,
/**
* You can import directly from @lit/task now.
* @deprecated
*/
initialState,
/**
* You can import directly from @lit/task now.
* @deprecated
*/
shallowArrayEquals, } from '@lit/task/task.js';
//# sourceMappingURL=task.d.ts.map

@@ -6,310 +6,27 @@ /**

*/
import { notEqual } from '@lit/reactive-element';
/**
* States for task status
* You can import directly from @lit/task now.
* @deprecated
*/
export const TaskStatus = {
INITIAL: 0,
PENDING: 1,
COMPLETE: 2,
ERROR: 3,
};
export {
/**
* A special value that can be returned from task functions to reset the task
* status to INITIAL.
* You can import directly from @lit/task now.
* @deprecated
*/
export const initialState = Symbol();
// TODO(sorvell / justinfagnani): Some issues:
// 1. With the task triggered in `update`, there is no ReactiveElement
// change-in-update warning in the common case that the update itself does not change
// the deps; however, Task's `requestUpdate` call to render pending state will not
// trigger another update since the element is updating. This `requestUpdate`
// could be triggered in updated, but that results a change-in-update warning.
// 2. There is no good signal for when the task has resolved and rendered other
// than requestAnimationFrame. The user would need to store a promise for the
// task and then wait for that and the element to update. (Update just justinfagnani:
// Why isn't waiting taskComplete and updateComplete sufficient? This comment is
// from before taskComplete existed!)
Task,
/**
* A controller that performs an asynchronous task (like a fetch) when its
* host element updates.
*
* Task requests an update on the host element when the task starts and
* completes so that the host can render the task status, value, and error as
* the task runs.
*
* The task function must be supplied and can take a list of arguments. The
* arguments are given to the Task as a function that returns a list of values,
* which is run and checked for changes on every host update.
*
* The `value` property reports the completed value, and the `error` property
* an error state if one occurs. The `status` property can be checked for
* status and is of type `TaskStatus` which has states for initial, pending,
* complete, and error.
*
* The `render` method accepts an object with optional methods corresponding
* to the task statuses to easily render different templates for each task
* status.
*
* The task is run automatically when its arguments change; however, this can
* be customized by setting `autoRun` to false and calling `run` explicitly
* to run the task.
*
* For a task to see state changes in the current update pass of the host
* element, those changes must be made in `willUpdate()`. State changes in
* `update()` or `updated()` will not be visible to the task until the next
* update pass.
*
* @example
*
* ```ts
* class MyElement extends LitElement {
* url = 'example.com/api';
* id = 0;
*
* task = new Task(
* this,
* {
* task: async ([url, id]) => {
* const response = await fetch(`${this.url}?id=${this.id}`);
* if (!response.ok) {
* throw new Error(response.statusText);
* }
* return response.json();
* },
* args: () => [this.id, this.url],
* }
* );
*
* render() {
* return this.task.render({
* pending: () => html`<p>Loading...</p>`,
* complete: (value) => html`<p>Result: ${value}</p>`
* });
* }
* }
* ```
* You can import directly from @lit/task now.
* @deprecated
*/
export class Task {
constructor(host, task, args) {
var _a, _b, _c;
this._callId = 0;
this.status = TaskStatus.INITIAL;
(this._host = host).addController(this);
const taskConfig = typeof task === 'object' ? task : { task, args };
this._task = taskConfig.task;
this._argsFn = taskConfig.args;
this._argsEqual = (_a = taskConfig.argsEqual) !== null && _a !== void 0 ? _a : shallowArrayEquals;
this._onComplete = taskConfig.onComplete;
this._onError = taskConfig.onError;
this.autoRun = (_b = taskConfig.autoRun) !== null && _b !== void 0 ? _b : true;
// Providing initialValue puts the task in COMPLETE state and stores the
// args immediately so it only runs when they change again.
if ('initialValue' in taskConfig) {
this._value = taskConfig.initialValue;
this.status = TaskStatus.COMPLETE;
this._previousArgs = (_c = this._getArgs) === null || _c === void 0 ? void 0 : _c.call(this);
}
}
/**
* 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.
*/
get taskComplete() {
// If a task run exists, return the cached promise. This is true in the case
// where the user has called taskComplete in pending or completed state
// before and has not started a new task run since.
if (this._taskComplete) {
return this._taskComplete;
}
// Generate an in-progress promise if the the status is pending and has been
// cleared by .run().
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) {
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).
}
else {
this._taskComplete = Promise.resolve(this._value);
}
return this._taskComplete;
}
hostUpdate() {
if (this.autoRun === true) {
this._performTask();
}
}
hostUpdated() {
if (this.autoRun === 'afterUpdate') {
this._performTask();
}
}
_getArgs() {
if (this._argsFn === undefined) {
return undefined;
}
const args = this._argsFn();
if (!Array.isArray(args)) {
throw new Error('The args function must return an array');
}
return args;
}
/**
* Determines if the task should run when it's triggered because of a
* host update, and runs the task if it should.
*
* A task should run when its arguments change from the previous run, based on
* the args equality function.
*
* This method is side-effectful: it stores the new args as the previous args.
*/
async _performTask() {
const args = this._getArgs();
const prev = this._previousArgs;
this._previousArgs = args;
if (args !== prev &&
args !== undefined &&
(prev === undefined || !this._argsEqual(prev, args))) {
await this.run(args);
}
}
/**
* Runs a task manually.
*
* This can be useful for running tasks in response to events as opposed to
* automatically running when host element state changes.
*
* @param args an optional set of arguments to use for this task run. If args
* is not given, the args function is called to get the arguments for
* this run.
*/
async run(args) {
var _a, _b, _c, _d, _e;
args !== null && args !== void 0 ? args : (args = this._getArgs());
// Remember the args for potential future automatic runs.
// TODO (justinfagnani): add test
this._previousArgs = args;
if (this.status === TaskStatus.PENDING) {
(_a = this._abortController) === null || _a === void 0 ? void 0 : _a.abort();
}
else {
// Clear the last complete task run in INITIAL because it may be a resolved
// promise. Also clear if COMPLETE or ERROR because the value returned by
// awaiting taskComplete may have changed since last run.
this._taskComplete = undefined;
this._resolveTaskComplete = undefined;
this._rejectTaskComplete = undefined;
}
this.status = TaskStatus.PENDING;
let result;
let error;
// Request an update to report pending state.
if (this.autoRun === 'afterUpdate') {
// Avoids a change-in-update warning
queueMicrotask(() => this._host.requestUpdate());
}
else {
this._host.requestUpdate();
}
const key = ++this._callId;
this._abortController = new AbortController();
let errored = false;
try {
result = await this._task(args, { signal: this._abortController.signal });
}
catch (e) {
errored = true;
error = e;
}
// If this is the most recent task call, process this value.
if (this._callId === key) {
if (result === initialState) {
this.status = TaskStatus.INITIAL;
}
else {
if (errored === false) {
try {
(_b = this._onComplete) === null || _b === void 0 ? void 0 : _b.call(this, result);
}
catch {
// Ignore user errors from onComplete.
}
this.status = TaskStatus.COMPLETE;
(_c = this._resolveTaskComplete) === null || _c === void 0 ? void 0 : _c.call(this, result);
}
else {
try {
(_d = this._onError) === null || _d === void 0 ? void 0 : _d.call(this, error);
}
catch {
// Ignore user errors from onError.
}
this.status = TaskStatus.ERROR;
(_e = this._rejectTaskComplete) === null || _e === void 0 ? void 0 : _e.call(this, error);
}
this._value = result;
this._error = error;
}
// Request an update with the final value.
this._host.requestUpdate();
}
}
/**
* Aborts the currently pending task run by aborting the AbortSignal
* passed to the task function.
*
* Aborting a task does nothing if the task is not running: ie, in the
* complete, error, or initial states.
*
* Aborting a task does not automatically cancel the task function. The task
* function must be written to accept the AbortSignal and either forward it
* to other APIs like `fetch()`, or handle cancellation manually by using
* [`signal.throwIfAborted()`]{@link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/throwIfAborted}
* or the
* [`abort`]{@link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/abort_event}
* event.
*
* @param reason The reason for aborting. Passed to
* `AbortController.abort()`.
*/
abort(reason) {
var _a;
if (this.status === TaskStatus.PENDING) {
(_a = this._abortController) === null || _a === void 0 ? void 0 : _a.abort(reason);
}
}
get value() {
return this._value;
}
get error() {
return this._error;
}
render(renderer) {
var _a, _b, _c, _d;
switch (this.status) {
case TaskStatus.INITIAL:
return (_a = renderer.initial) === null || _a === void 0 ? void 0 : _a.call(renderer);
case TaskStatus.PENDING:
return (_b = renderer.pending) === null || _b === void 0 ? void 0 : _b.call(renderer);
case TaskStatus.COMPLETE:
return (_c = renderer.complete) === null || _c === void 0 ? void 0 : _c.call(renderer, this.value);
case TaskStatus.ERROR:
return (_d = renderer.error) === null || _d === void 0 ? void 0 : _d.call(renderer, this.error);
default:
throw new Error(`Unexpected status: ${this.status}`);
}
}
}
export const shallowArrayEquals = (oldArgs, newArgs) => oldArgs === newArgs ||
(oldArgs.length === newArgs.length &&
oldArgs.every((v, i) => !notEqual(v, newArgs[i])));
TaskStatus,
/**
* You can import directly from @lit/task now.
* @deprecated
*/
initialState,
/**
* You can import directly from @lit/task now.
* @deprecated
*/
shallowArrayEquals, } from '@lit/task/task.js';
//# sourceMappingURL=task.js.map

@@ -1,2 +0,2 @@

export{Task,TaskStatus,initialState,shallowArrayEquals}from"./task.js";
export{Task,TaskStatus,initialState,shallowArrayEquals}from"@lit/task/task.js";
//# sourceMappingURL=index.js.map
{
"name": "@lit-labs/task",
"version": "3.0.2",
"version": "3.1.0-pre.0",
"description": "A controller for Lit that renders asynchronous tasks.",

@@ -50,4 +50,3 @@ "license": "BSD-3-Clause",

"test:dev": "wireit",
"test:prod": "wireit",
"checksize": "wireit"
"test:prod": "wireit"
},

@@ -61,3 +60,3 @@ "wireit": {

"../../lit:build",
"../../reactive-element:build"
"../../task:build"
]

@@ -68,2 +67,3 @@ },

"dependencies": [
"../../task:build:ts:types",
"../../lit:build:ts:types",

@@ -110,13 +110,2 @@ "../../reactive-element:build:ts:types"

},
"checksize": {
"command": "rollup -c --environment=CHECKSIZE",
"dependencies": [
"build:ts"
],
"files": [
"rollup.config.js",
"../../../rollup-common.js"
],
"output": []
},
"test": {

@@ -160,7 +149,8 @@ "dependencies": [

"@types/trusted-types": "^2.0.2",
"@lit-internal/scripts": "^1.0.0",
"lit": "^2.8.0"
"@lit-internal/scripts": "^1.0.1-pre.0",
"lit": "^3.0.0-pre.1"
},
"#versionComment": "We depend on <2.0.0 of task because we want to be compatible with 0.x.x versions, as well as the 1.x.x versions, as they're intended to all be compatible with the 3.x.x API of lit-labs/task before it graduated out of labs.",
"dependencies": {
"@lit/reactive-element": "^1.1.0"
"@lit/task": "1.0.0-pre.0"
},

@@ -167,0 +157,0 @@ "publishConfig": {

@@ -5,83 +5,6 @@ # @lit-labs/task

## Overview
This package has graduated from labs! It is now available as `@lit/task`. This package is just a proxy that re-exports `@lit/task`. As a result, while it will no longer be updated, it will continue to work and get updates through the ^1.0.0 version range of `@lit/task`. This should reduce duplication of code while the ecosystem migrates their imports away from `@lit-labs/task`.
Often a Lit element needs to request, process, and render remote data, for
example when querying a REST API for data to be displayed. The `Task`
controller provides a simple pattern for encapsulating this behavior in an
easily reusable way. The controller integrates with a host Lit element. The
user provides a task function and an arguments function. Whenever the element
updates, the arguments are checked and if any have changed, the task is
initiated.
If you're looking at this locally or on GitHub, you can now find the README here: [README.md](../../task/README.md).
Sometimes it's important to control exactly when a task runs. For example,
task arguments may have changed, but it should not run until an interaction
event like a button click. For these types of use cases, the `autoRun` option
can be set to `false`. This setting can be passed in the task configuration
and/or be set on the `Task` itself. It defaults to `true`, but when `autoRun`
is `false`, the task does not run automatically when arguments change.
Instead, it can be run explicitly by calling `run(arg?)`. By default, `run()`
uses the task's configured arguments function, but a custom array of arguments
may be optionally passed.
The controller requests an update of the element whenever the task
status changes. Task status is provided via the `TaskStatus` object which has
values for `INITIAL`, `PENDING`, `COMPLETE`, and `ERROR`. The task result is
available via its `value` property, or via the `error` property when an error
occurs. The task `render` method may also be used to easily render different
task states. It accepts an object which optionally can implement methods for
`initial`, `pending`, `complete(value)`, and `error(error)`. These methods
typically return a Lit `TemplateResult` to render.
## Installation
From inside your project folder, run:
```bash
$ npm install @lit-labs/task
```
## Usage
Here's an example:
```ts
import {Task, TaskStatus} from '@lit-labs/task';
// ...
class MyElement extends LitElement {
@state()
private _userId: number = -1;
private _apiTask = new Task(
this,
([userId]) =>
fetch(`//example.com/api/userInfo?${userId}`).then((response) =>
response.json()
),
() => [this._userId]
);
render() {
return html`
<div>User Info</div>
${this._apiTask.render({
pending: () => html`Loading user info...`,
complete: (user) => html`${user.name}`,
})}
<!-- ... -->
`;
}
}
```
### Argument equality
Task accepts an `argsEqual` to determine if a task should auto-run by testing a new arguments array for equality against the previous run's arguments array.
The default equality function is `shallowArrayEquals`, which compares each argument in the array against the previous array with `notEqual` from `@lit/reactive-element` (which itself uses `===`). This works well if your arguments are primitive values like strings.
If your arguments are objects, you will want to use a more sophisticated equality function. Task provides `deepArrayEquals` in the `deep-equals.js` module, which compares each argument with a `deepEquals` function that can handle primitives, objects, Arrays, Maps, Sets, RegExps, or objects that implement `toString()` or `toValue()`.
## Contributing
Please see [CONTRIBUTING.md](../../../CONTRIBUTING.md).
If you're looking at this online, you can also find its README on npmjs: https://www.npmjs.com/package/@lit/task

@@ -1,215 +0,61 @@

import { ReactiveControllerHost } from '@lit/reactive-element/reactive-controller.js';
export interface TaskFunctionOptions {
signal: AbortSignal;
}
export declare type TaskFunction<D extends ReadonlyArray<unknown>, R = unknown> = (args: D, options: TaskFunctionOptions) => R | typeof initialState | Promise<R | typeof initialState>;
export declare type ArgsFunction<D extends ReadonlyArray<unknown>> = () => D;
export { ArgsFunction as DepsFunction };
/**
* States for task status
* @license
* Copyright 2017 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
export declare const TaskStatus: {
readonly INITIAL: 0;
readonly PENDING: 1;
readonly COMPLETE: 2;
readonly ERROR: 3;
};
/**
* A special value that can be returned from task functions to reset the task
* status to INITIAL.
* You can import directly from @lit/task now.
* @deprecated
*/
export declare const initialState: unique symbol;
export declare type TaskStatus = (typeof TaskStatus)[keyof typeof TaskStatus];
export declare type StatusRenderer<R> = {
initial?: () => unknown;
pending?: () => unknown;
complete?: (value: R) => unknown;
error?: (error: unknown) => unknown;
};
export interface TaskConfig<T extends ReadonlyArray<unknown>, R> {
task: TaskFunction<T, R>;
args?: ArgsFunction<T>;
/**
* Determines if the task is run automatically when arguments change after a
* host update. Default to `true`.
*
* If `true`, the task checks arguments during the host update (after
* `willUpdate()` and before `update()` in Lit) and runs if they change. For
* a task to see argument changes they must be done in `willUpdate()` or
* earlier. The host element can see task status changes caused by its own
* current update.
*
* If `'afterUpdate'`, the task checks arguments and runs _after_ the host
* update. This means that the task can see host changes done in update, such
* as rendered DOM. The host element can not see task status changes caused
* by its own update, so the task must trigger a second host update to make
* those changes renderable.
*
* Note: `'afterUpdate'` is unlikely to be SSR compatible in the future.
*
* If `false`, the task is not run automatically, and must be run with the
* {@linkcode run} method.
*/
autoRun?: boolean | 'afterUpdate';
/**
* A function that determines if the current arg and previous args arrays are
* equal. If the argsEqual function returns true, the task will not auto-run.
*
* The default is {@linkcode shallowArrayEquals}. {@linkcode deepArrayEquals}
* is also available.
*/
argsEqual?: (oldArgs: T, newArgs: T) => boolean;
/**
* If initialValue is provided, the task is initialized to the COMPLETE
* status and the value is set to initialData.
*
* Initial args should be coherent with the initialValue, since they are
* assumed to be the args that would produce that value. When autoRun is
* `true` the task will not auto-run again until the args change.
*/
initialValue?: R;
onComplete?: (value: R) => unknown;
onError?: (error: unknown) => unknown;
}
export {
/**
* A controller that performs an asynchronous task (like a fetch) when its
* host element updates.
*
* Task requests an update on the host element when the task starts and
* completes so that the host can render the task status, value, and error as
* the task runs.
*
* The task function must be supplied and can take a list of arguments. The
* arguments are given to the Task as a function that returns a list of values,
* which is run and checked for changes on every host update.
*
* The `value` property reports the completed value, and the `error` property
* an error state if one occurs. The `status` property can be checked for
* status and is of type `TaskStatus` which has states for initial, pending,
* complete, and error.
*
* The `render` method accepts an object with optional methods corresponding
* to the task statuses to easily render different templates for each task
* status.
*
* The task is run automatically when its arguments change; however, this can
* be customized by setting `autoRun` to false and calling `run` explicitly
* to run the task.
*
* For a task to see state changes in the current update pass of the host
* element, those changes must be made in `willUpdate()`. State changes in
* `update()` or `updated()` will not be visible to the task until the next
* update pass.
*
* @example
*
* ```ts
* class MyElement extends LitElement {
* url = 'example.com/api';
* id = 0;
*
* task = new Task(
* this,
* {
* task: async ([url, id]) => {
* const response = await fetch(`${this.url}?id=${this.id}`);
* if (!response.ok) {
* throw new Error(response.statusText);
* }
* return response.json();
* },
* args: () => [this.id, this.url],
* }
* );
*
* render() {
* return this.task.render({
* pending: () => html`<p>Loading...</p>`,
* complete: (value) => html`<p>Result: ${value}</p>`
* });
* }
* }
* ```
* You can import directly from @lit/task now.
* @deprecated
*/
export declare class Task<T extends ReadonlyArray<unknown> = ReadonlyArray<unknown>, R = unknown> {
private _previousArgs?;
private _task;
private _argsFn?;
private _argsEqual;
private _callId;
private _host;
private _value?;
private _error?;
private _abortController?;
private _onComplete?;
private _onError?;
status: TaskStatus;
/**
* Determines if the task is run automatically when arguments change after a
* host update. Default to `true`.
*
* @see {@link TaskConfig.autoRun} for more information.
*/
autoRun: boolean | 'afterUpdate';
/**
* 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.
*/
get taskComplete(): Promise<R>;
private _resolveTaskComplete?;
private _rejectTaskComplete?;
private _taskComplete?;
constructor(host: ReactiveControllerHost, task: TaskFunction<T, R>, args?: ArgsFunction<T>);
constructor(host: ReactiveControllerHost, task: TaskConfig<T, R>);
hostUpdate(): void;
hostUpdated(): void;
private _getArgs;
/**
* Determines if the task should run when it's triggered because of a
* host update, and runs the task if it should.
*
* A task should run when its arguments change from the previous run, based on
* the args equality function.
*
* This method is side-effectful: it stores the new args as the previous args.
*/
private _performTask;
/**
* Runs a task manually.
*
* This can be useful for running tasks in response to events as opposed to
* automatically running when host element state changes.
*
* @param args an optional set of arguments to use for this task run. If args
* is not given, the args function is called to get the arguments for
* this run.
*/
run(args?: T): Promise<void>;
/**
* Aborts the currently pending task run by aborting the AbortSignal
* passed to the task function.
*
* Aborting a task does nothing if the task is not running: ie, in the
* complete, error, or initial states.
*
* Aborting a task does not automatically cancel the task function. The task
* function must be written to accept the AbortSignal and either forward it
* to other APIs like `fetch()`, or handle cancellation manually by using
* [`signal.throwIfAborted()`]{@link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/throwIfAborted}
* or the
* [`abort`]{@link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal/abort_event}
* event.
*
* @param reason The reason for aborting. Passed to
* `AbortController.abort()`.
*/
abort(reason?: unknown): void;
get value(): R | undefined;
get error(): unknown;
render<T extends StatusRenderer<R>>(renderer: T): MaybeReturnType<T["initial"]> | MaybeReturnType<T["pending"]> | MaybeReturnType<T["complete"]> | MaybeReturnType<T["error"]>;
}
declare type MaybeReturnType<F> = F extends (...args: never[]) => infer R ? R : undefined;
export declare const shallowArrayEquals: <T extends readonly unknown[]>(oldArgs: T, newArgs: T) => boolean;
ArgsFunction,
/**
* You can import directly from @lit/task now.
* @deprecated
*/
DepsFunction,
/**
* You can import directly from @lit/task now.
* @deprecated
*/
StatusRenderer,
/**
* You can import directly from @lit/task now.
* @deprecated
*/
Task,
/**
* You can import directly from @lit/task now.
* @deprecated
*/
TaskConfig,
/**
* You can import directly from @lit/task now.
* @deprecated
*/
TaskFunction,
/**
* You can import directly from @lit/task now.
* @deprecated
*/
TaskFunctionOptions,
/**
* You can import directly from @lit/task now.
* @deprecated
*/
TaskStatus,
/**
* You can import directly from @lit/task now.
* @deprecated
*/
initialState,
/**
* You can import directly from @lit/task now.
* @deprecated
*/
shallowArrayEquals, } from '@lit/task/task.js';
//# sourceMappingURL=task.d.ts.map

@@ -1,7 +0,2 @@

import{notEqual as t}from"@lit/reactive-element";
/**
* @license
* 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){var h,e,o;this.t=0,this.status=0,(this.i=t).addController(this);const n="object"==typeof i?i:{task:i,args:s};this.o=n.task,this.l=n.args,this.h=null!==(h=n.argsEqual)&&void 0!==h?h:r,this.u=n.onComplete,this.v=n.onError,this.autoRun=null===(e=n.autoRun)||void 0===e||e,"initialValue"in n&&(this.p=n.initialValue,this.status=2,this._=null===(o=this.j)||void 0===o?void 0:o.call(this))}get taskComplete(){return this.m||(1===this.status?this.m=new Promise(((t,i)=>{this.g=t,this.k=i})):3===this.status?this.m=Promise.reject(this.A):this.m=Promise.resolve(this.p)),this.m}hostUpdate(){!0===this.autoRun&&this.O()}hostUpdated(){"afterUpdate"===this.autoRun&&this.O()}j(){if(void 0===this.l)return;const t=this.l();if(!Array.isArray(t))throw Error("The args function must return an array");return t}async O(){const t=this.j(),i=this._;this._=t,t===i||void 0===t||void 0!==i&&this.h(i,t)||await this.run(t)}async run(t){var i,h,r,e,o;let n,l;null!=t||(t=this.j()),this._=t,1===this.status?null===(i=this.T)||void 0===i||i.abort():(this.m=void 0,this.g=void 0,this.k=void 0),this.status=1,"afterUpdate"===this.autoRun?queueMicrotask((()=>this.i.requestUpdate())):this.i.requestUpdate();const a=++this.t;this.T=new AbortController;let u=!1;try{n=await this.o(t,{signal:this.T.signal})}catch(t){u=!0,l=t}if(this.t===a){if(n===s)this.status=0;else{if(!1===u){try{null===(h=this.u)||void 0===h||h.call(this,n)}catch{}this.status=2,null===(r=this.g)||void 0===r||r.call(this,n)}else{try{null===(e=this.v)||void 0===e||e.call(this,l)}catch{}this.status=3,null===(o=this.k)||void 0===o||o.call(this,l)}this.p=n,this.A=l}this.i.requestUpdate()}}abort(t){var i;1===this.status&&(null===(i=this.T)||void 0===i||i.abort(t))}get value(){return this.p}get error(){return this.A}render(t){var i,s,h,r;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===(r=t.error)||void 0===r?void 0:r.call(t,this.error);default:throw Error("Unexpected status: "+this.status)}}}const r=(i,s)=>i===s||i.length===s.length&&i.every(((i,h)=>!t(i,s[h])));export{h as Task,i as TaskStatus,s as initialState,r as shallowArrayEquals};
export{Task,TaskStatus,initialState,shallowArrayEquals}from"@lit/task/task.js";
//# sourceMappingURL=task.js.map

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc