core/observers/record.observer.ts
core/observers/record.observer.ts is a file in GovLab Context. 132 lines of code and 30 definitions.
import {
ATTRIBUTION_KEY,
INDEX_MARK,
LABEL_KEYS,
LIST_MARK,
PATH_JOINER,
SOURCE_JOINER,
WHOLE_RECORD,
} from "#configuration/constants/record.constants";
import type { RecordOrigin, TrackedRecord, UnreadKey, UnreadReason } from "#types/record.types";
import { isPlainRecord } from "#core/predicates/record.predicate";
const childrenOf = function childrenOf(value: unknown, path: string): [Record<string, unknown>, string][] {
if (isPlainRecord(value)) {
return [[value, `${path}${PATH_JOINER}`]];
}
const elements: unknown[] = Array.isArray(value) ? value : [];
return elements.filter(isPlainRecord).map((element) => [element, `${path}${LIST_MARK}${PATH_JOINER}`]);
};
const pathsUnder = function pathsUnder(raw: Record<string, unknown>, prefix: string): string[] {
return Object.entries(raw).flatMap(([key, value]) => {
const path = `${prefix}${key}`;
return [path, ...childrenOf(value, path).flatMap(([child, childPrefix]) => pathsUnder(child, childPrefix))];
});
};
const presentPaths = function presentPaths(raw: Record<string, unknown>): string[] {
return [...new Set(pathsUnder(raw, ""))];
};
const labelOf = function labelOf(raw: Record<string, unknown>, fallback: string): string {
for (const key of LABEL_KEYS) {
const value = raw[key];
if (typeof value === "string" && value.length > 0) {
return value;
}
}
return fallback;
};
const isUnread = function isUnread(entry: TrackedRecord, path: string): boolean {
return !entry.read.has(path) && ![...entry.delegated].some((prefix) => path.startsWith(prefix));
};
export class ReadAudit {
readonly #collection: string;
readonly #tracked: TrackedRecord[] = [];
readonly #dropped: UnreadKey[] = [];
readonly #origins = new WeakMap<object, RecordOrigin>();
readonly #attributions = new Set<string>();
public constructor(collection: string) {
this.#collection = collection;
}
public attribution(tracked: Record<string, unknown>): void {
const notice = tracked[ATTRIBUTION_KEY];
if (typeof notice === "string" && notice.length > 0) {
this.#attributions.add(notice);
}
}
public attributions(): string[] {
return [...this.#attributions];
}
public track(value: Record<string, unknown>, source: string): Record<string, unknown> {
const raw = this.#release(value);
const entry: TrackedRecord = {
delegated: new Set<string>(),
raw,
read: new Set<string>(),
record: `${source}${SOURCE_JOINER}${labelOf(raw, source)}`,
};
this.#tracked.push(entry);
return this.#wrap(raw, "", entry);
}
public records(list: unknown, source: string): Record<string, unknown>[] {
const items: unknown[] = Array.isArray(list) ? list : [];
return items.flatMap((item, index) => {
if (isPlainRecord(item)) {
return [this.track(item, source)];
}
this.#drop(`${source}${INDEX_MARK}${String(index)}`, "not-a-record");
return [];
});
}
public reject(value: unknown, source: string): void {
const raw = isPlainRecord(value) ? this.#release(value) : null;
this.#drop(raw === null ? source : `${source}${SOURCE_JOINER}${labelOf(raw, source)}`, "rejected");
}
public unread(): UnreadKey[] {
const unread = this.#tracked.flatMap((entry) =>
presentPaths(entry.raw)
.filter((path) => isUnread(entry, path))
.map((key): UnreadKey => ({
collection: this.#collection,
key,
reason: "unread",
record: entry.record,
})),
);
return [...this.#dropped, ...unread];
}
#release(value: Record<string, unknown>): Record<string, unknown> {
const origin = this.#origins.get(value);
if (origin === undefined) {
return value;
}
origin.entry.delegated.add(origin.prefix);
return origin.target;
}
#drop(record: string, reason: UnreadReason): void {
this.#dropped.push({ collection: this.#collection, key: WHOLE_RECORD, reason, record });
}
#wrap(raw: Record<string, unknown>, prefix: string, entry: TrackedRecord): Record<string, unknown> {
const proxy = new Proxy(raw, {
get: (target, key, receiver): unknown => {
if (typeof key !== "string") {
return Reflect.get(target, key, receiver);
}
const path = `${prefix}${key}`;
entry.read.add(path);
const value = target[key];
if (isPlainRecord(value)) {
return this.#wrap(value, `${path}${PATH_JOINER}`, entry);
}
if (Array.isArray(value)) {
return value.map((element: unknown) =>
isPlainRecord(element)
? this.#wrap(element, `${path}${LIST_MARK}${PATH_JOINER}`, entry)
: element,
);
}
return value;
},
});
this.#origins.set(proxy, { entry, prefix, target: raw });
return proxy;
}
}