@antischematic/angular-state-library
Version:
Reactive state without boilerplate
1,158 lines (1,140 loc) • 42.2 kB
JavaScript
import * as i0 from '@angular/core';
import { ChangeDetectorRef, InjectionToken, inject, INJECTOR, Injectable, ErrorHandler, createEnvironmentInjector, EnvironmentInjector, ElementRef, Directive, Input, EventEmitter } from '@angular/core';
import { defer, filter, Observable, map, Subject, Subscription, switchAll, pipe, mergeAll, concatAll, exhaustAll, startWith, distinctUntilChanged, BehaviorSubject, NEVER, isObservable, ReplaySubject, observable, tap, catchError, EMPTY, takeWhile, merge, fromEvent, of, debounce, interval, switchMap, takeUntil, throttle, timer, retry, share, finalize } from 'rxjs';
import { DOCUMENT } from '@angular/common';
var EventType;
(function (EventType) {
EventType["Dispatch"] = "dispatch";
EventType["Next"] = "next";
EventType["Error"] = "error";
EventType["Complete"] = "complete";
})(EventType || (EventType = {}));
const meta = new WeakMap();
const action$1 = Symbol("action");
const selector = Symbol("selector");
const tracked = Symbol("track");
const injector = Symbol("injector");
const caught = Symbol("caught");
const attach = Symbol("attach");
function ensureKey(target, key) {
return target.has(key) ? target.get(key) : target.set(key, new Map()).get(key);
}
function getMetaKeys(metaKey, target) {
return ensureKey(ensureKey(meta, target), metaKey);
}
function getMeta(metaKey, target, key) {
return getMetaKeys(metaKey, target).get(key);
}
function setMeta(metaKey, value, target, key) {
return ensureKey(ensureKey(meta, target), metaKey).set(key, value);
}
function getMetaValues(metaKey, target) {
return Array.from(getMetaKeys(metaKey, target).values());
}
function getActions(target, phase) {
return getMetaValues(action$1, target).filter(meta => phase ? meta.phase === phase : true);
}
function getSelectors(target, withDescriptor) {
return getMetaValues(selector, target).filter(selector => !!selector.descriptor === withDescriptor);
}
function getErrorHandlers(target) {
return getMetaValues(caught, target);
}
function getDeps(target, key) {
return getMeta(tracked, target, key);
}
function getToken(token, context, key) {
var _a;
return (_a = getMeta(injector, context, key)) === null || _a === void 0 ? void 0 : _a.get(token);
}
function markDirty(context) {
getToken(ChangeDetectorRef, context).markForCheck();
}
function getAttachments(target) {
return getMetaValues(attach, target);
}
const cache = new WeakMap();
const proxies = new WeakMap();
let deps = [];
function pushStack(value) {
deps.unshift(value);
}
function popStack() {
deps.shift();
}
function isTracking() {
return deps.length > 0;
}
const changesMap = new WeakMap();
function getChanges(deps) {
var _a;
const changes = (_a = changesMap.get(deps)) !== null && _a !== void 0 ? _a : new Map();
changesMap.set(deps, changes);
return changes;
}
function addDep(object, key, value, previous = value, update = false) {
var _a, _b;
if (isTracking()) {
let seen = false;
for (const dep of deps) {
const keyValues = (_a = dep.get(object)) !== null && _a !== void 0 ? _a : new Map;
dep.set(object, keyValues);
if (!seen && update && !Object.is(value, previous)) {
seen = true;
const changes = getChanges(dep);
const change = (_b = changes.get(object)) !== null && _b !== void 0 ? _b : new Map();
changes.set(object, change);
if (!change.has(key)) {
change.set(key, untrack(previous));
}
}
if (update && keyValues.has(key) || !update) {
keyValues.set(key, value);
}
}
}
}
function createObjectProxy(object) {
return new Proxy(object, {
get(target, p) {
const value = Reflect.get(target, p);
addDep(target, p, value);
return value;
},
set(target, p, value, receiver) {
const previous = Reflect.get(target, p);
const result = Reflect.set(target, p, value, receiver);
addDep(target, p, value, previous, true);
return result;
},
deleteProperty(target, p) {
const previous = Reflect.get(target, p);
const result = Reflect.deleteProperty(target, p);
addDep(target, p, void 0, previous, true);
return result;
}
});
}
function createProxy(object) {
if (!isObject(object))
return object;
if (cache.has(object)) {
return cache.get(object);
}
const proxy = createObjectProxy(object);
cache.set(object, proxy);
proxies.set(proxy, object);
return proxy;
}
function isTracked(object) {
return proxies.has(object);
}
function isObject(value) {
return typeof value === "object" && value !== null;
}
function track(object) {
return isObject(object) && !isTracked(object) ? createProxy(object) : object;
}
function untrack(object) {
var _a;
return (_a = proxies.get(object)) !== null && _a !== void 0 ? _a : object;
}
function isPlainObject(obj) {
const proto = Object.getPrototypeOf(obj);
return proto === null || proto === Object.prototype;
}
function call(target, key, ...args) {
return target[key].apply(target, args);
}
function wrap(target, property, fn) {
var _a;
const descriptor = Object.getOwnPropertyDescriptor(target, property);
const object = descriptor ? descriptor : target;
const getOrValue = (descriptor === null || descriptor === void 0 ? void 0 : descriptor.get) ? "get" : "value";
const originalFunction = (_a = (descriptor ? descriptor[getOrValue] : object[property])) !== null && _a !== void 0 ? _a : noop;
Object.defineProperty(target, property, {
configurable: true,
[getOrValue]: function (...args) {
return fn.call(untrack(this), originalFunction, ...args);
}
});
return originalFunction === noop;
}
function noop() { }
const UID = new InjectionToken("UID", {
factory() {
let id = 0;
return function getId() {
return id++;
};
}
});
function events(token, injector = inject(INJECTOR)) {
return defer(() => {
const context = typeof token === "function" ? injector.get(token) : token;
return injector.get(EVENTS).pipe(filter(event => event.context === context));
});
}
function configureStore(config) {
return {
provide: config.root ? ROOT_CONFIG : STORE_CONFIG,
useValue: config
};
}
function observeInZone(source, zone) {
return new Observable(subscriber => {
return zone.run(() => {
return source.subscribe(subscriber);
});
});
}
function get(token) {
return track(inject(token).value);
}
function set(token, value) {
inject(token).next(value);
}
function filterByNameType(name, type) {
return filter((event) => event.name === name && event.type === type);
}
function actionEvent(token, name, injector) {
return events(token, injector).pipe(filterByNameType(name, EventType.Dispatch));
}
function action(token, name, injector) {
return actionEvent(token, name, injector).pipe(map((event) => event.value));
}
function nextEvent(token, name, injector) {
return events(token, injector).pipe(filterByNameType(name, EventType.Next));
}
function next(token, name, injector) {
return nextEvent(token, name, injector).pipe(map((event) => event.value));
}
function errorEvent(token, name, injector) {
return events(token, injector).pipe(filterByNameType(name, EventType.Error));
}
function error(token, name, injector) {
return errorEvent(token, name, injector).pipe(map((event) => event.value));
}
function completeEvent(token, name, injector) {
return events(token, injector).pipe(filterByNameType(name, EventType.Complete));
}
function complete(token, name, injector) {
return completeEvent(token, name, injector).pipe(filterByNameType(name, EventType.Complete), map(() => undefined));
}
const ACTION = new InjectionToken("ACTION");
const CONTEXT = new InjectionToken("CONTEXT");
const STORE_CONFIG = new InjectionToken("STORE_CONFIG");
const ROOT_CONFIG = new InjectionToken("ROOT_CONFIG", {
factory() {
return {};
}
});
const EVENTS = new InjectionToken("EVENTS", {
factory() {
return new Subject();
}
});
class EventScheduler {
constructor(context) {
this.context = context;
this.events = [];
this.dispatcher = inject(EVENTS);
this.getId = inject(UID);
}
schedule(type, name, value, changes) {
this.events.push({
id: this.getId(),
timestamp: Date.now(),
type,
context: this.context,
name,
value,
changes
});
}
flush() {
const events = this.events;
if (events.length) {
let event;
this.events = [];
while (event = events.shift()) {
this.dispatcher.next(event);
}
}
return this.events.length > 0;
}
}
class EffectScheduler {
constructor() {
this.source = new Subject();
this.queue = [];
this.connected = false;
this.subscription = Subscription.EMPTY;
this.pending = new Set;
this.closed = false;
}
next(source) {
this.connect();
this.source.next(source);
}
enqueue(source) {
this.queue.push(source);
}
dequeue() {
let effect;
if (this.pending.size === 0) {
while (effect = this.queue.shift()) {
this.next(effect);
}
}
}
connect() {
var _a;
if (!this.connected && !this.closed) {
this.connected = true;
this.subscription = this.source.pipe((_a = this.operator) !== null && _a !== void 0 ? _a : switchAll()).subscribe();
this.subscription.add(() => this.connected = false);
}
}
addPending(promise) {
this.pending.add(promise);
promise.finally(() => {
this.pending.delete(promise);
this.dequeue();
});
}
ngOnDestroy() {
this.closed = true;
this.source.complete();
this.subscription.unsubscribe();
}
}
EffectScheduler.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: EffectScheduler, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
EffectScheduler.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: EffectScheduler });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: EffectScheduler, decorators: [{
type: Injectable
}] });
class Teardown {
constructor() {
this.subscriptions = [];
}
unsubscribe() {
let subscription;
while (subscription = this.subscriptions.shift()) {
subscription.unsubscribe();
}
}
ngOnDestroy() {
this.unsubscribe();
}
}
Teardown.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: Teardown, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
Teardown.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: Teardown });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: Teardown, decorators: [{
type: Injectable
}] });
class Changes {
constructor(target) {
this.target = target;
}
get value() {
var _a, _b;
return (_b = track((_a = this.target.__ngSimpleChanges__) === null || _a === void 0 ? void 0 : _a.previous)) !== null && _b !== void 0 ? _b : {};
}
}
class StoreErrorHandler {
constructor(prototype, instance) {
this.prototype = prototype;
this.instance = instance;
}
handleError(error) {
const errorHandlers = getErrorHandlers(this.prototype);
for (const handler of errorHandlers) {
try {
this.instance[handler.key].call(this.instance, error);
break;
}
catch (e) {
error = e;
}
}
throw error;
}
}
function useOperator(operator) {
const effect = inject(EffectScheduler);
if (!effect.operator) {
effect.operator = operator;
}
}
function useSwitch(operator) {
useOperator(operator ? pipe(operator, switchAll()) : switchAll());
}
function useMerge(operator, concurrent = operator) {
useOperator(typeof operator === "function" ? pipe(operator, mergeAll(concurrent)) : mergeAll(concurrent));
}
function useConcat(operator) {
useOperator(operator ? pipe(operator, concatAll()) : concatAll());
}
function useExhaust(operator) {
useOperator(operator ? pipe(operator, exhaustAll()) : exhaustAll());
}
function addTeardown(teardown) {
const subscription = new Subscription();
subscription.add(teardown);
inject(Teardown).subscriptions.push(subscription);
}
function useInputs() {
return inject(Changes).value;
}
function pick(object, keys) {
if (Array.isArray(keys)) {
return keys.reduce((acc, key) => {
acc[key] = object[key];
return acc;
}, {});
}
return object[keys];
}
function slice(token, keys, injector = inject(INJECTOR)) {
return defer(() => {
const context = injector.get(token);
return store(token, injector).pipe(map((context) => pick(context, keys)), startWith(pick(context, keys)), distinctUntilChanged((a, b) => !Array.isArray(keys) ? Object.is(a, b) : keys.every(key => Object.is(a[key], b[key]))));
});
}
function store(token, injector = inject(INJECTOR)) {
return defer(() => {
const context = injector.get(token);
return injector.get(EVENTS).pipe(filter(event => event.changes.has(context)), map(() => context));
});
}
function inputs(token, injector = inject(INJECTOR)) {
return defer(() => {
return events(token, injector).pipe(filter((event) => event.name === "ngOnChanges"), map(event => event.value));
});
}
function withState(initial, options = {}) {
var _a;
const destination = new BehaviorSubject(initial);
const source = (_a = options.from) !== null && _a !== void 0 ? _a : NEVER;
return {
destination,
source,
};
}
const Selector = function Selector(name, select) {
class Selector {
constructor() {
this.connected = false;
this.subscription = new Subscription();
const subject = new Subject();
const selection = select(subject);
if (isObservable(selection)) {
this.source = selection;
this.destination = new ReplaySubject(1);
}
else {
this.source = selection.source;
this.destination = selection.destination;
}
this.target = select.length > 0 ? subject : this.destination;
this.subscription.add(this.destination.subscribe((value) => {
this.value = value;
}));
}
[observable]() {
return this;
}
connect() {
if (!this.connected) {
this.connected = true;
this.subscription.add(this.source.subscribe(this.destination));
}
}
next(value) {
this.target.next(value);
}
pipe(...operators) {
return new Observable(subscriber => {
return this.subscribe(subscriber);
}).pipe(...operators);
}
subscribe(observer) {
try {
return this.destination.subscribe(observer);
}
finally {
this.connect();
}
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
Selector.overriddenName = name;
Selector.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: Selector, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
Selector.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: Selector });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: Selector, decorators: [{
type: Injectable
}], ctorParameters: function () { return []; } });
return Selector;
};
class SelectObserver {
constructor(target, key, event, cdr, errorHandler) {
this.target = target;
this.key = key;
this.event = event;
this.cdr = cdr;
this.errorHandler = errorHandler;
}
next(value) {
const previous = this.target[this.key];
this.target[this.key] = track(value);
const changes = new Map([[this.target, new Map([[this.key, previous]])]]);
this.event.schedule(EventType.Dispatch, this.key, value, changes);
this.cdr.markForCheck();
}
error(error) {
console.error("Error thrown in Select");
console.error("Directive:", this.target);
console.error("Key:", this.key);
this.errorHandler.handleError(error);
}
complete() { }
}
function subscribe(token, directive, key) {
var _a, _b, _c;
const instance = token ? inject(token) : directive[key];
const observer = new SelectObserver(directive, key, inject(EventScheduler), inject(ChangeDetectorRef), inject(ErrorHandler));
const subscription = (_b = (_a = instance.ngOnSelect) === null || _a === void 0 ? void 0 : _a.call(instance, observer)) !== null && _b !== void 0 ? _b : (_c = instance.subscribe) === null || _c === void 0 ? void 0 : _c.call(instance, observer);
if (!subscription) {
console.error('Directive:', directive);
console.error('Key:', key);
console.error('Object:', instance);
throw new Error(`Object does not implement OnSelect or Subscribable interfaces`);
}
directive[key] = track(directive[key]);
addTeardown(subscription);
}
function checkDeps(deps) {
let dirty = false;
for (const [object, keyValues] of deps) {
for (const [key, previous] of keyValues) {
const current = object[key];
if (!Object.is(current, previous)) {
keyValues.set(key, current);
dirty = true;
}
}
}
return dirty;
}
function decorateCheck(target, name) {
const actions = getActions(target, name);
wrap(target, name, function check(fn) {
var _b;
const events = getToken(EventScheduler, this);
for (const action of actions) {
const deps = getDeps(this, action.key);
const dirty = action.track && deps && checkDeps(deps);
if (((_b = action.descriptor) === null || _b === void 0 ? void 0 : _b.value.length) === 0 && (!deps && action.immediate && action.phase === name || dirty)) {
markDirty(this);
call(this, action.key);
}
}
for (const action of actions) {
const effect = getToken(EffectScheduler, this, action.key);
effect.dequeue();
}
if (events.flush()) {
check.call(this, fn);
}
else {
fn.apply(this);
}
});
}
function getConfig() {
var _b;
return (_b = inject(STORE_CONFIG, { self: true, optional: true })) !== null && _b !== void 0 ? _b : inject(ROOT_CONFIG);
}
function provideValue(provide, useValue) {
return { provide, useValue };
}
function setup(target, factory, ...args) {
var _b;
const instance = factory(...args);
const prototype = target.prototype;
const parent = inject(INJECTOR);
const storeInjector = createEnvironmentInjector([
provideValue(Changes, new Changes(instance)),
provideValue(ErrorHandler, new StoreErrorHandler(prototype, instance)),
provideValue(EventScheduler, new EventScheduler(instance)),
Teardown
], parent);
let storeConfig = getConfig();
setMeta(injector, storeInjector, instance);
for (const action of getActions(prototype)) {
const actionInjector = createEnvironmentInjector([
provideValue(ACTION, action),
provideValue(CONTEXT, { instance }),
EffectScheduler,
Teardown,
(_b = storeConfig === null || storeConfig === void 0 ? void 0 : storeConfig.actionProviders) !== null && _b !== void 0 ? _b : []
], storeInjector);
setMeta(injector, actionInjector, instance, action.key);
}
return instance;
}
const stores = new Set();
const decorated = new WeakSet();
function decorateFactory(target, fn, ...additionalArgs) {
const factory = target["ɵfac"];
if (factory) {
Object.defineProperty(target, "ɵfac", {
configurable: true,
value: function (...args) {
return fn(target, factory, ...additionalArgs, ...args);
}
});
}
}
function runInContext(deps, fn, context = {}, catchError = true, key, ...args) {
const injector = getToken(EnvironmentInjector, untrack(context), key);
const errorHandler = injector.get(ErrorHandler);
pushStack(deps);
try {
return injector.runInContext(() => fn.apply(context, args));
}
catch (e) {
if (catchError) {
errorHandler.handleError(e);
}
else {
throw e;
}
}
finally {
popStack();
}
}
function runAction(fn, key, deps, args) {
const event = inject(EventScheduler);
event.schedule(EventType.Dispatch, key, args.length === 1 ? args[0] : args, getChanges(deps));
return fn.apply(this, args);
}
function decorateActions(target) {
for (const { key, catchError } of getActions(target)) {
wrap(target, key, function (fn, ...args) {
const proxy = createProxy(this);
const deps = new Map();
setMeta(tracked, deps, this, key);
teardown(this, key);
return runInContext(deps, runAction, proxy, catchError, key, fn, key, deps, args);
});
}
}
function decorateSelect(target) {
var _b;
var _a;
(_b = (_a = target.prototype).ngOnSelect) !== null && _b !== void 0 ? _b : (_a.ngOnSelect = function (observer) {
return store(target).subscribe(observer);
});
}
function decorateSelectors(target) {
for (const { key } of getSelectors(target, true)) {
wrap(target, key, function (fn, ...args) {
const cacheKey = key + JSON.stringify(args);
const proxy = createProxy(this);
const deps = getDeps(this, cacheKey);
const dirty = deps ? checkDeps(deps) : true;
let result = getMeta(cacheKey, this, key);
if (dirty) {
const newDeps = new Map();
result = runInContext(newDeps, fn, proxy, true, void 0, ...args);
setMeta(cacheKey, result, this, key);
setMeta(tracked, newDeps, this, cacheKey);
}
return result;
});
}
}
function decorateChanges(target) {
wrap(target, "ngOnChanges", function (fn, value) {
const events = getToken(EventScheduler, this);
const changes = Object.entries(value).map(([key, change]) => [key, change.previousValue]);
events.schedule(EventType.Dispatch, "ngOnChanges", Object.assign({}, value), new Map([[this, new Map(changes)]]));
fn.call(this, value);
});
}
function decorateOnInit(target) {
wrap(target, "ngOnInit", function (fn) {
const injector = getToken(EnvironmentInjector, this);
for (const attachment of getSelectors(target, false)) {
injector.runInContext(() => {
subscribe(attachment.token, this, attachment.key);
});
}
fn.call(this);
});
}
function decorateDestroy(target) {
wrap(target, "ngOnDestroy", function (fn) {
for (const environmentInjector of getMetaValues(injector, this)) {
environmentInjector.destroy();
}
fn.apply(this);
});
}
function teardown(context, key) {
var _b;
(_b = getToken(Teardown, context, key)) === null || _b === void 0 ? void 0 : _b.unsubscribe();
}
const observers = [EventType.Next, EventType.Error, EventType.Complete, "finalize"];
function callObserver(fn, applyThis, value) {
fn.call(applyThis, value);
}
function dispatch(source, observerOrOptions = {}, options = observerOrOptions) {
var _a;
const action = inject(ACTION);
const context = inject(CONTEXT).instance;
const applyThis = observerOrOptions && !isPlainObject(observerOrOptions) ? observerOrOptions : context;
const errorHandler = inject(ErrorHandler);
const event = inject(EventScheduler);
const effect = inject(EffectScheduler);
const changeDetector = inject(ChangeDetectorRef);
const signal = new Subject();
const zone = options.zone === "noop" ? Zone.root : (_a = options.zone) !== null && _a !== void 0 ? _a : Zone.current;
const observer = typeof observerOrOptions === "function" ? { next: observerOrOptions } : Object.assign({}, observerOrOptions);
for (const key of observers) {
wrap(observer, key, function (fn, value) {
const isAction = key !== "finalize";
try {
if (!changeDetector.destroyed) {
const deps = new Map();
isAction && event.schedule(key, action.key, value, getChanges(deps));
changeDetector.markForCheck();
runInContext(deps, callObserver, context, false, action.key, fn, applyThis, value);
}
}
finally {
if (isAction) {
signal[key](value);
}
else {
signal.complete();
}
}
});
}
effect.enqueue(observeInZone(source.pipe(tap(observer), catchError(e => {
zone.runGuarded(() => errorHandler.handleError(e));
return EMPTY;
})), zone));
return signal;
}
class TemplateProvider extends ReplaySubject {
constructor() {
var _a;
super(1);
this._firstValue = false;
const style = (_a = inject(ElementRef).nativeElement) === null || _a === void 0 ? void 0 : _a.style;
if (style)
style.display = "contents";
}
set __value(value) {
this._firstValue = true;
this.next(value);
}
ngOnInit() {
if (!this._firstValue) {
this.next(this.value);
}
}
subscribe(observer) {
return super.subscribe(observer);
}
}
TemplateProvider.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: TemplateProvider, deps: [], target: i0.ɵɵFactoryTarget.Directive });
TemplateProvider.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.0.0", type: TemplateProvider, inputs: { __value: ["value", "__value"] }, usesInheritance: true, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: TemplateProvider, decorators: [{
type: Directive
}], ctorParameters: function () { return []; }, propDecorators: { __value: [{
type: Input,
args: ["value"]
}] } });
function loadEffect(load) {
return function (...args) {
const injector = inject(EnvironmentInjector);
const effect = inject(EffectScheduler);
const promise = load().then((mod) => {
return injector.runInContext(() => {
return mod.default(...args);
});
});
effect.addPending(promise);
return new Observable(subscriber => {
promise
.then(source => {
subscriber.add(source.subscribe(subscriber));
})
.catch(e => {
subscriber.error(e);
});
return subscriber;
});
};
}
/// <reference path="../../../node_modules/zone.js/zone.d.ts" />
function handleError(transition) {
if (transition.failed) {
transition.onError.next(transition.thrownError);
}
else if (transition.resetOnSuccess) {
transition.retryCount = 0;
}
}
function checkStable({ transition, microtasks, macroTasks, parentZone, timeout }) {
const { isUnstable } = transition;
const { slowMs, timeoutMs, slow, isSlow } = transition;
if (!microtasks && !macroTasks && !transition.stable) {
clearTimeout(timeout.timeoutId);
clearTimeout(timeout.slowId);
parentZone.run(() => {
handleError(transition);
if (slow) {
isSlow.next(false);
}
isUnstable.next(false);
});
}
if ((microtasks || macroTasks) && transition.stable) {
if (transition.failed) {
transition.retryCount++;
}
transition.failed = false;
transition.timeout = false;
transition.thrownError = null;
parentZone.run(() => {
isUnstable.next(true);
if (slowMs) {
timeout.slowId = setTimeout(() => {
transition.isSlow.next(true);
}, slowMs);
}
if (timeoutMs) {
timeout.timeoutId = setTimeout(() => {
transition.failed = true;
transition.timeout = true;
transition.thrownError = new Error(`Transition timed out after ${timeoutMs}ms`);
transition.cancel();
}, timeoutMs);
}
});
}
}
let id = 0;
class TransitionSpec {
constructor(name, transition) {
this.name = name;
this.transition = transition;
this.microtasks = 0;
this.macroTasks = 0;
this.parentZone = Zone.current;
this.tasks = new Set();
this.timeout = {};
this.properties = {
id: id++
};
}
onScheduleTask(parentZoneDelegate, currentZone, targetZone, task) {
this.tasks.add(task);
return parentZoneDelegate.scheduleTask(targetZone, task);
}
onInvokeTask(parentZoneDelegate, currentZone, targetZone, task, applyThis, applyArgs) {
this.tasks.delete(task);
return parentZoneDelegate.invokeTask(targetZone, task, applyThis, applyArgs);
}
onCancelTask(parentZoneDelegate, currentZone, targetZone, task) {
this.tasks.delete(task);
return parentZoneDelegate.cancelTask(targetZone, task);
}
onHasTask(parentZoneDelegate, currentZone, targetZone, hasTaskState) {
if (currentZone === targetZone) {
if (hasTaskState.change === "microTask") {
this.microtasks += hasTaskState.microTask ? 1 : -1;
checkStable(this);
}
else if (hasTaskState.change === "macroTask") {
this.macroTasks += hasTaskState.macroTask ? 1 : -1;
checkStable(this);
}
}
return parentZoneDelegate.hasTask(targetZone, hasTaskState);
}
onHandleError(parentZoneDelegate, currentZone, targetZone, error) {
this.transition.failed = true;
this.transition.thrownError = error;
return parentZoneDelegate.handleError(targetZone, error);
}
cancelTasks() {
for (const task of this.tasks) {
task.zone.cancelTask(task);
}
}
}
class Transition {
constructor(options = {}) {
var _a, _b, _c;
this.options = options;
this.spec = new TransitionSpec("transition", this);
this.isUnstable = new BehaviorSubject(false);
this.isSlow = new BehaviorSubject(false);
this.onError = new Subject();
this.timeout = false;
this.failed = false;
this.retryCount = 0;
this.thrownError = null;
this.emitter = new EventEmitter(options.async);
this.slowMs = (_a = options.slowMs) !== null && _a !== void 0 ? _a : 0;
this.timeoutMs = (_b = options.timeoutMs) !== null && _b !== void 0 ? _b : 0;
this.resetOnSuccess = (_c = options.resetOnSuccess) !== null && _c !== void 0 ? _c : false;
}
get stable() {
return !this.unstable;
}
get unstable() {
return this.isUnstable.value;
}
get slow() {
return this.isSlow.value;
}
next(value) {
this.run(this.emitter.next, this.emitter, value);
}
error(error) {
this.run(this.emitter.error, this.emitter, error);
}
complete() {
this.run(this.emitter.complete, this.emitter);
}
emit(value) {
this.run(this.emitter.emit, this.emitter, value);
return this.isUnstable.pipe(takeWhile(Boolean));
}
cancel() {
this.spec.cancelTasks();
}
subscribe(observer) {
return this.emitter.subscribe(observer);
}
run(fn, applyThis, ...applyArgs) {
if (Zone.current.get("id") === this.spec.properties.id) {
return fn.apply(this, applyArgs);
}
else {
const zone = Zone.current.fork(this.spec);
if (this.options.cancelPrevious) {
this.cancel();
}
return zone.runGuarded(fn, applyThis, applyArgs);
}
}
ngOnSelect(observer) {
return merge(this.isUnstable, this.isSlow).pipe(map(() => this)).subscribe(observer);
}
}
function useTransition(transition, options = { emit: false }) {
return source => transition ? new Observable(subscriber => {
return transition.run(() => {
if (options.emit) {
subscriber.add(transition.subscribe(subscriber));
}
subscriber.add(source.subscribe(subscriber));
return subscriber;
});
}) : source;
}
const TransitionToken = class TransitionToken extends InjectionToken {
constructor(name, options) {
super(name, {
factory() {
return new Transition(options);
}
});
}
};
const defaults = { track: true, immediate: true };
function createDecorator(symbol, defaults) {
return function decorate(options) {
return function (target, key, descriptor) {
setMeta(symbol, Object.assign(Object.assign(Object.assign({}, defaults), options), { key, descriptor }), target, key);
};
};
}
function Store() {
return function (target) {
const { prototype } = target;
decorateFactory(target, setup);
decorateChanges(prototype);
decorateOnInit(prototype);
decorateDestroy(prototype);
decorateCheck(prototype, "ngDoCheck" /* Phase.DoCheck */);
decorateCheck(prototype, "ngAfterContentChecked" /* Phase.AfterContentChecked */);
decorateCheck(prototype, "ngAfterViewChecked" /* Phase.AfterViewChecked */);
decorateActions(prototype);
decorateSelectors(prototype);
decorateSelect(target);
};
}
const Action = createDecorator(action$1, { phase: "ngDoCheck" /* Phase.DoCheck */ });
const Invoke = createDecorator(action$1, Object.assign(Object.assign({}, defaults), { phase: "ngDoCheck" /* Phase.DoCheck */ }));
const Before = createDecorator(action$1, Object.assign(Object.assign({}, defaults), { phase: "ngAfterContentChecked" /* Phase.AfterContentChecked */ }));
const Layout = createDecorator(action$1, Object.assign(Object.assign({}, defaults), { phase: "ngAfterViewChecked" /* Phase.AfterViewChecked */ }));
function Caught() {
return function (target, key, descriptor) {
setMeta(action$1, { key, descriptor, phase: "ngDoCheck" /* Phase.DoCheck */, catchError: false }, target, key);
setMeta(caught, { key, descriptor }, target, key);
};
}
function Select(token) {
return function (target, key, descriptor) {
setMeta(selector, { key, token, descriptor }, target, key);
};
}
function onVisible(document, refCount) {
return toggle(refCount, fromEvent(document, "visibilitychange").pipe(filter(() => document.visibilityState === "visible")));
}
function onReconnect(document, refCount) {
const window = document.defaultView;
if (window) {
return toggle(refCount, fromEvent(window, "online"));
}
else {
return EMPTY;
}
}
function toggle(refCount, source) {
const delay = refCount.pipe(filter((count) => count > 0));
const resume = of(null);
return source.pipe(debounce(() => refCount.value > 0 ? resume : delay));
}
class ResourceManager {
constructor() {
this.cache = new Map();
this.document = inject(DOCUMENT);
}
query(source, options) {
const key = this.keygen(options.key);
const { cache, document } = this;
if (cache.has(key)) {
const { resource, fetch, errors } = cache.get(key);
if (options.refreshIfStale !== false) {
fetch.next(source);
}
return merge(resource, errors);
}
const cancel = new Subject();
const invalidate = new Subject();
const fetch = new BehaviorSubject(source);
const refCount = new BehaviorSubject(0);
const invalidators = [fetch];
if (options.refreshOnFocus) {
invalidators.push(onVisible(document, refCount));
}
if (options.refreshOnReconnect) {
invalidators.push(onReconnect(document, refCount));
}
if (options.refreshInterval) {
const nativeInterval = observeInZone(interval(options.refreshInterval), Zone.root);
invalidators.push(toggle(refCount, nativeInterval));
}
const errors = new Subject();
const reload = merge(...invalidators).pipe(switchMap(() => fetch.pipe(takeUntil(cancel))), takeUntil(cancel), throttle(() => { var _a; return observeInZone(timer((_a = options.staleTime) !== null && _a !== void 0 ? _a : 0), Zone.root); }));
const resource = invalidate.pipe(startWith(null), switchMap(() => reload), switchAll(), retry({
resetOnSuccess: true,
delay: (error, retryCount) => {
fetch.next(void 0);
errors.error(new QueryError(error, retryCount));
return resource;
}
}), share({
connector: () => { var _a; return new ReplaySubject(1, (_a = options.cacheTime) !== null && _a !== void 0 ? _a : Infinity); },
resetOnError: false,
resetOnComplete: false,
resetOnRefCountZero: false
}), tap({
subscribe: () => refCount.next(refCount.value + 1),
unsubscribe: () => refCount.next(refCount.value - 1)
}));
cache.set(key, {
resource,
errors,
fetch,
cancel,
invalidate,
source,
options
});
return merge(resource, errors);
}
mutate(source, options) {
const keys = options.invalidate ? Array.isArray(options.invalidate[0]) ? options.invalidate.map(this.keygen) : [this.keygen(options.invalidate)] : [];
for (const key of keys) {
this.invalidate(key, true);
}
return source.pipe(finalize(() => {
for (const key of keys) {
this.invalidate(key, false);
}
}));
}
revalidate(key) {
this.invalidate(this.keygen(key), true);
this.invalidate(this.keygen(key), false);
}
keygen(seed) {
return JSON.stringify(seed);
}
invalidate(key, doCancel) {
for (const [matchKey, { invalidate, cancel }] of this.cache) {
if (matchKey.startsWith(key.slice(0, key.length - 2))) {
if (doCancel) {
cancel.next();
}
else {
invalidate.next();
}
}
}
}
}
ResourceManager.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: ResourceManager, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
ResourceManager.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: ResourceManager, providedIn: "root" });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.0", ngImport: i0, type: ResourceManager, decorators: [{
type: Injectable,
args: [{ providedIn: "root" }]
}] });
function useQuery(options) {
var _a;
const resource = (_a = options.resource) !== null && _a !== void 0 ? _a : inject(ResourceManager);
return source => resource.query(source, options);
}
function useMutation(options) {
var _a;
const resource = (_a = options.resource) !== null && _a !== void 0 ? _a : inject(ResourceManager);
return source => resource.mutate(source, options);
}
class QueryError {
constructor(error, retryCount) {
this.error = error;
this.retryCount = retryCount;
}
}
// noinspection JSUnusedGlobalSymbols
/**
* Generated bundle index. Do not edit.
*/
export { track as $, untrack as $$, ACTION, Action, Before, Caught, EVENTS, EventType, Invoke, Layout, QueryError, ResourceManager, Select, Selector, Store, TemplateProvider, Transition, TransitionToken, action, actionEvent, addTeardown, complete, completeEvent, configureStore, dispatch, error, errorEvent, events, get, inputs, isTracked, loadEffect, next, nextEvent, set, slice, store, track, untrack, useConcat, useExhaust, useInputs, useMerge, useMutation, useOperator, useQuery, useSwitch, useTransition, withState, decorateFactory as ɵɵdecorateFactory, stores as ɵɵstores };
//# sourceMappingURL=antischematic-angular-state-library.mjs.map
//# sourceMappingURL=antischematic-angular-state-library.mjs.map