Skip to content
This repository was archived by the owner on Aug 19, 2025. It is now read-only.
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
42 changes: 35 additions & 7 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ const writeFiles = async (
supabaseFile: File,
hookFiles: HookFile[],
metadataFile: File,
componentFiles: File[]
componentFiles: {
tableComponents: File[];
joinTableComponents: File[];
viewComponents: File[];
}
) => {
await writeFile(
`${DIRECTORY}/${supabaseFile.fileName}`,
Expand All @@ -29,14 +33,36 @@ const writeFiles = async (
`${DIRECTORY}/${metadataFile.fileName}`,
metadataFile.content
);
await Promise.all(
componentFiles.map((hookFile) => {

const tableComponentPromises = componentFiles.tableComponents.map(
(componentFile) => {
return writeFile(
`${DIRECTORY}/components/${hookFile.fileName}`,
hookFile.content
`${DIRECTORY}/components/tables/${componentFile.fileName}`,
componentFile.content
);
})
}
);
const joinTableComponentPromises = componentFiles.joinTableComponents.map(
(componentFile) => {
return writeFile(
`${DIRECTORY}/components/joinTables/${componentFile.fileName}`,
componentFile.content
);
}
);
const viewComponentPromises = componentFiles.viewComponents.map(
(componentFile) => {
return writeFile(
`${DIRECTORY}/components/views/${componentFile.fileName}`,
componentFile.content
);
}
);
await Promise.all([
...tableComponentPromises,
...joinTableComponentPromises,
...viewComponentPromises,
]);
};

const run = async () => {
Expand All @@ -45,7 +71,9 @@ const run = async () => {

await remove(DIRECTORY);
await ensureDir(`${DIRECTORY}/hooks`);
await ensureDir(`${DIRECTORY}/components`);
await ensureDir(`${DIRECTORY}/components/tables`);
await ensureDir(`${DIRECTORY}/components/joinTables`);
await ensureDir(`${DIRECTORY}/components/views`);
await writeFile(`${DIRECTORY}/${types.fileName}`, types.content);

const supabaseFile = await parseSupabaseFile();
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@backengine/codegen",
"version": "1.0.16",
"version": "2.0.0",
"description": "Generate code for Backengine projects.",
"bin": "build/index.js",
"files": [
Expand Down
79 changes: 22 additions & 57 deletions src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,63 +1,28 @@
import comment from "../comment";
import { fetchTables } from "../pgMeta/fetchTables";
import type { File, HookFile } from "../types";
import prettier from "prettier";
import { parseNameFormats } from "../utils";
import { parseComponentFilesForTables } from "./tables";
import { parseComponentFilesForJoinTables } from "./joinTables";
import { parseComponentFilesForViews } from "./views";

const mapHookFileToComponent = async (hookFile: HookFile): Promise<File> => {
const {
file: { fileName },
} = hookFile;

const componentName = fileName.replace("use", "");
const { camelCasePlural } = parseNameFormats(componentName);

const content = `
${comment}

"use client";

import ${fileName} from "../hooks/${fileName}";

export default function ${componentName}() {
const { ${camelCasePlural} } = ${fileName}();

return (
<div
style={{
paddingTop: "20px",
}}
>
<code>${camelCasePlural}</code>
<pre
className="border rounded-md text-xs"
style={{
marginTop: "4px",
padding: "16px",
height: "200px",
overflowY: "auto",
}}
>
{JSON.stringify(${camelCasePlural}, null, 2)}
</pre>
</div>
)
};
`;

const formattedContent = await prettier.format(content, {
parser: "typescript",
});
export const parseComponentFiles = async (
hookFiles: HookFile[]
): Promise<{
tableComponents: File[];
joinTableComponents: File[];
viewComponents: File[];
}> => {
const { tables, joinTables } = await fetchTables();

const tableComponents = await parseComponentFilesForTables(hookFiles, tables);
const joinTableComponents = await parseComponentFilesForJoinTables(
hookFiles,
joinTables
);
const viewComponents = await parseComponentFilesForViews(hookFiles);

return {
fileName: `${componentName}.tsx`,
content: formattedContent,
tableComponents,
joinTableComponents,
viewComponents,
};
};

export const parseComponentFiles = async (
hookFiles: HookFile[]
): Promise<File[]> => {
const componentPromises = hookFiles.map(mapHookFileToComponent);
const files = await Promise.all(componentPromises);
return files;
};
164 changes: 164 additions & 0 deletions src/components/joinTables/get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import prettier from "prettier";
import comment from "../../comment";
import { TablesResponse } from "../../pgMeta/fetchTables";
import type { File, HookFile } from "../../types";
import { parseFetchFunctionNamesForJoinTable } from "./utils";

export const mapHookFileToGetComponent = async (
hookFile: HookFile,
joinTables: TablesResponse
): Promise<File> => {
const {
entityName,
file: { fileName },
} = hookFile;

const componentName = `${fileName.replace("use", "")}`;

const { tableOneFetchFunctionName, tableTwoFetchFunctionName } =
parseFetchFunctionNamesForJoinTable(joinTables, entityName);

const content = `
${comment}

import { useState } from "react";
import type { TableOneRow, TableTwoRow } from "../../hooks/${fileName}";

export default function Get${componentName}({
${tableOneFetchFunctionName},
${tableTwoFetchFunctionName}
}:
{
${tableOneFetchFunctionName}: (id: TableOneRow["id"]) => Promise<TableTwoRow[]>,
${tableTwoFetchFunctionName}: (id: TableTwoRow["id"]) => Promise<TableOneRow[]>
}) {
const [id, setId] = useState("");
const [data, setData] = useState<TableOneRow[] | TableTwoRow[]>();

return (
<div
style={{
paddingTop: "20px",
}}
>
<pre
className="border rounded-md text-xs"
style={{
marginTop: "4px",
padding: "16px",
height: "200px",
overflowY: "auto",
}}
>
{JSON.stringify(data, null, 2)}
</pre>
<div
className="flex items-center"
style={{
marginTop: "10px",
}}
>
<label
htmlFor="ID"
style={{
flexBasis: "120px",
}}
>
ID
</label>
<input
type="text"
id="ID"
style={{
background: "#000",
color: "#fff",
border: "1px solid #34383A",
marginLeft: "10px",
flex: "1",
borderRadius: "0.375rem",
padding: "4px 16px",
}}
value={id}
onChange={(event) => setId(event.target.value)}
/>
</div>
<div style={{
display: "flex",
marginTop: "10px",
}}>
<button
style={{
background: "#fff",
color: "#000",
padding: "8px 10px",
minWidth: "200px",
borderRadius: "0.375rem",
display: "flex",
alignItems: "center",
justifyContent: "center",
marginRight: "20px",
}}
onClick={() => ${tableOneFetchFunctionName}(id as any).then((data) => setData(data))}
>
<div style={{ marginRight: "10px" }}>Run ${tableOneFetchFunctionName}</div>
<svg
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
style={{
height: "20px",
}}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M5.25 5.653c0-.856.917-1.398 1.667-.986l11.54 6.348a1.125 1.125 0 010 1.971l-11.54 6.347a1.125 1.125 0 01-1.667-.985V5.653z"
/>
</svg>
</button>
<button
style={{
background: "#fff",
color: "#000",
padding: "8px 10px",
minWidth: "200px",
borderRadius: "0.375rem",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
onClick={() => ${tableTwoFetchFunctionName}(id as any).then((data) => setData(data))}
>
<div style={{ marginRight: "10px" }}>Run ${tableTwoFetchFunctionName}</div>
<svg
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
style={{
height: "20px",
}}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M5.25 5.653c0-.856.917-1.398 1.667-.986l11.54 6.348a1.125 1.125 0 010 1.971l-11.54 6.347a1.125 1.125 0 01-1.667-.985V5.653z"
/>
</svg>
</button>
</div>
</div>
)
};
`;

const formattedContent = await prettier.format(content, {
parser: "typescript",
});

return {
fileName: `Get${componentName}.tsx`,
content: formattedContent,
};
};
72 changes: 72 additions & 0 deletions src/components/joinTables/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import prettier from "prettier";
import comment from "../../comment";
import type { TablesResponse } from "../../pgMeta/fetchTables";
import type { File, HookFile } from "../../types";
import { mapHookFileToGetComponent } from "./get";
import { parseFetchFunctionNamesForJoinTable } from "./utils";

export const mapHookFileToComponent = async (
hookFile: HookFile,
joinTables: TablesResponse
): Promise<File> => {
const {
entityName,
file: { fileName },
} = hookFile;

const componentName = fileName.replace("use", "");
const getComponentName = `Get${componentName}`;

const { tableOneFetchFunctionName, tableTwoFetchFunctionName } =
parseFetchFunctionNamesForJoinTable(joinTables, entityName);

const content = `
${comment}

"use client";

import ${fileName} from "../../hooks/${fileName}";
import ${getComponentName} from "./${getComponentName}";

export default function ${componentName}() {
const { ${tableOneFetchFunctionName}, ${tableTwoFetchFunctionName} } = ${fileName}();

return (
<div>
<${getComponentName} ${tableOneFetchFunctionName}={${tableOneFetchFunctionName}} ${tableTwoFetchFunctionName}={${tableTwoFetchFunctionName}} />
</div>
)
};
`;

const formattedContent = await prettier.format(content, {
parser: "typescript",
});

return {
fileName: `${componentName}.tsx`,
content: formattedContent,
};
};

export const parseComponentFilesForJoinTables = async (
hookFiles: HookFile[],
joinTables: TablesResponse
): Promise<File[]> => {
const joinTableHookFiles = hookFiles.filter(
(hookFile) => hookFile.entityType === "JOIN_TABLE"
);

const componentPromises = joinTableHookFiles.map((joinTableHookFile) =>
mapHookFileToComponent(joinTableHookFile, joinTables)
);
const getComponentPromises = joinTableHookFiles.map((joinTableHookFile) =>
mapHookFileToGetComponent(joinTableHookFile, joinTables)
);

const files = await Promise.all([
...componentPromises,
...getComponentPromises,
]);
return files;
};
Loading