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

Enhance Metadata Generation with "Used By" Tracking #774

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Changes from 2 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
82 changes: 75 additions & 7 deletions engine/decofile/fsFolder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,19 @@ import type {
} from "./provider.ts";
import type { VersionedDecofile } from "./realtime.ts";

interface BaseMetadata {
blockType: string;
__resolveType: string;
usedBy: string[];
}

interface PageMetadata extends BaseMetadata {
name: string;
path: string;
}

type Metadata = BaseMetadata | PageMetadata;

export const parseBlockId = (filename: string) =>
decodeURIComponent(filename.slice(0, filename.length - ".json".length));

Expand All @@ -26,7 +39,10 @@ const inferBlockType = (resolveType: string, knownBlockTypes: Set<string>) => {
return blockType;
};

const inferMetadata = (content: unknown, knownBlockTypes: Set<string>) => {
const inferMetadata = (
content: unknown,
knownBlockTypes: Set<string>,
): Metadata | null => {
try {
const { __resolveType, name, path } = content as Record<string, string>;
const blockType = inferBlockType(__resolveType, knownBlockTypes);
Expand All @@ -41,24 +57,66 @@ const inferMetadata = (content: unknown, knownBlockTypes: Set<string>) => {
path: path,
blockType,
__resolveType,
usedBy: [],
};
}

return {
blockType,
__resolveType,
usedBy: [],
};
// TODO @gimenes: when the json is wrong, we should somehow resolve to a standard block that talks well to the admin so the user can fix it somehow
} catch {
return null;
}
};

/**
* Recursively maps block references in an object and updates the `usedBy` property of the corresponding blocks.
*
* @param obj - The object to map block references in.
* @param blocks - A map of block paths to block metadata.
* @param currentPath - The current path of the object being processed.
* @param isRoot - Indicates whether the current object is the root object.
*/
const mapBlockReferences = (
obj: unknown,
blocks: Map<string, Metadata>,
currentPath: string,
isRoot = true,
): void => {
if (typeof obj !== "object" || obj === null) return;

if (Array.isArray(obj)) {
obj.forEach((item) => mapBlockReferences(item, blocks, currentPath, false));
} else {
for (const [key, value] of Object.entries(obj)) {
if (key === "__resolveType" && typeof value === "string" && !isRoot) {
const blockName = value.split("/").pop();
if (blockName) {
const blockPath = Array.from(blocks.keys()).find((path) =>
Copy link
Contributor

@tlgimenes tlgimenes Aug 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isso aqui nao é lento nao? criar um array dos e fazer um find para cada prop de cada block, ainda mais recursivamente assim?

decodeURIComponent(path.split("/").pop() ?? "") ===
`${blockName}.json`
);
if (blockPath && blockPath !== currentPath) {
const block = blocks.get(blockPath);
if (block && !block.usedBy.includes(currentPath)) {
block.usedBy.push(currentPath);
}
}
}
} else if (typeof value === "object" && value !== null) {
mapBlockReferences(value, blocks, currentPath, false);
}
}
}
};

/** Syncs FileSystem Metadata with Storage metadata */
export const genMetadata = async () => {
try {
const knownBlockTypes = new Set(getBlocks().map((x) => x.type));
const paths = [];
const paths: string[] = [];

const walker = walk(join(DECO_FOLDER, BLOCKS_FOLDER), {
includeDirs: false,
Expand All @@ -79,13 +137,23 @@ export const genMetadata = async () => {
),
);

const metadata = Object.fromEntries(entries.map((
[path, content],
) => [path, inferMetadata(content, knownBlockTypes)]));
const metadata = new Map(
entries.map(([path, content]) => [
path,
inferMetadata(content, knownBlockTypes),
]).filter(([, meta]) => meta !== null) as [string, Metadata][],
);

for (const [path, content] of entries) {
mapBlockReferences(content, metadata, path);
}

const pathname = join(Deno.cwd(), METADATA_PATH);
await ensureFile(pathname);
await Deno.writeTextFile(pathname, JSON.stringify(metadata));
await Deno.writeTextFile(
pathname,
JSON.stringify(Object.fromEntries(metadata)),
);
} catch (error) {
console.error("Error while auto-generating blocks.json", error);
}
Expand Down
Loading