Skip to content

Commit aa36c43

Browse files
committed
internal improvements
1 parent 3411d1b commit aa36c43

File tree

12 files changed

+120
-155
lines changed

12 files changed

+120
-155
lines changed

packages/core/src/fields/inputFields/AbstractInputField.ts

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { InputFieldSvelteWrapper } from 'packages/core/src/fields/inputFields/In
55
import type { IPlugin } from 'packages/core/src/IPlugin';
66
import type { MetadataSubscription } from 'packages/core/src/metadata/MetadataSubscription';
77
import { Mountable } from 'packages/core/src/utils/Mountable';
8-
import { ComputedSignal, Signal } from 'packages/core/src/utils/Signal';
8+
import { MappedSignal } from 'packages/core/src/utils/Signal';
99

1010
export abstract class AbstractInputField<
1111
MetadataValueType,
@@ -15,8 +15,7 @@ export abstract class AbstractInputField<
1515
readonly plugin: IPlugin;
1616
readonly mountable: InputFieldMountable;
1717
readonly svelteWrapper: InputFieldSvelteWrapper<ComponentValueType, SvelteExports>;
18-
readonly inputSignal: Signal<unknown>;
19-
readonly computedSignal: ComputedSignal<unknown, MetadataValueType>;
18+
readonly inputSignal: MappedSignal<unknown, MetadataValueType>;
2019

2120
private metadataSubscription?: MetadataSubscription;
2221

@@ -25,14 +24,13 @@ export abstract class AbstractInputField<
2524

2625
this.mountable = mountable;
2726
this.plugin = mountable.plugin;
28-
this.inputSignal = new Signal<unknown>(undefined);
2927
this.svelteWrapper = new InputFieldSvelteWrapper<ComponentValueType, SvelteExports>(
3028
this.plugin,
3129
this.getSvelteComponent(),
3230
);
3331

34-
this.computedSignal = new ComputedSignal<unknown, MetadataValueType>(
35-
this.inputSignal,
32+
this.inputSignal = new MappedSignal<unknown, MetadataValueType>(
33+
undefined,
3634
(value: unknown): MetadataValueType => {
3735
const filteredValue = this.filterValue(value);
3836
if (filteredValue !== undefined) {
@@ -44,14 +42,6 @@ export abstract class AbstractInputField<
4442
);
4543
}
4644

47-
// TODO: What is this?
48-
public destroy(): void {
49-
// we don't need to unregister the listener because the component will destroy all listeners on unmount
50-
if (this.svelteWrapper.isMounted()) {
51-
this.unmount();
52-
}
53-
}
54-
5545
protected abstract getSvelteComponent(): InputFieldSvelteComponent<ComponentValueType, SvelteExports>;
5646

5747
/**
@@ -92,7 +82,7 @@ export abstract class AbstractInputField<
9282
* Get the metadata value that the input field currently has.
9383
*/
9484
public getValue(): MetadataValueType {
95-
return this.computedSignal.get();
85+
return this.inputSignal.get();
9686
}
9787

9888
/**
@@ -108,7 +98,7 @@ export abstract class AbstractInputField<
10898
* @param value
10999
*/
110100
public setValue(value: MetadataValueType): void {
111-
this.computedSignal.set(value);
101+
this.inputSignal.setDirect(value);
112102
this.notifySubscription(value);
113103
}
114104

@@ -143,22 +133,19 @@ export abstract class AbstractInputField<
143133
}
144134

145135
protected onMount(targetEl: HTMLElement): void {
146-
// fix for computed signal possibly not having the correct value, as the class might not have been fully initialized
147-
this.inputSignal.set(this.inputSignal.get());
148-
149-
this.computedSignal.registerListener({
136+
this.inputSignal.registerListener({
150137
callback: value => this.svelteWrapper.setValue(this.reverseMapValue(value)),
151138
});
152139

140+
this.svelteWrapper.registerListener({
141+
callback: value => {
142+
this.notifySubscription(this.mapValue(value));
143+
},
144+
});
145+
153146
const bindTarget = this.mountable.getBindTarget();
154147

155148
if (bindTarget) {
156-
this.svelteWrapper.registerListener({
157-
callback: value => {
158-
this.notifySubscription(this.mapValue(value));
159-
},
160-
});
161-
162149
this.metadataSubscription = this.mountable.plugin.metadataManager.subscribe(
163150
this.mountable.getUuid(),
164151
this.inputSignal,
@@ -171,7 +158,7 @@ export abstract class AbstractInputField<
171158
}
172159

173160
protected onUnmount(): void {
174-
this.computedSignal.unregisterAllListeners();
161+
this.inputSignal.unregisterAllListeners();
175162
this.metadataSubscription?.unsubscribe();
176163

177164
this.svelteWrapper.unmount();

packages/core/src/fields/inputFields/InputFieldMountable.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ export class InputFieldMountable extends FieldMountable {
172172
MB_DEBUG && console.debug('meta-bind | InputFieldMountable >> unmount', this.declaration);
173173
super.onUnmount(targetEl);
174174

175-
this.inputField?.destroy();
175+
this.inputField?.unmount();
176176

177177
showUnloadedMessage(targetEl, 'input field');
178178
}

packages/core/src/metadata/ComputedMetadataSubscription.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { MetadataManager } from 'packages/core/src/metadata/MetadataManager
33
import type { MetadataSubscription } from 'packages/core/src/metadata/MetadataSubscription';
44
import type { BindTargetDeclaration } from 'packages/core/src/parsers/bindTargetParser/BindTargetDeclaration';
55
import { ErrorLevel, MetaBindInternalError } from 'packages/core/src/utils/errors/MetaBindErrors';
6-
import type { Signal } from 'packages/core/src/utils/Signal';
6+
import type { Signal, Writable } from 'packages/core/src/utils/Signal';
77
import { getUUID } from 'packages/core/src/utils/Utils';
88

99
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
@@ -16,7 +16,7 @@ export interface ComputedSubscriptionDependency {
1616

1717
export class ComputedMetadataSubscription implements IMetadataSubscription {
1818
readonly uuid: string;
19-
readonly callbackSignal: Signal<unknown>;
19+
readonly callbackSignal: Writable<unknown>;
2020

2121
readonly metadataManager: MetadataManager;
2222

@@ -32,7 +32,7 @@ export class ComputedMetadataSubscription implements IMetadataSubscription {
3232

3333
constructor(
3434
uuid: string,
35-
callbackSignal: Signal<unknown>,
35+
callbackSignal: Writable<unknown>,
3636
metadataManager: MetadataManager,
3737
bindTarget: BindTargetDeclaration | undefined,
3838
dependencies: ComputedSubscriptionDependency[],
@@ -74,7 +74,7 @@ export class ComputedMetadataSubscription implements IMetadataSubscription {
7474

7575
private async computeValue(): Promise<void> {
7676
try {
77-
const values = this.dependencySubscriptions.map(x => x.callbackSignal.get());
77+
const values = this.dependencies.map(x => x.callbackSignal.get());
7878
const value = await this.computeFunction(values);
7979
this.callbackSignal.set(value);
8080
if (this.bindTarget !== undefined) {

packages/core/src/metadata/InternalMetadataSources.ts

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import type { BindTargetScope } from 'packages/core/src/metadata/BindTargetScope';
21
import type { IMetadataSubscription } from 'packages/core/src/metadata/IMetadataSubscription';
32
import type {
43
FilePathMetadataCacheItem,
@@ -49,10 +48,6 @@ export class GlobalMetadataSource implements IMetadataSource<GlobalMetadataCache
4948
};
5049
}
5150

52-
public createCacheItem(_storagePath: string): GlobalMetadataCacheItem {
53-
return this.cache;
54-
}
55-
5651
public getOrCreateCacheItem(_storagePath: string): GlobalMetadataCacheItem {
5752
return this.cache;
5853
}
@@ -75,14 +70,6 @@ export class GlobalMetadataSource implements IMetadataSource<GlobalMetadataCache
7570
return '';
7671
}
7772

78-
public resolveBindTargetScope(
79-
bindTargetDeclaration: BindTargetDeclaration,
80-
_scope: BindTargetScope | undefined,
81-
_parser: BindTargetParser,
82-
): BindTargetDeclaration {
83-
return bindTargetDeclaration;
84-
}
85-
8673
public deleteCache(_cacheItem: GlobalMetadataCacheItem): void {
8774
// noop
8875
}
@@ -99,8 +86,8 @@ export class GlobalMetadataSource implements IMetadataSource<GlobalMetadataCache
9986
// noop
10087
}
10188

102-
public readCache(_bindTarget: BindTargetDeclaration): unknown {
103-
return this.readCacheItem(this.cache, _bindTarget.storageProp);
89+
public readCache(bindTarget: BindTargetDeclaration): unknown {
90+
return this.readCacheItem(this.cache, bindTarget.storageProp);
10491
}
10592

10693
public readCacheItem(cacheItem: GlobalMetadataCacheItem, propPath: PropPath): unknown {
@@ -113,6 +100,7 @@ export class GlobalMetadataSource implements IMetadataSource<GlobalMetadataCache
113100

114101
public subscribe(subscription: IMetadataSubscription): GlobalMetadataCacheItem {
115102
this.cache.subscriptions.push(subscription);
103+
116104
return this.cache;
117105
}
118106

@@ -150,14 +138,6 @@ export class ScopeMetadataSource implements IMetadataSource<IMetadataCacheItem>
150138
this.manager = manager;
151139
}
152140

153-
public createCacheItem(_storagePath: string): IMetadataCacheItem {
154-
throw new MetaBindInternalError({
155-
errorLevel: ErrorLevel.CRITICAL,
156-
effect: 'action not permitted',
157-
cause: `source 'scope' should have no cache items or subscriptions`,
158-
});
159-
}
160-
161141
public getOrCreateCacheItem(_storagePath: string): IMetadataCacheItem {
162142
throw new MetaBindInternalError({
163143
errorLevel: ErrorLevel.CRITICAL,
@@ -184,14 +164,6 @@ export class ScopeMetadataSource implements IMetadataSource<IMetadataCacheItem>
184164
return '';
185165
}
186166

187-
public resolveBindTargetScope(
188-
bindTargetDeclaration: BindTargetDeclaration,
189-
scope: BindTargetScope | undefined,
190-
parser: BindTargetParser,
191-
): BindTargetDeclaration {
192-
return parser.resolveScope(bindTargetDeclaration, scope);
193-
}
194-
195167
public deleteCache(_cacheItem: IMetadataCacheItem): void {
196168
// noop
197169
}

packages/core/src/metadata/MetadataCacheItem.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,15 @@ export interface IMetadataCacheItem {
77
/**
88
* The cycles since the last change to the cache by the plugin.
99
*/
10-
cyclesSinceInternalChange: number;
10+
externalWriteLock: number;
1111
/**
1212
* Whether the cache was changed by the plugin. If this is true, the frontmatter should be updated.
1313
*/
14-
pendingInternalChange: boolean;
14+
dirty: boolean;
1515
/**
1616
* The cycles that the cache has been inactive, meaning no listener registered to it.
1717
*/
18-
cyclesSinceInactive: number;
19-
/**
20-
* Whether the there are no subscribers to the cache.
21-
*/
22-
inactive: boolean;
18+
cyclesWithoutListeners: number;
2319
}
2420

2521
export interface FilePathMetadataCacheItem extends IMetadataCacheItem {

packages/core/src/metadata/MetadataManager.ts

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ import {
1515
} from 'packages/core/src/utils/errors/MetaBindErrors';
1616
import type { PropPath } from 'packages/core/src/utils/prop/PropPath';
1717
import { PropUtils } from 'packages/core/src/utils/prop/PropUtils';
18-
import type { Signal } from 'packages/core/src/utils/Signal';
18+
import type { Writable } from 'packages/core/src/utils/Signal';
1919

20-
export const METADATA_CACHE_UPDATE_CYCLE_THRESHOLD = 5; // {syncInterval (200)} * 5 = 1s
20+
export const METADATA_CACHE_EXTERNAL_WRITE_LOCK_DURATION = 5; // {syncInterval (200)} * 5 = 1s
2121
export const METADATA_CACHE_INACTIVE_CYCLE_THRESHOLD = 5 * 60; // {syncInterval (200)} * 5 * 60 = 1 minute
2222

2323
export type MetadataSource = IMetadataSource<IMetadataCacheItem>;
@@ -124,7 +124,7 @@ export class MetadataManager {
124124

125125
public subscribe(
126126
uuid: string,
127-
callbackSignal: Signal<unknown>,
127+
callbackSignal: Writable<unknown>,
128128
bindTarget: BindTargetDeclaration,
129129
onDelete: () => void,
130130
): MetadataSubscription {
@@ -153,7 +153,7 @@ export class MetadataManager {
153153
*/
154154
public subscribeComputed(
155155
uuid: string,
156-
callbackSignal: Signal<unknown>,
156+
callbackSignal: Writable<unknown>,
157157
bindTarget: BindTargetDeclaration | undefined,
158158
dependencies: ComputedSubscriptionDependency[],
159159
computeFunction: ComputeFunction,
@@ -194,7 +194,7 @@ export class MetadataManager {
194194

195195
const cacheItem = source.unsubscribe(subscription);
196196
if (cacheItem.subscriptions.length === 0) {
197-
cacheItem.inactive = true;
197+
cacheItem.cyclesWithoutListeners = 0;
198198
}
199199
}
200200

@@ -213,8 +213,7 @@ export class MetadataManager {
213213
}
214214

215215
const cacheItem = source.subscribe(subscription);
216-
cacheItem.inactive = false;
217-
cacheItem.cyclesSinceInactive = 0;
216+
cacheItem.cyclesWithoutListeners = 0;
218217

219218
subscription.notify(source.readCacheItem(cacheItem, subscription.bindTarget.storageProp));
220219
}
@@ -326,21 +325,27 @@ export class MetadataManager {
326325
for (const cacheItem of source.iterateCacheItems()) {
327326
source.onCycle(cacheItem);
328327

329-
if (cacheItem.pendingInternalChange) {
328+
// if the cache is dirty, sync the changes to the external source
329+
if (cacheItem.dirty) {
330330
try {
331331
source.syncExternal(cacheItem);
332332
} catch (e) {
333-
console.warn('failed to update frontmatter', e);
333+
console.warn(`failed to sync changes to external source for ${source.id}`, e);
334334
}
335-
cacheItem.pendingInternalChange = false;
335+
cacheItem.dirty = false;
336+
}
337+
// decrease the external write lock duration
338+
if (cacheItem.externalWriteLock > 0) {
339+
cacheItem.externalWriteLock -= 1;
336340
}
337-
cacheItem.cyclesSinceInternalChange += 1;
338341

339-
if (cacheItem.inactive) {
340-
cacheItem.cyclesSinceInactive += 1;
342+
// if there are no listeners, increase the cycles without listeners
343+
if (cacheItem.subscriptions.length > 0) {
344+
cacheItem.cyclesWithoutListeners += 1;
341345
}
346+
// if the cache is inactive, check if it should be deleted
342347
if (
343-
cacheItem.cyclesSinceInactive > METADATA_CACHE_INACTIVE_CYCLE_THRESHOLD &&
348+
cacheItem.cyclesWithoutListeners > METADATA_CACHE_INACTIVE_CYCLE_THRESHOLD &&
344349
source.shouldDelete(cacheItem)
345350
) {
346351
markedForDelete.push(cacheItem);
@@ -372,8 +377,8 @@ export class MetadataManager {
372377
}
373378

374379
const cacheItem = source.writeCache(value, bindTarget);
375-
cacheItem.pendingInternalChange = true;
376-
cacheItem.cyclesSinceInternalChange = 0;
380+
cacheItem.dirty = true;
381+
cacheItem.externalWriteLock = METADATA_CACHE_EXTERNAL_WRITE_LOCK_DURATION;
377382
this.notifyListeners(bindTarget, updateSourceUuid);
378383
}
379384

@@ -402,7 +407,7 @@ export class MetadataManager {
402407
* @param cacheItem
403408
*/
404409
public isCacheExternalWriteLocked(cacheItem: IMetadataCacheItem): boolean {
405-
return cacheItem.cyclesSinceInternalChange < METADATA_CACHE_UPDATE_CYCLE_THRESHOLD;
410+
return cacheItem.externalWriteLock > 0;
406411
}
407412

408413
/**
@@ -485,10 +490,9 @@ export class MetadataManager {
485490
public getDefaultCacheItem(): IMetadataCacheItem {
486491
return {
487492
subscriptions: [],
488-
cyclesSinceInternalChange: METADATA_CACHE_UPDATE_CYCLE_THRESHOLD + 1,
489-
pendingInternalChange: false,
490-
cyclesSinceInactive: 0,
491-
inactive: true,
493+
externalWriteLock: 0,
494+
dirty: false,
495+
cyclesWithoutListeners: 0,
492496
};
493497
}
494498

0 commit comments

Comments
 (0)