@aurelia/runtime
Advanced tools
Comparing version 2.1.0-dev.202404150648 to 2.1.0-dev.202405060015
@@ -1,15 +0,11 @@ | ||
export { type ExpressionKind, CallFunctionExpression, CustomExpression, BindingBehaviorExpression, ValueConverterExpression, AssignExpression, ConditionalExpression, AccessThisExpression, AccessGlobalExpression, AccessScopeExpression, AccessBoundaryExpression, 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 { astAssign, astBind, astEvaluate, astUnbind, } from './binding/ast.eval'; | ||
export { type IConnectableBinding, connectable, BindingObserverRecord, } from './binding/connectable'; | ||
export { IExpressionParser, type ExpressionType, parseExpression, } from './binding/expression-parser'; | ||
export { type IObserverLocatorBasedConnectable, type IObserverRecord, connectable, } from './observation/connectable'; | ||
export { ArrayObserver, ArrayIndexObserver, enableArrayObservation, disableArrayObservation, type IArrayIndexObserver, } from './observation/array-observer'; | ||
export { MapObserver, enableMapObservation, disableMapObservation, } from './observation/map-observer'; | ||
export { SetObserver, enableSetObservation, disableSetObservation } from './observation/set-observer'; | ||
export { BindingContext, Scope, } from './observation/scope'; | ||
export { CollectionLengthObserver, CollectionSizeObserver, } from './observation/collection-length-observer'; | ||
export { ComputedObserver, type ComputedGetterFn, } from './observation/computed-observer'; | ||
export { IDirtyChecker, DirtyChecker, DirtyCheckProperty, DirtyCheckSettings, } from './observation/dirty-checker'; | ||
export { type IEffect, IObservation, Observation, type EffectRunFunc, } from './observation/observation'; | ||
export { type IEffect, IObservation, Observation, type EffectRunFunc, } from './observation/effect-runner'; | ||
export { type IObservableDefinition, observable, } from './observation/observable'; | ||
export { type IObjectObservationAdapter, IObserverLocator, INodeObserverLocator, getCollectionObserver, ObserverLocator, getObserverLookup, type ObservableGetter, type ObservableSetter, } from './observation/observer-locator'; | ||
export { type IObjectObservationAdapter, IObserverLocator, INodeObserverLocator, IComputedObserverLocator, getCollectionObserver, ObserverLocator, getObserverLookup, type ObservableGetter, } from './observation/observer-locator'; | ||
export { PrimitiveObserver, } from './observation/primitive-observer'; | ||
@@ -20,7 +16,6 @@ export { PropertyAccessor, } from './observation/property-accessor'; | ||
export { SetterObserver, } from './observation/setter-observer'; | ||
export { ISignaler, } from './observation/signaler'; | ||
export { SubscriberRecord, subscriberCollection, } from './observation/subscriber-collection'; | ||
export { subscriberCollection, } from './observation/subscriber-collection'; | ||
export { batch, } from './observation/subscriber-batch'; | ||
export { ConnectableSwitcher, } from './observation/connectable-switcher'; | ||
export { type AccessorOrObserver, type IRateLimitOptions, type IBinding, AccessorType, type Collection, type CollectionKind, type IAccessor, type IBindingContext, type ICollectionChangeTracker, type ICollectionObserver, type IConnectable, type ICollectionSubscriber, type IndexMap, type IObserver, type IObservable, type IOverrideContext, type InterceptorFunc, type ISubscribable, type ISubscriberCollection, type CollectionObserver, type ICollectionSubscriberCollection, type ICollectionSubscribable, type ISubscriber, type ISubscriberRecord, isIndexMap, copyIndexMap, cloneIndexMap, createIndexMap, ICoercionConfiguration, } from './observation'; | ||
export { type AccessorOrObserver, AccessorType, type Collection, type CollectionKind, type IAccessor, type ICollectionChangeTracker, type ICollectionObserver, type IConnectable, type ICollectionSubscriber, type IndexMap, type IObserver, type IObservable, type InterceptorFunc, type ISubscribable, type ISubscriberCollection, type CollectionObserver, type ICollectionSubscriberCollection, type ICollectionSubscribable, type ISubscriber, type ISubscriberRecord, isIndexMap, copyIndexMap, cloneIndexMap, createIndexMap, ICoercionConfiguration, } from './observation'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -1,20 +0,3 @@ | ||
import { IDisposable, IIndexable, IServiceLocator } from '@aurelia/kernel'; | ||
import type { Scope } from './observation/scope'; | ||
import { IIndexable } from '@aurelia/kernel'; | ||
import type { CollectionLengthObserver, CollectionSizeObserver } from './observation/collection-length-observer'; | ||
import { TaskQueue } from '@aurelia/platform'; | ||
export interface IBinding { | ||
readonly isBound: boolean; | ||
bind(scope: Scope): void; | ||
unbind(): void; | ||
get: IServiceLocator['get']; | ||
useScope?(scope: Scope): void; | ||
limit?(opts: IRateLimitOptions): IDisposable; | ||
} | ||
export interface IRateLimitOptions { | ||
type: 'throttle' | 'debounce'; | ||
delay: number; | ||
queue: TaskQueue; | ||
now: () => number; | ||
signals: string[]; | ||
} | ||
export declare const ICoercionConfiguration: import("@aurelia/kernel").InterfaceSymbol<ICoercionConfiguration>; | ||
@@ -156,8 +139,2 @@ export interface ICoercionConfiguration { | ||
export type CollectionObserver = ICollectionObserver<CollectionKind>; | ||
export interface IBindingContext { | ||
[key: PropertyKey]: any; | ||
} | ||
export interface IOverrideContext { | ||
[key: PropertyKey]: any; | ||
} | ||
export type IObservable<T = IIndexable> = T & { | ||
@@ -164,0 +141,0 @@ $observers?: IIndexable<{}, AccessorOrObserver>; |
import { ICoercionConfiguration, IObserver, InterceptorFunc } from '../observation'; | ||
import type { AccessorType, ISubscriber, ICollectionSubscriber, ISubscriberCollection, IConnectable } from '../observation'; | ||
import type { IConnectableBinding } from '../binding/connectable'; | ||
import type { IObserverLocatorBasedConnectable } from './connectable'; | ||
import type { IObserverLocator } from './observer-locator'; | ||
export type ComputedGetterFn<T = any, R = any> = (this: T, obj: T, observer: IConnectable) => R; | ||
export interface ComputedObserver<T extends object> extends IConnectableBinding, ISubscriberCollection { | ||
export interface ComputedObserver<T extends object> extends IObserverLocatorBasedConnectable, ISubscriberCollection { | ||
} | ||
export declare class ComputedObserver<T extends object> implements IObserver, IConnectableBinding, ISubscriber, ICollectionSubscriber, ISubscriberCollection { | ||
export declare class ComputedObserver<T extends object> implements IObserver, IObserverLocatorBasedConnectable, ISubscriber, ICollectionSubscriber, ISubscriberCollection { | ||
type: AccessorType; | ||
@@ -10,0 +10,0 @@ /** |
@@ -1,3 +0,2 @@ | ||
import { AccessorType, IAccessor, ISubscriberCollection } from '../observation'; | ||
import type { Constructable } from '@aurelia/kernel'; | ||
import { type Constructable } from '@aurelia/kernel'; | ||
import type { InterceptorFunc } from '../observation'; | ||
@@ -9,17 +8,12 @@ export interface IObservableDefinition { | ||
} | ||
export declare function observable(target: object, key: PropertyKey, descriptor?: PropertyDescriptor & { | ||
initializer?: () => unknown; | ||
}): void; | ||
export declare function observable(config: IObservableDefinition): (target: Constructable | object, ...args: unknown[]) => void; | ||
export declare function observable(key: PropertyKey): ClassDecorator; | ||
export declare function observable(): PropertyDecorator; | ||
export interface SetterNotifier extends IAccessor, ISubscriberCollection { | ||
} | ||
export declare class SetterNotifier implements IAccessor { | ||
static mixed: boolean; | ||
readonly type: AccessorType; | ||
constructor(obj: object, callbackKey: PropertyKey, set: InterceptorFunc | undefined, initialValue: unknown); | ||
getValue(): unknown; | ||
setValue(value: unknown): void; | ||
} | ||
type FieldInitializer<TFThis, TValue> = (this: TFThis, initialValue: TValue) => TValue; | ||
type ObservableFieldDecorator<TFThis, TValue> = (target: undefined, context: ClassFieldDecoratorContext<TFThis, TValue>) => FieldInitializer<TFThis, TValue>; | ||
type ObservableClassDecorator<TCThis extends Constructable> = (target: TCThis, context: ClassDecoratorContext<TCThis>) => void; | ||
export declare const observable: { | ||
<TFThis, TValue>(target: undefined, context: ClassFieldDecoratorContext<TFThis, TValue>): FieldInitializer<TFThis, TValue>; | ||
<TCThis extends Constructable, TFThis_1, TValue_1>(config: IObservableDefinition): (target: TCThis | undefined, context: ClassDecoratorContext<TCThis> | ClassFieldDecoratorContext<TFThis_1, TValue_1>) => void | FieldInitializer<TFThis_1, TValue_1>; | ||
<TCThis_1 extends Constructable>(key: PropertyKey): ObservableClassDecorator<TCThis_1>; | ||
<TFThis_2, TValue_2>(): ObservableFieldDecorator<TFThis_2, TValue_2>; | ||
}; | ||
export {}; | ||
//# sourceMappingURL=observable.d.ts.map |
@@ -17,12 +17,12 @@ import { ComputedGetterFn } from './computed-observer'; | ||
export declare const INodeObserverLocator: import("@aurelia/kernel").InterfaceSymbol<INodeObserverLocator>; | ||
export interface IComputedObserverLocator { | ||
getObserver(obj: object, key: PropertyKey, pd: ExtendedPropertyDescriptor, requestor: IObserverLocator): IObserver; | ||
} | ||
export declare const IComputedObserverLocator: import("@aurelia/kernel").InterfaceSymbol<IComputedObserverLocator>; | ||
export type ExtendedPropertyDescriptor = PropertyDescriptor & { | ||
get?: ObservableGetter; | ||
set?: ObservableSetter; | ||
}; | ||
export type ObservableGetter = PropertyDescriptor['get'] & { | ||
getObserver?(obj: unknown, requestor: IObserverLocator): IObserver; | ||
getObserver?(obj: unknown): IObserver; | ||
}; | ||
export type ObservableSetter = PropertyDescriptor['set'] & { | ||
getObserver?(obj: unknown, requestor: IObserverLocator): IObserver; | ||
}; | ||
export declare class ObserverLocator { | ||
@@ -29,0 +29,0 @@ addAdapter(adapter: IObjectObservationAdapter): void; |
import { Constructable } from '@aurelia/kernel'; | ||
export declare function nowrap(): (target: unknown, context: ClassDecoratorContext | ClassFieldDecoratorContext) => void; | ||
/** | ||
* A decorator to signal proxy observation shouldn't make an effort to wrap an object | ||
*/ | ||
export declare function nowrap(target: Constructable): void; | ||
export declare function nowrap(target: object, key: PropertyKey, descriptor?: PropertyDescriptor): void; | ||
export declare function nowrap(): ClassDecorator | PropertyDecorator | any; | ||
export declare function nowrap(target?: Constructable | object, key?: PropertyKey, descriptor?: PropertyDescriptor): ClassDecorator | PropertyDecorator; | ||
export declare function nowrap(target: Constructable, context: ClassDecoratorContext): void; | ||
export declare function nowrap(target: undefined, context: ClassFieldDecoratorContext): void; | ||
//# sourceMappingURL=proxy-decorators.d.ts.map |
@@ -1,12 +0,8 @@ | ||
import type { Collection, ICollectionSubscriber, IndexMap, ISubscriber, ISubscriberRecord } from '../observation'; | ||
import type { ICollectionSubscriber, ISubscriber } from '../observation'; | ||
import { Constructable } from '@aurelia/kernel'; | ||
export type IAnySubscriber = ISubscriber | ICollectionSubscriber; | ||
export declare function subscriberCollection(): ClassDecorator; | ||
export declare function subscriberCollection(target: Function): void; | ||
export declare class SubscriberRecord<T extends IAnySubscriber> implements ISubscriberRecord<T> { | ||
count: number; | ||
add(subscriber: T): boolean; | ||
remove(subscriber: T): boolean; | ||
notify(val: unknown, oldVal: unknown): void; | ||
notifyCollection(collection: Collection, indexMap: IndexMap): void; | ||
} | ||
export declare const subscriberCollection: { | ||
(): <T extends Constructable>(value: T, context: ClassDecoratorContext) => T; | ||
<T_1 extends Constructable>(target: T_1, context: ClassDecoratorContext): T_1; | ||
}; | ||
//# sourceMappingURL=subscriber-collection.d.ts.map |
{ | ||
"name": "@aurelia/runtime", | ||
"version": "2.1.0-dev.202404150648", | ||
"version": "2.1.0-dev.202405060015", | ||
"main": "dist/cjs/index.cjs", | ||
@@ -57,5 +57,6 @@ "module": "dist/esm/index.mjs", | ||
"dependencies": { | ||
"@aurelia/kernel": "2.1.0-dev.202404150648", | ||
"@aurelia/metadata": "2.1.0-dev.202404150648", | ||
"@aurelia/platform": "2.1.0-dev.202404150648" | ||
"@aurelia/kernel": "2.1.0-dev.202405060015", | ||
"@aurelia/expression-parser": "2.1.0-dev.202405060015", | ||
"@aurelia/metadata": "2.1.0-dev.202405060015", | ||
"@aurelia/platform": "2.1.0-dev.202405060015" | ||
}, | ||
@@ -62,0 +63,0 @@ "devDependencies": { |
export { | ||
type ExpressionKind, | ||
// Ast nodes | ||
CallFunctionExpression, | ||
CustomExpression, | ||
BindingBehaviorExpression, | ||
ValueConverterExpression, | ||
AssignExpression, | ||
ConditionalExpression, | ||
AccessThisExpression, | ||
AccessGlobalExpression, | ||
AccessScopeExpression, | ||
AccessBoundaryExpression, | ||
AccessMemberExpression, | ||
AccessKeyedExpression, | ||
CallScopeExpression, | ||
CallMemberExpression, | ||
BinaryExpression, | ||
UnaryExpression, | ||
PrimitiveLiteralExpression, | ||
ArrayLiteralExpression, | ||
ObjectLiteralExpression, | ||
TemplateExpression, | ||
TaggedTemplateExpression, | ||
ArrayBindingPattern, | ||
ObjectBindingPattern, | ||
BindingIdentifier, | ||
ForOfStatement, | ||
Interpolation, | ||
DestructuringAssignmentExpression, | ||
DestructuringAssignmentSingleExpression, | ||
DestructuringAssignmentRestExpression, | ||
ArrowFunction, | ||
astVisit, | ||
Unparser, | ||
// ast typing helpers | ||
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 { | ||
astAssign, | ||
astBind, | ||
astEvaluate, | ||
astUnbind, | ||
} from './binding/ast.eval'; | ||
export { | ||
type IConnectableBinding, | ||
type IObserverLocatorBasedConnectable, | ||
type IObserverRecord, | ||
connectable, | ||
BindingObserverRecord, | ||
} from './binding/connectable'; | ||
export { | ||
IExpressionParser, | ||
type ExpressionType, | ||
parseExpression, | ||
} from './binding/expression-parser'; | ||
} from './observation/connectable'; | ||
@@ -95,6 +25,2 @@ export { | ||
export { | ||
BindingContext, | ||
Scope, | ||
} from './observation/scope'; | ||
export { | ||
CollectionLengthObserver, | ||
@@ -118,3 +44,3 @@ CollectionSizeObserver, | ||
type EffectRunFunc, | ||
} from './observation/observation'; | ||
} from './observation/effect-runner'; | ||
export { | ||
@@ -128,2 +54,3 @@ type IObservableDefinition, | ||
INodeObserverLocator, | ||
IComputedObserverLocator, | ||
getCollectionObserver, | ||
@@ -133,3 +60,3 @@ ObserverLocator, | ||
type ObservableGetter, | ||
type ObservableSetter, | ||
// type ObservableSetter, | ||
} from './observation/observer-locator'; | ||
@@ -152,6 +79,2 @@ export { | ||
export { | ||
ISignaler, | ||
} from './observation/signaler'; | ||
export { | ||
SubscriberRecord, | ||
subscriberCollection, | ||
@@ -168,4 +91,2 @@ } from './observation/subscriber-collection'; | ||
type AccessorOrObserver, | ||
type IRateLimitOptions, | ||
type IBinding, | ||
AccessorType, | ||
@@ -175,3 +96,2 @@ type Collection, | ||
type IAccessor, | ||
type IBindingContext, | ||
type ICollectionChangeTracker, | ||
@@ -184,3 +104,2 @@ type ICollectionObserver, | ||
type IObservable, | ||
type IOverrideContext, | ||
type InterceptorFunc, | ||
@@ -187,0 +106,0 @@ type ISubscribable, |
@@ -1,25 +0,6 @@ | ||
import { DI, IDisposable, IIndexable, IServiceLocator } from '@aurelia/kernel'; | ||
import { DI, IIndexable } from '@aurelia/kernel'; | ||
import { isArray, objectFreeze } from './utilities'; | ||
import type { Scope } from './observation/scope'; | ||
import type { CollectionLengthObserver, CollectionSizeObserver } from './observation/collection-length-observer'; | ||
import { TaskQueue } from '@aurelia/platform'; | ||
export interface IBinding { | ||
readonly isBound: boolean; | ||
bind(scope: Scope): void; | ||
unbind(): void; | ||
get: IServiceLocator['get']; | ||
useScope?(scope: Scope): void; | ||
limit?(opts: IRateLimitOptions): IDisposable; | ||
} | ||
export interface IRateLimitOptions { | ||
type: 'throttle' | 'debounce'; | ||
delay: number; | ||
queue: TaskQueue; | ||
now: () => number; | ||
signals: string[]; | ||
} | ||
export const ICoercionConfiguration = /*@__PURE__*/DI.createInterface<ICoercionConfiguration>('ICoercionConfiguration'); | ||
@@ -258,14 +239,4 @@ export interface ICoercionConfiguration { | ||
export interface IBindingContext { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
[key: PropertyKey]: any; | ||
} | ||
export interface IOverrideContext { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
[key: PropertyKey]: any; | ||
} | ||
export type IObservable<T = IIndexable> = T & { | ||
$observers?: IIndexable<{}, AccessorOrObserver>; | ||
}; |
@@ -18,3 +18,3 @@ import { | ||
} from './subscriber-collection'; | ||
import { def, defineHiddenProp, defineMetadata, getOwnMetadata, isFunction } from '../utilities'; | ||
import { def, defineHiddenProp, defineMetadata, getMetadata, isFunction } from '../utilities'; | ||
import { addCollectionBatch, batching } from './subscriber-batch'; | ||
@@ -372,4 +372,4 @@ import { IIndexable } from '@aurelia/kernel'; | ||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions | ||
if (!(getOwnMetadata(observationEnabledKey, Array) ?? false)) { | ||
defineMetadata(observationEnabledKey, true, Array); | ||
if (!(getMetadata(observationEnabledKey, Array) ?? false)) { | ||
defineMetadata(true, Array, observationEnabledKey); | ||
for (const method of methods) { | ||
@@ -394,2 +394,6 @@ if (proto[method].observing !== true) { | ||
export class ArrayObserver { | ||
static { | ||
subscriberCollection(ArrayObserver, null!); | ||
} | ||
public type: AccessorType = atObserver; | ||
@@ -449,2 +453,5 @@ | ||
export class ArrayIndexObserver implements IArrayIndexObserver { | ||
static { | ||
subscriberCollection(ArrayIndexObserver, null!); | ||
} | ||
@@ -513,5 +520,2 @@ public doNotCache: boolean = true; | ||
subscriberCollection(ArrayObserver); | ||
subscriberCollection(ArrayIndexObserver); | ||
export function getArrayObserver(array: unknown[]): ArrayObserver { | ||
@@ -518,0 +522,0 @@ let observer = observerLookup.get(array); |
@@ -20,2 +20,6 @@ import { Collection, IObserver, atObserver } from '../observation'; | ||
export class CollectionLengthObserver implements IObserver, ICollectionSubscriber { | ||
static { | ||
implementLengthObserver(CollectionLengthObserver); | ||
} | ||
public readonly type: AccessorType = atObserver; | ||
@@ -69,2 +73,6 @@ | ||
export class CollectionSizeObserver implements ICollectionSubscriber { | ||
static { | ||
implementLengthObserver(CollectionSizeObserver); | ||
} | ||
public readonly type: AccessorType = atObserver; | ||
@@ -109,3 +117,3 @@ | ||
ensureProto(proto, 'unsubscribe', unsubscribe); | ||
subscriberCollection(klass); | ||
return subscriberCollection(klass, null!); | ||
} | ||
@@ -124,4 +132,1 @@ | ||
} | ||
implementLengthObserver(CollectionLengthObserver); | ||
implementLengthObserver(CollectionSizeObserver); |
@@ -9,3 +9,3 @@ import { | ||
import { enterConnectable, exitConnectable } from './connectable-switcher'; | ||
import { connectable } from '../binding/connectable'; | ||
import { connectable } from './connectable'; | ||
import { wrap, unwrap } from './proxy-observation'; | ||
@@ -21,3 +21,3 @@ import { areEqual, isFunction } from '../utilities'; | ||
} from '../observation'; | ||
import type { IConnectableBinding } from '../binding/connectable'; | ||
import type { IObserverLocatorBasedConnectable } from './connectable'; | ||
import type { IObserverLocator } from './observer-locator'; | ||
@@ -30,10 +30,14 @@ import { ErrorNames, createMappedError } from '../errors'; | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
export interface ComputedObserver<T extends object> extends IConnectableBinding, ISubscriberCollection { } | ||
export interface ComputedObserver<T extends object> extends IObserverLocatorBasedConnectable, ISubscriberCollection { } | ||
export class ComputedObserver<T extends object> implements | ||
IObserver, | ||
IConnectableBinding, | ||
IObserverLocatorBasedConnectable, | ||
ISubscriber, | ||
ICollectionSubscriber, | ||
ISubscriberCollection { | ||
static { | ||
connectable(ComputedObserver, null!); | ||
subscriberCollection(ComputedObserver, null!); | ||
} | ||
@@ -203,4 +207,1 @@ public type: AccessorType = atObserver; | ||
} | ||
connectable(ComputedObserver); | ||
subscriberCollection(ComputedObserver); |
@@ -67,3 +67,3 @@ import { IContainer, IPlatform, Registration, resolve } from '@aurelia/kernel'; | ||
) { | ||
subscriberCollection(DirtyCheckProperty); | ||
subscriberCollection(DirtyCheckProperty, null!); | ||
} | ||
@@ -70,0 +70,0 @@ |
import { createIndexMap, atObserver } from '../observation'; | ||
import { CollectionSizeObserver } from './collection-length-observer'; | ||
import { subscriberCollection } from './subscriber-collection'; | ||
import { def, defineHiddenProp, defineMetadata, getOwnMetadata } from '../utilities'; | ||
import { def, defineHiddenProp, defineMetadata, getMetadata } from '../utilities'; | ||
@@ -135,4 +135,4 @@ import type { | ||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions | ||
if (!(getOwnMetadata(observationEnabledKey, Map) ?? false)) { | ||
defineMetadata(observationEnabledKey, true, Map); | ||
if (!(getMetadata(observationEnabledKey, Map) ?? false)) { | ||
defineMetadata(true, Map, observationEnabledKey); | ||
for (const method of methods) { | ||
@@ -157,2 +157,6 @@ if (proto[method].observing !== true) { | ||
export class MapObserver { | ||
static { | ||
subscriberCollection(MapObserver, null!); | ||
} | ||
public type: AccessorType = atObserver; | ||
@@ -195,4 +199,2 @@ private lenObs?: CollectionSizeObserver; | ||
subscriberCollection(MapObserver); | ||
export function getMapObserver(map: Map<unknown, unknown>): MapObserver { | ||
@@ -199,0 +201,0 @@ let observer = observerLookup.get(map); |
@@ -1,7 +0,7 @@ | ||
import { AccessorType, IAccessor, IObserver, ISubscriberCollection, atObserver } from '../observation'; | ||
import { AccessorType, IAccessor, ISubscriberCollection, atObserver } from '../observation'; | ||
import { safeString, def, isFunction, areEqual } from '../utilities'; | ||
import { currentConnectable } from './connectable-switcher'; | ||
import type { Constructable, IIndexable } from '@aurelia/kernel'; | ||
import type { IBindingContext, InterceptorFunc, IObservable } from '../observation'; | ||
import { emptyObject, type Constructable, type IIndexable } from '@aurelia/kernel'; | ||
import type { InterceptorFunc, IObservable } from '../observation'; | ||
import type { ObservableGetter } from './observer-locator'; | ||
@@ -18,215 +18,207 @@ import type { SetterObserver } from './setter-observer'; | ||
function getObserversLookup(obj: IObservable): IIndexable<{}, SetterObserver | SetterNotifier> { | ||
if (obj.$observers === void 0) { | ||
def(obj, '$observers', { value: {} }); | ||
// todo: define in a weakmap | ||
} | ||
return obj.$observers as IIndexable<{}, SetterObserver | SetterNotifier>; | ||
} | ||
type FieldInitializer<TFThis, TValue> = (this: TFThis, initialValue: TValue) => TValue; | ||
type ObservableFieldDecorator<TFThis, TValue> = (target: undefined, context: ClassFieldDecoratorContext<TFThis, TValue>) => FieldInitializer<TFThis, TValue>; | ||
type ObservableClassDecorator<TCThis extends Constructable> = (target: TCThis, context: ClassDecoratorContext<TCThis>) => void; | ||
const noValue: unknown = {}; | ||
export const observable = /*@__PURE__*/(() => { | ||
type SetterObserverOwningObject = IIndexable<IBindingContext, IObserver>; | ||
function getObserversLookup(obj: IObservable): IIndexable<{}, SetterObserver | SetterNotifier> { | ||
if (obj.$observers === void 0) { | ||
def(obj, '$observers', { value: {} }); | ||
// todo: define in a weakmap | ||
} | ||
return obj.$observers as IIndexable<{}, SetterObserver | SetterNotifier>; | ||
} | ||
// for | ||
// class { | ||
// @observable prop | ||
// } | ||
export function observable(target: object, key: PropertyKey, descriptor?: PropertyDescriptor & { initializer?: () => unknown }): void; | ||
// for | ||
// @observable({...}) | ||
// class {} | ||
// and | ||
// class { | ||
// @observable({...}) prop | ||
// } | ||
export function observable(config: IObservableDefinition): (target: Constructable | object, ...args: unknown[]) => void; | ||
// for | ||
// @observable('') class {} | ||
// @observable(5) class {} | ||
// @observable(Symbol()) class {} | ||
export function observable(key: PropertyKey): ClassDecorator; | ||
// for: | ||
// class { | ||
// @observable() prop | ||
// } | ||
export function observable(): PropertyDecorator; | ||
// impl, wont be seen | ||
export function observable( | ||
targetOrConfig?: Constructable | object | PropertyKey | IObservableDefinition, | ||
key?: PropertyKey, | ||
descriptor?: PropertyDescriptor | ||
): ClassDecorator | PropertyDecorator { | ||
if (!SetterNotifier.mixed) { | ||
SetterNotifier.mixed = true; | ||
subscriberCollection(SetterNotifier); | ||
} | ||
// either this check, or arguments.length === 3 | ||
// or could be both, so can throw against user error for better DX | ||
if (key == null) { | ||
// for: | ||
// @observable('prop') | ||
// class {} | ||
// | ||
// @observable({ name: 'prop', callback: ... }) | ||
// class {} | ||
// | ||
// class { | ||
// @observable() prop | ||
// @observable({ callback: ... }) prop2 | ||
// } | ||
return ((t: Constructable, k: PropertyKey, d: PropertyDescriptor) => deco(t, k, d, targetOrConfig as PropertyKey | IObservableDefinition)) as ClassDecorator; | ||
} | ||
// for: | ||
const noValue: unknown = {}; | ||
// for | ||
// class { | ||
// @observable prop | ||
// } | ||
return deco(targetOrConfig, key, descriptor) as PropertyDecorator; | ||
function deco( | ||
target: Constructable | object | PropertyKey | undefined, | ||
key?: PropertyKey, | ||
descriptor?: PropertyDescriptor & { initializer?: CallableFunction }, | ||
config?: PropertyKey | IObservableDefinition, | ||
): void | PropertyDescriptor { | ||
// class decorator? | ||
const isClassDecorator = key === void 0; | ||
config = typeof config !== 'object' | ||
? { name: config } | ||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions | ||
: (config || {}); | ||
if (isClassDecorator) { | ||
key = config.name; | ||
function observable<TFThis, TValue>(target: undefined, context: ClassFieldDecoratorContext<TFThis, TValue>): FieldInitializer<TFThis, TValue>; | ||
// for | ||
// @observable({...}) | ||
// class {} | ||
// and | ||
// class { | ||
// @observable({...}) prop | ||
// } | ||
function observable<TCThis extends Constructable, TFThis, TValue>(config: IObservableDefinition): (target: TCThis | undefined, context: ClassDecoratorContext<TCThis> | ClassFieldDecoratorContext<TFThis, TValue>) => FieldInitializer<TFThis, TValue> | void; | ||
// for | ||
// @observable('') class {} | ||
// @observable(5) class {} | ||
// @observable(Symbol()) class {} | ||
function observable<TCThis extends Constructable>(key: PropertyKey): ObservableClassDecorator<TCThis>; | ||
// for: | ||
// class { | ||
// @observable() prop | ||
// } | ||
function observable<TFThis, TValue>(): ObservableFieldDecorator<TFThis, TValue>; | ||
// impl, wont be seen | ||
function observable<TCThis extends Constructable, TFThis, TValue>(targetOrConfig?: undefined | IObservableDefinition | PropertyKey, context?: ClassFieldDecoratorContext): ObservableClassDecorator<TCThis> | ObservableFieldDecorator<TFThis, TValue> | FieldInitializer<TFThis, TValue> { | ||
if (!SetterNotifier.mixed) { | ||
SetterNotifier.mixed = true; | ||
subscriberCollection(SetterNotifier, null!); | ||
} | ||
if (key == null || key === '') { | ||
throw createMappedError(ErrorNames.invalid_observable_decorator_usage); | ||
let isClassDecorator = false; | ||
let config: IObservableDefinition; | ||
if (typeof targetOrConfig === 'object') { | ||
config = targetOrConfig; | ||
} else if (targetOrConfig != null) { | ||
config = { name: targetOrConfig }; | ||
isClassDecorator = true; | ||
} else { | ||
config = emptyObject; | ||
} | ||
// determine callback name based on config or convention. | ||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing, @typescript-eslint/strict-boolean-expressions | ||
const callback = config.callback || `${safeString(key)}Changed`; | ||
let initialValue = noValue; | ||
if (descriptor) { | ||
// we're adding a getter and setter which means the property descriptor | ||
// cannot have a "value" or "writable" attribute | ||
delete descriptor.value; | ||
delete descriptor.writable; | ||
initialValue = descriptor.initializer?.(); | ||
delete descriptor.initializer; | ||
} else { | ||
descriptor = { configurable: true }; | ||
// case: @observable() prop | ||
if (arguments.length === 0) { | ||
return function (target: unknown, context: DecoratorContext) { | ||
if (context.kind !== 'field') throw createMappedError(ErrorNames.invalid_observable_decorator_usage); | ||
return createFieldInitializer(context); | ||
}; | ||
} | ||
// make the accessor enumerable by default, as fields are enumerable | ||
if (!('enumerable' in descriptor)) { | ||
descriptor.enumerable = true; | ||
// case: @observable prop | ||
if (context?.kind === 'field') return createFieldInitializer(context); | ||
// case: @observable(PropertyKey) class | ||
if (isClassDecorator) { | ||
return function (target: TCThis, context: ClassDecoratorContext<TCThis>) { | ||
createDescriptor(target, config.name!, () => noValue, true); | ||
}; | ||
} | ||
// todo(bigopon/fred): discuss string api for converter | ||
const $set = config.set; | ||
descriptor.get = function g(/* @observable */this: SetterObserverOwningObject) { | ||
const notifier = getNotifier(this, key!, callback, initialValue, $set); | ||
currentConnectable()?.subscribeTo(notifier); | ||
return notifier.getValue(); | ||
// case: @observable({...}) class | @observable({...}) prop | ||
return function (target: Constructable | undefined, context: ClassFieldDecoratorContext | ClassDecoratorContext) { | ||
switch (context.kind) { | ||
case 'field': return createFieldInitializer(context); | ||
case 'class': return createDescriptor(target, config.name!, () => noValue, true); | ||
default: throw createMappedError(ErrorNames.invalid_observable_decorator_usage); | ||
} | ||
}; | ||
descriptor.set = function s(/* @observable */this: SetterObserverOwningObject, newValue: unknown) { | ||
getNotifier(this, key!, callback, initialValue, $set).setValue(newValue); | ||
}; | ||
(descriptor.get as ObservableGetter).getObserver = function gO(/* @observable */obj: SetterObserverOwningObject) { | ||
return getNotifier(obj, key!, callback, initialValue, $set); | ||
}; | ||
if (isClassDecorator) { | ||
def((target as Constructable).prototype as object, key, descriptor); | ||
} else { | ||
return descriptor; | ||
function createFieldInitializer(context: ClassFieldDecoratorContext): FieldInitializer<TFThis, TValue> { | ||
let $initialValue: TValue; | ||
context.addInitializer(function (this: unknown) { | ||
createDescriptor(this, context.name, () => $initialValue, false); | ||
}); | ||
return function (this: TFThis, initialValue: TValue) { | ||
return $initialValue = initialValue; | ||
}; | ||
} | ||
function createDescriptor(target: unknown, property: PropertyKey, initialValue: () => unknown, targetIsClass: boolean): void { | ||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing, @typescript-eslint/strict-boolean-expressions | ||
const callback = config.callback || `${safeString(property)}Changed`; | ||
const $set = config.set; | ||
const observableGetter: ObservableGetter = function (this: IObservable) { | ||
const notifier = getNotifier(this, property, callback, initialValue, $set); | ||
currentConnectable()?.subscribeTo(notifier); | ||
return notifier.getValue(); | ||
}; | ||
observableGetter.getObserver = function (obj: IObservable) { | ||
return getNotifier(obj, property, callback, initialValue, $set); | ||
}; | ||
const descriptor = { | ||
enumerable: true, | ||
configurable: true, | ||
get: observableGetter, | ||
set(this: IObservable, newValue: TValue) { | ||
getNotifier(this, property, callback, initialValue, $set).setValue(newValue); | ||
} | ||
}; | ||
if (targetIsClass) def((target as Constructable).prototype as object, property, descriptor); | ||
else def(target as object, property, descriptor); | ||
} | ||
} | ||
} | ||
function getNotifier( | ||
obj: SetterObserverOwningObject, | ||
key: PropertyKey, | ||
callbackKey: PropertyKey, | ||
initialValue: unknown, | ||
set: InterceptorFunc | undefined, | ||
): SetterNotifier { | ||
const lookup = getObserversLookup(obj) as unknown as Record<PropertyKey, SetterObserver | SetterNotifier>; | ||
let notifier = lookup[key as string] as SetterNotifier; | ||
if (notifier == null) { | ||
notifier = new SetterNotifier(obj, callbackKey, set, initialValue === noValue ? void 0 : initialValue); | ||
lookup[key as string] = notifier; | ||
function getNotifier( | ||
obj: IObservable, | ||
key: PropertyKey, | ||
callbackKey: PropertyKey, | ||
initialValue: () => unknown, | ||
set: InterceptorFunc | undefined, | ||
): SetterNotifier { | ||
const lookup = getObserversLookup(obj) as unknown as Record<PropertyKey, SetterObserver | SetterNotifier>; | ||
let notifier = lookup[key as string] as SetterNotifier; | ||
if (notifier == null) { | ||
const $initialValue = initialValue(); | ||
notifier = new SetterNotifier(obj, callbackKey, set, $initialValue === noValue ? void 0 : $initialValue); | ||
lookup[key as string] = notifier; | ||
} | ||
return notifier; | ||
} | ||
return notifier; | ||
} | ||
type ChangeHandlerCallback = (this: object, value: unknown, oldValue: unknown) => void; | ||
type ChangeHandlerCallback = (this: object, value: unknown, oldValue: unknown) => void; | ||
export interface SetterNotifier extends IAccessor, ISubscriberCollection {} | ||
interface SetterNotifier extends IAccessor, ISubscriberCollection { } | ||
export class SetterNotifier implements IAccessor { | ||
public static mixed = false; | ||
public readonly type: AccessorType = atObserver; | ||
class SetterNotifier implements IAccessor { | ||
public static mixed = false; | ||
public readonly type: AccessorType = atObserver; | ||
/** @internal */ | ||
private _value: unknown = void 0; | ||
/** @internal */ | ||
private _oldValue: unknown = void 0; | ||
/** @internal */ | ||
private readonly cb?: ChangeHandlerCallback; | ||
/** @internal */ | ||
private readonly _obj: object; | ||
/** @internal */ | ||
private readonly _setter: InterceptorFunc | undefined; | ||
/** @internal */ | ||
private readonly _hasSetter: boolean; | ||
/** @internal */ | ||
private _value: unknown = void 0; | ||
/** @internal */ | ||
private _oldValue: unknown = void 0; | ||
/** @internal */ | ||
private readonly cb?: ChangeHandlerCallback; | ||
/** @internal */ | ||
private readonly _obj: object; | ||
/** @internal */ | ||
private readonly _setter: InterceptorFunc | undefined; | ||
/** @internal */ | ||
private readonly _hasSetter: boolean; | ||
public constructor( | ||
obj: object, | ||
callbackKey: PropertyKey, | ||
set: InterceptorFunc | undefined, | ||
initialValue: unknown, | ||
) { | ||
this._obj = obj; | ||
this._setter = set; | ||
this._hasSetter = isFunction(set); | ||
const callback = (obj as IIndexable)[callbackKey as string]; | ||
this.cb = isFunction(callback) ? callback as ChangeHandlerCallback : void 0; | ||
this._value = initialValue; | ||
} | ||
public constructor( | ||
obj: object, | ||
callbackKey: PropertyKey, | ||
set: InterceptorFunc | undefined, | ||
initialValue: unknown, | ||
) { | ||
this._obj = obj; | ||
this._setter = set; | ||
this._hasSetter = isFunction(set); | ||
const callback = (obj as IIndexable)[callbackKey as string]; | ||
this.cb = isFunction(callback) ? callback as ChangeHandlerCallback : void 0; | ||
this._value = initialValue; | ||
} | ||
public getValue(): unknown { | ||
return this._value; | ||
} | ||
public getValue(): unknown { | ||
return this._value; | ||
} | ||
public setValue(value: unknown): void { | ||
if (this._hasSetter) { | ||
value = this._setter!(value); | ||
public setValue(value: unknown): void { | ||
if (this._hasSetter) { | ||
value = this._setter!(value); | ||
} | ||
if (!areEqual(value, this._value)) { | ||
this._oldValue = this._value; | ||
this._value = value; | ||
this.cb?.call(this._obj, this._value, this._oldValue); | ||
// this._value might have been updated during the callback | ||
// we only want to notify subscribers with the latest values | ||
value = this._oldValue; | ||
this._oldValue = this._value; | ||
this.subs.notify(this._value, value); | ||
} | ||
} | ||
if (!areEqual(value, this._value)) { | ||
this._oldValue = this._value; | ||
this._value = value; | ||
this.cb?.call(this._obj, this._value, this._oldValue); | ||
// this._value might have been updated during the callback | ||
// we only want to notify subscribers with the latest values | ||
value = this._oldValue; | ||
this._oldValue = this._value; | ||
this.subs.notify(this._value, value); | ||
} | ||
} | ||
} | ||
/* | ||
| typescript | babel | ||
----------|------------------|------------------------- | ||
property | config | config | ||
w/parens | target, key | target, key, descriptor | ||
----------|------------------|------------------------- | ||
property | target, key | target, key, descriptor | ||
no parens | n/a | n/a | ||
----------|------------------|------------------------- | ||
class | config | config | ||
| target | target | ||
*/ | ||
/* | ||
| typescript | babel | ||
----------|------------------|------------------------- | ||
property | config | config | ||
w/parens | target, key | target, key, descriptor | ||
----------|------------------|------------------------- | ||
property | target, key | target, key, descriptor | ||
no parens | n/a | n/a | ||
----------|------------------|------------------------- | ||
class | config | config | ||
| target | target | ||
*/ | ||
return observable; | ||
})(); |
@@ -58,12 +58,30 @@ import { Primitive, isArrayIndex, ILogger, resolve } from '@aurelia/kernel'; | ||
export interface IComputedObserverLocator { | ||
getObserver(obj: object, key: PropertyKey, pd: ExtendedPropertyDescriptor, requestor: IObserverLocator): IObserver; | ||
} | ||
export const IComputedObserverLocator = /*@__PURE__*/createInterface<IComputedObserverLocator>( | ||
'IComputedObserverLocator', | ||
x => x.singleton(class DefaultLocator implements IComputedObserverLocator { | ||
public getObserver(obj: object, key: PropertyKey, pd: ExtendedPropertyDescriptor, requestor: IObserverLocator): IObserver { | ||
const observer = new ComputedObserver(obj, pd.get!, pd.set, requestor, true); | ||
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; | ||
} | ||
}) | ||
); | ||
export type ExtendedPropertyDescriptor = PropertyDescriptor & { | ||
get?: ObservableGetter; | ||
set?: ObservableSetter; | ||
}; | ||
export type ObservableGetter = PropertyDescriptor['get'] & { | ||
getObserver?(obj: unknown, requestor: IObserverLocator): IObserver; | ||
getObserver?(obj: unknown): IObserver; | ||
}; | ||
export type ObservableSetter = PropertyDescriptor['set'] & { | ||
getObserver?(obj: unknown, requestor: IObserverLocator): IObserver; | ||
}; | ||
@@ -74,2 +92,3 @@ export class ObserverLocator { | ||
/** @internal */ private readonly _nodeObserverLocator = resolve(INodeObserverLocator); | ||
/** @internal */ private readonly _computedObserverLocator = resolve(IComputedObserverLocator); | ||
@@ -170,3 +189,3 @@ public addAdapter(adapter: IObjectObservationAdapter): void { | ||
if (obs == null) { | ||
obs = (pd.get?.getObserver ?? pd.set?.getObserver)?.(obj, this); | ||
obs = (pd.get?.getObserver)?.(obj); | ||
} | ||
@@ -177,3 +196,4 @@ | ||
? pd.configurable | ||
? this._createComputedObserver(obj, key, pd, true) | ||
// ? this._createComputedObserver(obj, key, pd, true) | ||
? this._computedObserverLocator.getObserver(obj, key, pd, this) | ||
: this._dirtyChecker.createProperty(obj, key) | ||
@@ -188,16 +208,16 @@ : 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); | ||
}, | ||
}); | ||
// /** @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; | ||
} | ||
// return observer; | ||
// } | ||
@@ -204,0 +224,0 @@ /** @internal */ |
@@ -1,5 +0,6 @@ | ||
import { Constructable } from '@aurelia/kernel'; | ||
import { Class, Constructable } from '@aurelia/kernel'; | ||
import { defineHiddenProp, safeString } from '../utilities'; | ||
import { nowrapClassKey, nowrapPropKey } from './proxy-observation'; | ||
export function nowrap(): (target: unknown, context: ClassDecoratorContext | ClassFieldDecoratorContext) => void; | ||
/** | ||
@@ -11,4 +12,3 @@ * A decorator to signal proxy observation shouldn't make an effort to wrap an object | ||
// class {} | ||
export function nowrap(target: Constructable): void; | ||
export function nowrap(target: Constructable, context: ClassDecoratorContext): void; | ||
// for | ||
@@ -18,55 +18,31 @@ // class { | ||
// } | ||
export function nowrap(target: object, key: PropertyKey, descriptor?: PropertyDescriptor): void; | ||
// for | ||
// @nowrap() | ||
// class {} | ||
// or | ||
// class { @nowrap() prop } | ||
// returning any just for TS, as it is unable to selectively choose whether it's a class decorator or prop decorator | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-redundant-type-constituents | ||
export function nowrap(): ClassDecorator | PropertyDecorator | any; // (target: Constructable | object, key: PropertyKey, descriptor?: PropertyDescriptor) => void; | ||
// base signature | ||
export function nowrap( | ||
target?: Constructable | object, | ||
key?: PropertyKey, | ||
descriptor?: PropertyDescriptor | ||
): ClassDecorator | PropertyDecorator; | ||
export function nowrap(target: undefined, context: ClassFieldDecoratorContext): void; | ||
/** | ||
* A decorator to signal proxy observation shouldn't make an effort to wrap an object | ||
*/ | ||
export function nowrap( | ||
target?: Constructable | object, | ||
key?: PropertyKey | ||
): void | ClassDecorator | PropertyDecorator { | ||
if (target == null) { | ||
// for | ||
// @nowrap() | ||
// class {} | ||
// or | ||
// class { @nowrap() prop } | ||
return (t: Constructable | object, k?: PropertyKey) => deco(t, k); | ||
} else { | ||
// for | ||
// @nowrap | ||
// class {} | ||
// or | ||
// class { | ||
// @nowrap prop | ||
// } | ||
return deco(target, key); | ||
} | ||
export function nowrap< | ||
TThis extends object | ||
>( | ||
target?: Class<TThis> | undefined, | ||
context?: ClassDecoratorContext<Class<TThis>> | ClassFieldDecoratorContext<TThis> | ||
): void | ||
| ((target: unknown, context: ClassDecoratorContext | ClassFieldDecoratorContext) => void) { | ||
return arguments.length === 0 ? decorator : decorator(target!, context!); | ||
function deco( | ||
target: Constructable | object, | ||
key?: PropertyKey | ||
): void | ClassDecorator | PropertyDecorator { | ||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions | ||
const isClassDecorator = !key; | ||
if (isClassDecorator) { | ||
defineHiddenProp(target, nowrapClassKey, true); | ||
} else { | ||
// defining on the constructor means inheritance lookup is supported | ||
defineHiddenProp((target as object).constructor, `${nowrapPropKey}_${safeString(key)}__`, true); | ||
function decorator( | ||
target: unknown, | ||
context: ClassDecoratorContext<Class<TThis>> | ClassFieldDecoratorContext<TThis> | ||
): void { | ||
switch (context.kind) { | ||
case 'class': | ||
defineHiddenProp(target as Class<TThis>, nowrapClassKey, true); | ||
break; | ||
case 'field': | ||
context.addInitializer(function (this: object) { | ||
const target = this.constructor; | ||
const property = `${nowrapPropKey}_${safeString(context.name)}__`; | ||
if (property in target) return; | ||
defineHiddenProp(target, property, true); | ||
}); | ||
break; | ||
} | ||
@@ -84,11 +60,8 @@ } | ||
class MyModel2 {} | ||
class MyModel3 { | ||
@nowrap public prop = 1; | ||
@nowrap() public prop1 = 1; | ||
} | ||
class MyModel4 { | ||
@nowrap() public prop = 2; | ||
} | ||
} | ||
/* eslint-enable */ |
import { createIndexMap, type AccessorType, type ICollectionSubscriberCollection, type ICollectionObserver, atObserver } from '../observation'; | ||
import { CollectionSizeObserver } from './collection-length-observer'; | ||
import { subscriberCollection } from './subscriber-collection'; | ||
import { def, defineHiddenProp, defineMetadata, getOwnMetadata } from '../utilities'; | ||
import { def, defineHiddenProp, defineMetadata, getMetadata } from '../utilities'; | ||
import { batching, addCollectionBatch } from './subscriber-batch'; | ||
@@ -115,4 +115,4 @@ import { IIndexable } from '@aurelia/kernel'; | ||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions | ||
if (!(getOwnMetadata(observationEnabledKey, Set) ?? false)) { | ||
defineMetadata(observationEnabledKey, true, Set); | ||
if (!(getMetadata(observationEnabledKey, Set) ?? false)) { | ||
defineMetadata(true, Set, observationEnabledKey); | ||
for (const method of methods) { | ||
@@ -137,2 +137,6 @@ if (proto[method].observing !== true) { | ||
export class SetObserver { | ||
static { | ||
subscriberCollection(SetObserver, null!); | ||
} | ||
public type: AccessorType = atObserver; | ||
@@ -175,4 +179,2 @@ private lenObs?: CollectionSizeObserver; | ||
subscriberCollection(SetObserver); | ||
export function getSetObserver(observedSet: Set<unknown>): SetObserver { | ||
@@ -179,0 +181,0 @@ let observer = observerLookup.get(observedSet); |
@@ -19,2 +19,6 @@ import { ICoercionConfiguration, IObserver, InterceptorFunc, atObserver } from '../observation'; | ||
export class SetterObserver implements IObserver, ISubscriberCollection { | ||
static { | ||
subscriberCollection(SetterObserver, null!); | ||
} | ||
// todo(bigopon): tweak the flag based on typeof obj (array/set/map/iterator/proxy etc...) | ||
@@ -130,6 +134,4 @@ public type: AccessorType = atObserver; | ||
subscriberCollection(SetterObserver); | ||
// 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; |
@@ -12,94 +12,99 @@ import { def, defineHiddenProp, ensureProto } from '../utilities'; | ||
import { addValueBatch, batching } from './subscriber-batch'; | ||
import { Class, Constructable } from '@aurelia/kernel'; | ||
export type IAnySubscriber = ISubscriber | ICollectionSubscriber; | ||
/* eslint-disable @typescript-eslint/ban-types */ | ||
export function subscriberCollection(): ClassDecorator; | ||
export function subscriberCollection(target: Function): void; | ||
export function subscriberCollection(target?: Function): ClassDecorator | void { | ||
return target == null ? subscriberCollectionDeco : subscriberCollectionDeco(target); | ||
} | ||
export const subscriberCollection = /*@__PURE__*/(() => { | ||
const decoratedTarget = new WeakSet<Function>(); | ||
function subscriberCollectionDeco(target: Function): void { // ClassDecorator expects it to be derived from Function | ||
if (decoratedTarget.has(target)) { | ||
return; | ||
function subscriberCollection(): <T extends Constructable>(value: T, context: ClassDecoratorContext) => T; | ||
function subscriberCollection<T extends Constructable>(target: T, context: ClassDecoratorContext): T; | ||
function subscriberCollection<T extends Constructable>(target?: T, context?: ClassDecoratorContext<T>): ((value: T, context: ClassDecoratorContext) => T) | T { | ||
return target == null ? subscriberCollectionDeco : subscriberCollectionDeco(target, context!); | ||
} | ||
decoratedTarget.add(target); | ||
const proto = target.prototype as ISubscriberCollection; | ||
// not configurable, as in devtool, the getter could be invoked on the prototype, | ||
// and become permanently broken | ||
def(proto, 'subs', { get: getSubscriberRecord }); | ||
ensureProto(proto, 'subscribe', addSubscriber); | ||
ensureProto(proto, 'unsubscribe', removeSubscriber); | ||
} | ||
/* eslint-enable @typescript-eslint/ban-types */ | ||
function getSubscriberRecord(this: ISubscriberCollection) { | ||
return defineHiddenProp(this, 'subs', new SubscriberRecord()); | ||
} | ||
export class SubscriberRecord<T extends IAnySubscriber> implements ISubscriberRecord<T> { | ||
public count: number = 0; | ||
/** @internal */ | ||
private readonly _subs: T[] = []; | ||
function addSubscriber(this: ISubscriberCollection, subscriber: IAnySubscriber): boolean { | ||
return this.subs.add(subscriber as ISubscriber & ICollectionSubscriber); | ||
} | ||
public add(subscriber: T): boolean { | ||
if (this._subs.includes(subscriber)) { | ||
return false; | ||
function removeSubscriber(this: ISubscriberCollection, subscriber: IAnySubscriber): boolean { | ||
return this.subs.remove(subscriber as ISubscriber & ICollectionSubscriber); | ||
} | ||
const decoratedTarget = new WeakSet<Constructable>(); | ||
function subscriberCollectionDeco<TObj extends object, T extends Class<TObj>>(target: T, context: ClassDecoratorContext): T { // ClassDecorator expects it to be derived from Function | ||
if (!decoratedTarget.has(target)) { | ||
decoratedTarget.add(target); | ||
const proto = target.prototype as ISubscriberCollection; | ||
// not configurable, as in devtool, the getter could be invoked on the prototype, | ||
// and become permanently broken | ||
def(proto, 'subs', { get: getSubscriberRecord }); | ||
ensureProto(proto, 'subscribe', addSubscriber); | ||
ensureProto(proto, 'unsubscribe', removeSubscriber); | ||
} | ||
this._subs[this._subs.length] = subscriber; | ||
++this.count; | ||
return true; | ||
return target; | ||
} | ||
public remove(subscriber: T): boolean { | ||
const idx = this._subs.indexOf(subscriber); | ||
if (idx !== -1) { | ||
this._subs.splice(idx, 1); | ||
--this.count; | ||
class SubscriberRecord<T extends IAnySubscriber> implements ISubscriberRecord<T> { | ||
public count: number = 0; | ||
/** @internal */ | ||
private readonly _subs: T[] = []; | ||
public add(subscriber: T): boolean { | ||
if (this._subs.includes(subscriber)) { | ||
return false; | ||
} | ||
this._subs[this._subs.length] = subscriber; | ||
++this.count; | ||
return true; | ||
} | ||
return false; | ||
} | ||
public notify(val: unknown, oldVal: unknown): void { | ||
if (batching) { | ||
addValueBatch(this, val, oldVal); | ||
public remove(subscriber: T): boolean { | ||
const idx = this._subs.indexOf(subscriber); | ||
if (idx !== -1) { | ||
this._subs.splice(idx, 1); | ||
--this.count; | ||
return true; | ||
} | ||
return false; | ||
} | ||
public notify(val: unknown, oldVal: unknown): void { | ||
if (batching) { | ||
addValueBatch(this, val, oldVal); | ||
return; | ||
} | ||
/** | ||
* Note: change handlers may have the side-effect of adding/removing subscribers to this collection during this | ||
* callSubscribers invocation, so we're caching them all before invoking any. | ||
* Subscribers added during this invocation are not invoked (and they shouldn't be). | ||
* Subscribers removed during this invocation will still be invoked (and they also shouldn't be, | ||
* however this is accounted for via $isBound and similar flags on the subscriber objects) | ||
*/ | ||
const _subs = this._subs.slice(0) as ISubscriber[]; | ||
const len = _subs.length; | ||
let i = 0; | ||
for (; i < len; ++i) { | ||
_subs[i].handleChange(val, oldVal); | ||
} | ||
return; | ||
} | ||
/** | ||
* Note: change handlers may have the side-effect of adding/removing subscribers to this collection during this | ||
* callSubscribers invocation, so we're caching them all before invoking any. | ||
* Subscribers added during this invocation are not invoked (and they shouldn't be). | ||
* Subscribers removed during this invocation will still be invoked (and they also shouldn't be, | ||
* however this is accounted for via $isBound and similar flags on the subscriber objects) | ||
*/ | ||
const _subs = this._subs.slice(0) as ISubscriber[]; | ||
const len = _subs.length; | ||
let i = 0; | ||
for (; i < len; ++i) { | ||
_subs[i].handleChange(val, oldVal); | ||
} | ||
return; | ||
} | ||
public notifyCollection(collection: Collection, indexMap: IndexMap): void { | ||
const _subs = this._subs.slice(0) as ICollectionSubscriber[]; | ||
const len = _subs.length; | ||
let i = 0; | ||
for (; i < len; ++i) { | ||
_subs[i].handleCollectionChange(collection, indexMap); | ||
public notifyCollection(collection: Collection, indexMap: IndexMap): void { | ||
const _subs = this._subs.slice(0) as ICollectionSubscriber[]; | ||
const len = _subs.length; | ||
let i = 0; | ||
for (; i < len; ++i) { | ||
_subs[i].handleCollectionChange(collection, indexMap); | ||
} | ||
return; | ||
} | ||
return; | ||
} | ||
} | ||
function getSubscriberRecord(this: ISubscriberCollection) { | ||
return defineHiddenProp(this, 'subs', new SubscriberRecord()); | ||
} | ||
function addSubscriber(this: ISubscriberCollection, subscriber: IAnySubscriber): boolean { | ||
return this.subs.add(subscriber as ISubscriber & ICollectionSubscriber); | ||
} | ||
function removeSubscriber(this: ISubscriberCollection, subscriber: IAnySubscriber): boolean { | ||
return this.subs.remove(subscriber as ISubscriber & ICollectionSubscriber); | ||
} | ||
return subscriberCollection; | ||
})(); |
@@ -76,4 +76,3 @@ import { Metadata } from '@aurelia/metadata'; | ||
/** @internal */ export const getOwnMetadata = Metadata.getOwn; | ||
/** @internal */ export const hasOwnMetadata = Metadata.hasOwn; | ||
/** @internal */ export const getMetadata = Metadata.get; | ||
/** @internal */ export const defineMetadata = Metadata.define; |
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
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
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1140141
4
89
19956
+ Added@aurelia/expression-parser@2.1.0-dev.202405060015(transitive)
+ Added@aurelia/kernel@2.1.0-dev.202405060015(transitive)
+ Added@aurelia/metadata@2.1.0-dev.202405060015(transitive)
+ Added@aurelia/platform@2.1.0-dev.202405060015(transitive)
- Removed@aurelia/kernel@2.1.0-dev.202404150648(transitive)
- Removed@aurelia/metadata@2.1.0-dev.202404150648(transitive)
- Removed@aurelia/platform@2.1.0-dev.202404150648(transitive)