Files
wehub-resource-sync 2114b14ee0
Sync main into demo / sync (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:35:26 +08:00

64 lines
1.8 KiB
TypeScript

import type { XPost } from '../types';
/**
* Runtime post overlay 表:
* - 值为 XPost: 整条 post 完整覆盖 base (id 必须存在且 case-sensitive 匹配 base)
* - 值为 null: tombstone, 隐藏对应 base post
* - 缺 key: 走 base 默认值
*
* Contract: post id 永远 case-sensitive 精确匹配, 不做任何 lowercase 归一。
*/
export type XRuntimePostTable = Record<string, XPost | null | undefined>;
export function getXRuntimePostEntry(
posts: XRuntimePostTable | undefined,
postId: string,
): XPost | null | undefined {
if (!posts) return undefined;
return Object.prototype.hasOwnProperty.call(posts, postId) ? posts[postId] : undefined;
}
export function resolveXRuntimePost(
posts: XRuntimePostTable | undefined,
basePostsById: Map<string, XPost>,
postId: string,
): XPost | null {
const patch = getXRuntimePostEntry(posts, postId);
if (patch === null) return null;
if (patch && typeof patch === 'object') return patch;
return basePostsById.get(postId) ?? null;
}
export function resolveXRuntimePosts(
posts: XRuntimePostTable | undefined,
basePosts: XPost[],
): XPost[] {
const basePostsById = new Map<string, XPost>();
for (const post of basePosts) {
if (post?.id) basePostsById.set(post.id, post);
}
const out: XPost[] = [];
const seen = new Set<string>();
const table = posts ?? {};
for (const [id, patch] of Object.entries(table)) {
if (patch === null) {
seen.add(id);
continue;
}
const resolved = resolveXRuntimePost(table, basePostsById, id);
if (!resolved?.id || seen.has(resolved.id)) continue;
seen.add(resolved.id);
out.push(resolved);
}
for (const post of basePosts) {
if (!post?.id || seen.has(post.id)) continue;
seen.add(post.id);
out.push(post);
}
return out;
}