@aurelia/runtime
Advanced tools
Comparing version 2.1.0-dev.202304111838 to 2.1.0-dev.202304270200
@@ -12,3 +12,3 @@ export { ExpressionKind, CallFunctionExpression, CustomExpression, BindingBehaviorExpression, ValueConverterExpression, AssignExpression, ConditionalExpression, AccessThisExpression, AccessScopeExpression, AccessMemberExpression, AccessKeyedExpression, CallScopeExpression, CallMemberExpression, BinaryExpression, UnaryExpression, PrimitiveLiteralExpression, ArrayLiteralExpression, ObjectLiteralExpression, TemplateExpression, TaggedTemplateExpression, ArrayBindingPattern, ObjectBindingPattern, BindingIdentifier, ForOfStatement, Interpolation, DestructuringAssignmentExpression, DestructuringAssignmentSingleExpression, DestructuringAssignmentRestExpression, ArrowFunction, astVisit, Unparser, type AnyBindingExpression, type BindingBehaviorInstance, type IsPrimary, type IsLiteral, type IsLeftHandSide, type IsUnary, type IsBinary, type IsConditional, type IsAssign, type IsValueConverter, type IsBindingBehavior, type IsAssignable, type IsExpression, type IsExpressionOrStatement, type IVisitor, type BinaryOperator, type BindingIdentifierOrPattern, type UnaryOperator, type IAstEvaluator, type ValueConverterInstance, } from './binding/ast'; | ||
export { IDirtyChecker, DirtyCheckProperty, DirtyCheckSettings, } from './observation/dirty-checker'; | ||
export { type IEffect, IObservation, Observation, type EffectFunc, } from './observation/observation'; | ||
export { type IEffect, IObservation, Observation, type EffectRunFunc, } from './observation/observation'; | ||
export { type IObservableDefinition, observable, } from './observation/observable'; | ||
@@ -15,0 +15,0 @@ export { type IObjectObservationAdapter, IObserverLocator, INodeObserverLocator, getCollectionObserver, ObserverLocator, getObserverLookup, type ObservableGetter, type ObservableSetter, } from './observation/observer-locator'; |
@@ -10,4 +10,4 @@ import { IDisposable, IIndexable, IServiceLocator } from '@aurelia/kernel'; | ||
get: IServiceLocator['get']; | ||
useScope(scope: Scope): void; | ||
limit(opts: IRateLimitOptions): IDisposable; | ||
useScope?(scope: Scope): void; | ||
limit?(opts: IRateLimitOptions): IDisposable; | ||
} | ||
@@ -19,2 +19,3 @@ export interface IRateLimitOptions { | ||
now: () => number; | ||
signals: string[]; | ||
} | ||
@@ -46,5 +47,5 @@ export declare const ICoercionConfiguration: import("@aurelia/kernel").InterfaceSymbol<ICoercionConfiguration>; | ||
} | ||
export interface ISubscribable { | ||
subscribe(subscriber: ISubscriber): void; | ||
unsubscribe(subscriber: ISubscriber): void; | ||
export interface ISubscribable<T = ISubscriber> { | ||
subscribe(subscriber: T): void; | ||
unsubscribe(subscriber: T): void; | ||
} | ||
@@ -126,3 +127,3 @@ export interface ICollectionSubscribable { | ||
*/ | ||
export interface IObserver extends IAccessor, ISubscribable { | ||
export interface IObserver<TValue = unknown> extends IAccessor<TValue>, ISubscribable { | ||
doNotCache?: boolean; | ||
@@ -129,0 +130,0 @@ } |
@@ -5,6 +5,6 @@ import { AccessorType, IObserver } from '../observation'; | ||
import type { IObserverLocator } from './observer-locator'; | ||
export interface ComputedObserver extends IConnectableBinding, ISubscriberCollection { | ||
export type ComputedGetterFn<T = any, R = any> = (this: T, obj: T, observer: IConnectable) => R; | ||
export interface ComputedObserver<T extends object> extends IConnectableBinding, ISubscriberCollection { | ||
} | ||
export declare class ComputedObserver implements IObserver, IConnectableBinding, ISubscriber, ICollectionSubscriber, ISubscriberCollection { | ||
static create(obj: object, key: PropertyKey, descriptor: PropertyDescriptor, observerLocator: IObserverLocator, useProxy: boolean): ComputedObserver; | ||
export declare class ComputedObserver<T extends object> implements IObserver, IConnectableBinding, ISubscriber, ICollectionSubscriber, ISubscriberCollection { | ||
type: AccessorType; | ||
@@ -14,3 +14,3 @@ /** | ||
*/ | ||
readonly $get: (watcher: IConnectable) => unknown; | ||
readonly $get: ComputedGetterFn<T>; | ||
/** | ||
@@ -24,4 +24,4 @@ * The setter this observer is wrapping | ||
readonly oL: IObserverLocator; | ||
constructor(obj: object, get: (watcher: IConnectable) => unknown, set: undefined | ((v: unknown) => void), useProxy: boolean, observerLocator: IObserverLocator); | ||
getValue(): unknown; | ||
constructor(obj: T, get: ComputedGetterFn<T>, set: undefined | ((v: unknown) => void), observerLocator: IObserverLocator, useProxy: boolean); | ||
getValue(): any; | ||
setValue(v: unknown): void; | ||
@@ -28,0 +28,0 @@ handleChange(): void; |
import { IObserverLocator } from './observer-locator'; | ||
import type { IConnectable } from '../observation'; | ||
export interface IObservation extends Observation { | ||
export interface IObservation { | ||
/** | ||
* Run an effect function an track the dependencies inside it, | ||
* to re-run whenever a dependency has changed | ||
*/ | ||
run(fn: EffectRunFunc): IEffect; | ||
/** | ||
* Run a getter based on the given object as its first parameter and track the dependencies via this getter, | ||
* to call the callback whenever the value has changed | ||
*/ | ||
watch<T, R>(obj: T, getter: (obj: T, watcher: IConnectable) => R, callback: (value: R, oldValue: R | undefined) => unknown | void, options?: IWatchOptions): IEffect; | ||
} | ||
export declare const IObservation: import("@aurelia/kernel").InterfaceSymbol<IObservation>; | ||
export interface IWatchOptions { | ||
/** | ||
* Indicates whether the callback of a watch should be immediately called on init | ||
*/ | ||
immediate?: boolean; | ||
} | ||
export declare class Observation implements IObservation { | ||
@@ -10,10 +26,7 @@ private readonly oL; | ||
constructor(oL: IObserverLocator); | ||
/** | ||
* Run an effect function an track the dependencies inside it, | ||
* to re-run whenever a dependency has changed | ||
*/ | ||
run(fn: EffectFunc): IEffect; | ||
run(fn: EffectRunFunc): IEffect; | ||
watch<T, R>(obj: T, getter: (obj: T, watcher: IConnectable) => R, callback: (value: R, oldValue: R | undefined) => unknown | void, options?: IWatchOptions): IEffect; | ||
} | ||
export type EffectFunc = (runner: IConnectable) => void; | ||
export interface IEffect extends IConnectable { | ||
export type EffectRunFunc = (this: IConnectable, runner: IConnectable) => void; | ||
export interface IEffect { | ||
run(): void; | ||
@@ -20,0 +33,0 @@ stop(): void; |
@@ -0,1 +1,2 @@ | ||
import { ComputedGetterFn } from './computed-observer'; | ||
import { IDirtyChecker } from './dirty-checker'; | ||
@@ -31,2 +32,3 @@ import { PropertyAccessor } from './property-accessor'; | ||
getObserver(obj: unknown, key: PropertyKey): IObserver; | ||
getObserver<T, R>(obj: T, key: ComputedGetterFn<T, R>): IObserver<R>; | ||
getAccessor(obj: object, key: PropertyKey): AccessorOrObserver; | ||
@@ -40,3 +42,3 @@ getArrayObserver(observedArray: unknown[]): ICollectionObserver<CollectionKind.array>; | ||
export declare const getCollectionObserver: (collection: RepeatableCollection) => CollectionObserver | undefined; | ||
export declare const getObserverLookup: <T extends IObserver>(instance: object) => Record<PropertyKey, T>; | ||
export declare const getObserverLookup: <T extends IObserver<unknown>>(instance: object) => Record<PropertyKey, T>; | ||
//# sourceMappingURL=observer-locator.d.ts.map |
{ | ||
"name": "@aurelia/runtime", | ||
"version": "2.1.0-dev.202304111838", | ||
"version": "2.1.0-dev.202304270200", | ||
"main": "dist/cjs/index.cjs", | ||
@@ -52,5 +52,5 @@ "module": "dist/esm/index.mjs", | ||
"dependencies": { | ||
"@aurelia/kernel": "2.1.0-dev.202304111838", | ||
"@aurelia/metadata": "2.1.0-dev.202304111838", | ||
"@aurelia/platform": "2.1.0-dev.202304111838" | ||
"@aurelia/kernel": "2.1.0-dev.202304270200", | ||
"@aurelia/metadata": "2.1.0-dev.202304270200", | ||
"@aurelia/platform": "2.1.0-dev.202304270200" | ||
}, | ||
@@ -57,0 +57,0 @@ "devDependencies": { |
@@ -114,3 +114,3 @@ export { | ||
Observation, | ||
type EffectFunc, | ||
type EffectRunFunc, | ||
} from './observation/observation'; | ||
@@ -117,0 +117,0 @@ export { |
@@ -13,4 +13,4 @@ import { DI, IDisposable, IIndexable, IServiceLocator } from '@aurelia/kernel'; | ||
get: IServiceLocator['get']; | ||
useScope(scope: Scope): void; | ||
limit(opts: IRateLimitOptions): IDisposable; | ||
useScope?(scope: Scope): void; | ||
limit?(opts: IRateLimitOptions): IDisposable; | ||
} | ||
@@ -23,5 +23,6 @@ | ||
now: () => number; | ||
signals: string[]; | ||
} | ||
export const ICoercionConfiguration = DI.createInterface<ICoercionConfiguration>('ICoercionConfiguration'); | ||
export const ICoercionConfiguration = /*@__PURE__*/DI.createInterface<ICoercionConfiguration>('ICoercionConfiguration'); | ||
export interface ICoercionConfiguration { | ||
@@ -56,5 +57,5 @@ /** When set to `true`, enables the automatic type-coercion for bindables globally. */ | ||
export interface ISubscribable { | ||
subscribe(subscriber: ISubscriber): void; | ||
unsubscribe(subscriber: ISubscriber): void; | ||
export interface ISubscribable<T = ISubscriber> { | ||
subscribe(subscriber: T): void; | ||
unsubscribe(subscriber: T): void; | ||
} | ||
@@ -183,3 +184,3 @@ | ||
*/ | ||
export interface IObserver extends IAccessor, ISubscribable { | ||
export interface IObserver<TValue = unknown> extends IAccessor<TValue>, ISubscribable { | ||
doNotCache?: boolean; | ||
@@ -186,0 +187,0 @@ } |
@@ -9,3 +9,3 @@ import { | ||
import { wrap, unwrap } from './proxy-observation'; | ||
import { areEqual, createError, def, isFunction, objectAssign } from '../utilities-objects'; | ||
import { areEqual, createError, isFunction } from '../utilities-objects'; | ||
@@ -19,7 +19,11 @@ import type { | ||
import type { IConnectableBinding } from '../binding/connectable'; | ||
import type { IObserverLocator, ObservableGetter } from './observer-locator'; | ||
import type { IObserverLocator } from './observer-locator'; | ||
export interface ComputedObserver extends IConnectableBinding, ISubscriberCollection { } | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
export type ComputedGetterFn<T = any, R = any> = (this: T, obj: T, observer: IConnectable) => R; | ||
export class ComputedObserver implements | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
export interface ComputedObserver<T extends object> extends IConnectableBinding, ISubscriberCollection { } | ||
export class ComputedObserver<T extends object> implements | ||
IObserver, | ||
@@ -31,24 +35,2 @@ IConnectableBinding, | ||
public static create( | ||
obj: object, | ||
key: PropertyKey, | ||
descriptor: PropertyDescriptor, | ||
observerLocator: IObserverLocator, | ||
useProxy: boolean, | ||
): ComputedObserver { | ||
const getter = descriptor.get!; | ||
const setter = descriptor.set; | ||
const observer = new ComputedObserver(obj, getter, setter, useProxy, observerLocator); | ||
def(obj, key, { | ||
enumerable: descriptor.enumerable, | ||
configurable: true, | ||
get: objectAssign(((/* Computed Observer */) => observer.getValue()) as ObservableGetter, { getObserver: () => observer }), | ||
set: (/* Computed Observer */v) => { | ||
observer.setValue(v); | ||
}, | ||
}); | ||
return observer; | ||
} | ||
public type: AccessorType = AccessorType.Observer; | ||
@@ -58,4 +40,2 @@ | ||
private _value: unknown = void 0; | ||
/** @internal */ | ||
private _oldValue: unknown = void 0; | ||
@@ -70,8 +50,11 @@ // todo: maybe use a counter allow recursive call to a certain level | ||
/** @internal */ | ||
private readonly _obj: object; | ||
private readonly _obj: T; | ||
/** @internal */ | ||
private readonly _wrapped: T; | ||
/** | ||
* The getter this observer is wrapping | ||
*/ | ||
public readonly $get: (watcher: IConnectable) => unknown; | ||
public readonly $get: ComputedGetterFn<T>; | ||
@@ -83,5 +66,2 @@ /** | ||
/** @internal */ | ||
private readonly _useProxy: boolean; | ||
/** | ||
@@ -93,12 +73,12 @@ * A semi-private property used by connectable mixin | ||
public constructor( | ||
obj: object, | ||
get: (watcher: IConnectable) => unknown, | ||
obj: T, | ||
get: ComputedGetterFn<T>, | ||
set: undefined | ((v: unknown) => void), | ||
observerLocator: IObserverLocator, | ||
useProxy: boolean, | ||
observerLocator: IObserverLocator, | ||
) { | ||
this._obj = obj; | ||
this._wrapped = useProxy ? wrap(obj) : obj; | ||
this.$get = get; | ||
this.$set = set; | ||
this._useProxy = useProxy; | ||
this.oL = observerLocator; | ||
@@ -109,3 +89,3 @@ } | ||
if (this.subs.count === 0) { | ||
return this.$get.call(this._obj, this); | ||
return this.$get.call(this._obj, this._obj, this); | ||
} | ||
@@ -179,6 +159,3 @@ if (this._isDirty) { | ||
if (!areEqual(newValue, oldValue)) { | ||
this._oldValue = oldValue; | ||
oV = this._oldValue; | ||
this._oldValue = this._value; | ||
this.subs.notify(this._value, oV); | ||
this.subs.notify(this._value, oldValue); | ||
} | ||
@@ -192,3 +169,3 @@ } | ||
enterConnectable(this); | ||
return this._value = unwrap(this.$get.call(this._useProxy ? wrap(this._obj) : this._obj, this)); | ||
return this._value = unwrap(this.$get.call(this._wrapped, this._wrapped, this)); | ||
} finally { | ||
@@ -204,5 +181,1 @@ this.obs.clear(); | ||
subscriberCollection(ComputedObserver); | ||
// a reusable variable for `.flush()` methods of observers | ||
// so that there doesn't need to create an env record for every call | ||
let oV: unknown = void 0; |
import { connectable } from '../binding/connectable'; | ||
import { enterConnectable, exitConnectable } from './connectable-switcher'; | ||
import { IObserverLocator } from './observer-locator'; | ||
import { createError, createInterface } from '../utilities-objects'; | ||
import type { ICollectionSubscriber, IConnectable, ISubscriber } from '../observation'; | ||
import type { BindingObserverRecord } from '../binding/connectable'; | ||
import { createError, createInterface } from '../utilities-objects'; | ||
export interface IObservation extends Observation {} | ||
export const IObservation = createInterface<IObservation>('IObservation', x => x.singleton(Observation)); | ||
export interface IObservation { | ||
/** | ||
* Run an effect function an track the dependencies inside it, | ||
* to re-run whenever a dependency has changed | ||
*/ | ||
run(fn: EffectRunFunc): IEffect; | ||
/** | ||
* Run a getter based on the given object as its first parameter and track the dependencies via this getter, | ||
* to call the callback whenever the value has changed | ||
*/ | ||
watch<T, R>( | ||
obj: T, | ||
getter: (obj: T, watcher: IConnectable) => R, | ||
callback: (value: R, oldValue: R | undefined) => unknown | void, | ||
options?: IWatchOptions, | ||
): IEffect; | ||
} | ||
export const IObservation = /*@__PURE__*/createInterface<IObservation>('IObservation', x => x.singleton(Observation)); | ||
export interface IWatchOptions { | ||
/** | ||
* Indicates whether the callback of a watch should be immediately called on init | ||
*/ | ||
immediate?: boolean; | ||
} | ||
export class Observation implements IObservation { | ||
@@ -16,2 +39,5 @@ | ||
/** @internal */ | ||
private readonly _defaultWatchOptions: IWatchOptions = { immediate: true }; | ||
public constructor( | ||
@@ -21,8 +47,4 @@ private readonly oL: IObserverLocator, | ||
/** | ||
* Run an effect function an track the dependencies inside it, | ||
* to re-run whenever a dependency has changed | ||
*/ | ||
public run(fn: EffectFunc): IEffect { | ||
const effect = new Effect(this.oL, fn); | ||
public run(fn: EffectRunFunc): IEffect { | ||
const effect = new RunEffect(this.oL, fn); | ||
// todo: batch effect run after it's in | ||
@@ -32,6 +54,40 @@ effect.run(); | ||
} | ||
public watch<T, R>( | ||
obj: T, | ||
getter: (obj: T, watcher: IConnectable) => R, | ||
callback: (value: R, oldValue: R | undefined) => unknown | void, | ||
options: IWatchOptions = this._defaultWatchOptions | ||
): IEffect { | ||
// eslint-disable-next-line no-undef-init | ||
let $oldValue: R | undefined = undefined; | ||
let stopped = false; | ||
const observer = this.oL.getObserver(obj, getter); | ||
const handler = { | ||
handleChange: (newValue: R, oldValue: R) => callback(newValue, $oldValue = oldValue), | ||
}; | ||
const run = () => { | ||
if (stopped) return; | ||
callback(observer.getValue(), $oldValue); | ||
}; | ||
const stop = () => { | ||
stopped = true; | ||
observer.unsubscribe(handler); | ||
}; | ||
observer.subscribe(handler); | ||
if (options.immediate) { | ||
run(); | ||
} | ||
return { run, stop }; | ||
} | ||
} | ||
export type EffectFunc = (runner: IConnectable) => void; | ||
export interface IEffect extends IConnectable { | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
function testObservationWatch(a: IObservation) { | ||
a.watch({ b: 5 }, o => o.b + 1, v => v.toFixed()); | ||
a.watch({ b: { c: '' } }, o => o.b.c === '', v => v); | ||
} | ||
export type EffectRunFunc = (this: IConnectable, runner: IConnectable) => void; | ||
export interface IEffect { | ||
run(): void; | ||
@@ -41,4 +97,4 @@ stop(): void; | ||
interface Effect extends IConnectable {} | ||
class Effect implements IEffect, ISubscriber, ICollectionSubscriber { | ||
interface RunEffect extends IConnectable {} | ||
class RunEffect implements IEffect, ISubscriber, ICollectionSubscriber { | ||
public readonly obs!: BindingObserverRecord; | ||
@@ -54,3 +110,3 @@ // to configure this, potentially a 2nd parameter is needed for run | ||
public readonly oL: IObserverLocator, | ||
public readonly fn: EffectFunc, | ||
public readonly fn: EffectRunFunc, | ||
) { | ||
@@ -115,2 +171,2 @@ } | ||
connectable(Effect); | ||
connectable(RunEffect); |
import { Primitive, isArrayIndex, ILogger } from '@aurelia/kernel'; | ||
import { getArrayObserver } from './array-observer'; | ||
import { ComputedObserver } from './computed-observer'; | ||
import { ComputedGetterFn, ComputedObserver } from './computed-observer'; | ||
import { IDirtyChecker } from './dirty-checker'; | ||
@@ -10,3 +10,3 @@ import { getMapObserver } from './map-observer'; | ||
import { SetterObserver } from './setter-observer'; | ||
import { safeString, createLookup, def, hasOwnProp, isArray, createInterface, createError, isMap, isSet, isObject } from '../utilities-objects'; | ||
import { safeString, createLookup, def, hasOwnProp, isArray, createInterface, createError, isMap, isSet, isObject, objectAssign, isFunction } from '../utilities-objects'; | ||
@@ -31,3 +31,3 @@ import type { | ||
export interface IObserverLocator extends ObserverLocator {} | ||
export const IObserverLocator = createInterface<IObserverLocator>('IObserverLocator', x => x.singleton(ObserverLocator)); | ||
export const IObserverLocator = /*@__PURE__*/createInterface<IObserverLocator>('IObserverLocator', x => x.singleton(ObserverLocator)); | ||
@@ -39,3 +39,3 @@ export interface INodeObserverLocator { | ||
} | ||
export const INodeObserverLocator = createInterface<INodeObserverLocator>('INodeObserverLocator', x => x.cachedCallback(handler => { | ||
export const INodeObserverLocator = /*@__PURE__*/createInterface<INodeObserverLocator>('INodeObserverLocator', x => x.cachedCallback(handler => { | ||
if (__DEV__) { | ||
@@ -90,9 +90,14 @@ handler.getAll(ILogger).forEach(logger => { | ||
public getObserver(obj: unknown, key: PropertyKey): IObserver { | ||
public getObserver(obj: unknown, key: PropertyKey): IObserver; | ||
public getObserver<T, R>(obj: T, key: ComputedGetterFn<T, R>): IObserver<R>; | ||
public getObserver(obj: unknown, key: PropertyKey | ComputedGetterFn): IObserver { | ||
if (obj == null) { | ||
throw nullObjectError(key); | ||
throw nullObjectError(safeString(key)); | ||
} | ||
if (!isObject(obj)) { | ||
return new PrimitiveObserver(obj as Primitive, key); | ||
return new PrimitiveObserver(obj as Primitive, isFunction(key) ? '' : key); | ||
} | ||
if (isFunction(key)) { | ||
return new ComputedObserver(obj, key, void 0, this, true); | ||
} | ||
const lookup = getObserverLookup(obj); | ||
@@ -181,3 +186,3 @@ let observer = lookup[key]; | ||
? pd.configurable | ||
? ComputedObserver.create(obj, key, pd, this, /* AOT: not true for IE11 */ true) | ||
? this._createComputedObserver(obj, key, pd, true) | ||
: this._dirtyChecker.createProperty(obj, key) | ||
@@ -193,2 +198,17 @@ : obs; | ||
/** @internal */ | ||
private _createComputedObserver(obj: object, key: PropertyKey, pd: PropertyDescriptor, useProxy?: boolean) { | ||
const observer = new ComputedObserver(obj, pd.get!, pd.set, this, !!useProxy); | ||
def(obj, key, { | ||
enumerable: pd.enumerable, | ||
configurable: true, | ||
get: objectAssign(((/* Computed Observer */) => observer.getValue()) as ObservableGetter, { getObserver: () => observer }), | ||
set: (/* Computed Observer */v) => { | ||
observer.setValue(v); | ||
}, | ||
}); | ||
return observer; | ||
} | ||
/** @internal */ | ||
private _getAdapterObserver(obj: IObservable, key: PropertyKey, pd: PropertyDescriptor): IObserver | null { | ||
@@ -195,0 +215,0 @@ if (this._adapters.length > 0) { |
Sorry, the diff of this file is too big to display
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
1637321
34730
+ Added@aurelia/kernel@2.1.0-dev.202304270200(transitive)
+ Added@aurelia/metadata@2.1.0-dev.202304270200(transitive)
+ Added@aurelia/platform@2.1.0-dev.202304270200(transitive)
- Removed@aurelia/kernel@2.1.0-dev.202304111838(transitive)
- Removed@aurelia/metadata@2.1.0-dev.202304111838(transitive)
- Removed@aurelia/platform@2.1.0-dev.202304111838(transitive)