Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

glimmer validator compat #95

Merged
merged 2 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/utils/glimmer-compat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * as caching from './caching-primitives';
export * as destroyable from './destroyable';
export * as storage from './storage-primitives';
export * as validator from './glimmer-validator';
92 changes: 92 additions & 0 deletions src/utils/glimmer-validator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import {
type Cell,
cellFor,
cellsMap,
getTracker,
isRendering,
setIsRendering,
} from './reactive';

export { cellFor as tagFor } from '@lifeart/gxt';

export function dirtyTagFor(obj: object, key: string | number | symbol): void {
// @ts-expect-error
const cell = cellFor(obj, key);
cell.update(cell.value);
}
export function tagMetaFor(obj: object): any {
return cellsMap.get(obj);
}

export function isTracking(): boolean {
return getTracker() !== null;
}

export function consumeTag(tag: Cell): void {
const TRACKER = getTracker();
if (TRACKER !== null) {
TRACKER.add(tag);
}
}

export type Getter<T, K extends keyof T> = (self: T) => T[K] | undefined;
export type Setter<T, K extends keyof T> = (self: T, value: T[K]) => void;

export function trackedData<T extends object, K extends keyof T>(
key: K,
initializer?: (this: T) => T[K],
): { getter: Getter<T, K>; setter: Setter<T, K> } {
let values = new WeakMap<T, T[K]>();
let hasInitializer = typeof initializer === 'function';

function getter(self: T) {
consumeTag(cellFor(self, key));

let value;

// If the field has never been initialized, we should initialize it
if (hasInitializer && !values.has(self)) {
value = initializer!.call(self);
values.set(self, value);
} else {
value = values.get(self);
}

return value;
}

function setter(self: T, value: T[K]): void {
dirtyTagFor(self, key);
values.set(self, value);
}

return { getter, setter };
}

let renderingStateBeforeBegin = isRendering();

export function beginTrackFrame() {
renderingStateBeforeBegin = isRendering();
if (!isRendering()) {
setIsRendering(true);
}
}

export function endTrackFrame() {
if (isRendering() !== renderingStateBeforeBegin) {
setIsRendering(renderingStateBeforeBegin);
}
}

export function beginUntrackFrame() {
renderingStateBeforeBegin = isRendering();
if (renderingStateBeforeBegin) {
setIsRendering(false);
}
}

export function endUntrackFrame() {
if (isRendering() !== renderingStateBeforeBegin) {
setIsRendering(renderingStateBeforeBegin);
}
}
33 changes: 20 additions & 13 deletions src/utils/reactive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const DEBUG_MERGED_CELLS = new Set<MergedCell>();
export const DEBUG_CELLS = new Set<Cell>();
var currentTracker: Set<Cell> | null = null;
let _isRendering = false;
const cellsMap = new WeakMap<object, Record<string, Cell<unknown>>>();
export const cellsMap = new WeakMap<object, Map<string | number | symbol, Cell<unknown>>>();

export function getCells() {
return Array.from(DEBUG_CELLS);
Expand All @@ -40,9 +40,9 @@ if (IS_DEV_MODE) {
}
}

function keysFor(obj: object): Record<string, Cell<unknown>> {
function keysFor(obj: object): Map<string | number | symbol, Cell<unknown>> {
if (!cellsMap.has(obj)) {
cellsMap.set(obj, {});
cellsMap.set(obj, new Map());
}
return cellsMap.get(obj)!;
}
Expand All @@ -56,26 +56,26 @@ export function tracked(
return {
get() {
const keys = keysFor(this);
if (!(key in keys)) {
if (!keys.has(key)) {
const value: any = cell(
hasInitializer
? descriptor!.initializer?.call(this)
: descriptor?.value,
`${klass.constructor.name}.${key}.@tracked`,
);
keys[key] = value;
keys.set(key, value);
return value.value;
} else {
return keys[key].value;
return keys.get(key)!.value;
}
},
set(newValue: any) {
const keys = keysFor(this);
if (!(key in keys)) {
keys[key] = cell(newValue, `${klass.constructor.name}.${key}.@tracked`);
if (!keys.has(key)) {
keys.set(key, cell(newValue, `${klass.constructor.name}.${key}.@tracked`));
return;
}
const _cell = keys[key];
const _cell = keys.get(key)!;
if (_cell.value === newValue) {
return;
}
Expand Down Expand Up @@ -278,15 +278,15 @@ export function cellFor<T extends object, K extends keyof T>(
obj: T,
key: K,
): Cell<T[K]> {
const refs = cellsMap.get(obj) || {};
if (key in refs) {
return refs[key as unknown as string] as Cell<T[K]>;
const refs = cellsMap.get(obj) || new Map<string | number | symbol, Cell>();
if (refs.has(key)) {
return refs.get(key) as Cell<T[K]>;
}
const cellValue = new Cell<T[K]>(
obj[key],
`${obj.constructor.name}.${String(key)}`,
);
refs[key as unknown as string] = cellValue;
refs.set(key, cellValue);
cellsMap.set(obj, refs);
Object.defineProperty(obj, key, {
get() {
Expand Down Expand Up @@ -326,3 +326,10 @@ export function inNewTrackingFrame(callback: () => void) {
callback();
currentTracker = existingTracker;
}

export function getTracker() {
return currentTracker;
}
export function setTracker(tracker: Set<Cell> | null) {
currentTracker = tracker;
}
Loading