From 9605e17e96765dfd4a82c1d14ccaf0e0993ddb15 Mon Sep 17 00:00:00 2001 From: Joseph Garrone Date: Sat, 27 Jul 2024 17:50:31 +0200 Subject: [PATCH] Fix generaion of entrypoint --- .../initialize-account-theme.ts | 19 ++- src/bin/shared/generateKcGenTs.ts | 113 +++++++++++++++++- 2 files changed, 128 insertions(+), 4 deletions(-) diff --git a/src/bin/initialize-account-theme/initialize-account-theme.ts b/src/bin/initialize-account-theme/initialize-account-theme.ts index 22e641ca..e15b95ba 100644 --- a/src/bin/initialize-account-theme/initialize-account-theme.ts +++ b/src/bin/initialize-account-theme/initialize-account-theme.ts @@ -6,6 +6,7 @@ import chalk from "chalk"; import { join as pathJoin, relative as pathRelative } from "path"; import * as fs from "fs"; import { updateAccountThemeImplementationInConfig } from "./updateAccountThemeImplementationInConfig"; +import { generateKcGenTs } from "../shared/generateKcGenTs"; export async function command(params: { cliCommandOptions: CliCommandOptions }) { const { cliCommandOptions } = params; @@ -14,7 +15,10 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) const accountThemeSrcDirPath = pathJoin(buildContext.themeSrcDirPath, "account"); - if (fs.existsSync(accountThemeSrcDirPath)) { + if ( + fs.existsSync(accountThemeSrcDirPath) && + fs.readdirSync(accountThemeSrcDirPath).length > 0 + ) { console.warn( chalk.red( `There is already a ${pathRelative( @@ -92,4 +96,17 @@ export async function command(params: { cliCommandOptions: CliCommandOptions }) } updateAccountThemeImplementationInConfig({ buildContext, accountThemeType }); + + await generateKcGenTs({ + buildContext: { + ...buildContext, + implementedThemeTypes: { + ...buildContext.implementedThemeTypes, + account: { + isImplemented: true, + type: accountThemeType + } + } + } + }); } diff --git a/src/bin/shared/generateKcGenTs.ts b/src/bin/shared/generateKcGenTs.ts index 61042913..7191a55c 100644 --- a/src/bin/shared/generateKcGenTs.ts +++ b/src/bin/shared/generateKcGenTs.ts @@ -1,14 +1,21 @@ -import { assert } from "tsafe/assert"; +import { assert, type Equals } from "tsafe/assert"; +import { id } from "tsafe/id"; import type { BuildContext } from "./buildContext"; import * as fs from "fs/promises"; import { join as pathJoin } from "path"; import { existsAsync } from "../tools/fs.existsAsync"; +import { z } from "zod"; export type BuildContextLike = { projectDirPath: string; themeNames: string[]; environmentVariables: { name: string; default: string }[]; themeSrcDirPath: string; + implementedThemeTypes: Pick< + BuildContext["implementedThemeTypes"], + "login" | "account" + >; + packageJsonFilePath: string; }; assert(); @@ -18,12 +25,53 @@ export async function generateKcGenTs(params: { }): Promise { const { buildContext } = params; - const filePath = pathJoin(buildContext.themeSrcDirPath, "kc.gen.ts"); + const isReactProject: boolean = await (async () => { + const parsedPackageJson = await (async () => { + type ParsedPackageJson = { + dependencies?: Record; + devDependencies?: Record; + }; + + const zParsedPackageJson = (() => { + type TargetType = ParsedPackageJson; + + const zTargetType = z.object({ + dependencies: z.record(z.string()).optional(), + devDependencies: z.record(z.string()).optional() + }); + + assert, TargetType>>(); + + return id>(zTargetType); + })(); + + return zParsedPackageJson.parse( + JSON.parse( + (await fs.readFile(buildContext.packageJsonFilePath)).toString("utf8") + ) + ); + })(); + + return ( + { + ...parsedPackageJson.dependencies, + ...parsedPackageJson.devDependencies + }.react !== undefined + ); + })(); + + const filePath = pathJoin( + buildContext.themeSrcDirPath, + `kc.gen.ts${isReactProject ? "x" : ""}` + ); const currentContent = (await existsAsync(filePath)) ? await fs.readFile(filePath) : undefined; + const hasLoginTheme = buildContext.implementedThemeTypes.login.isImplemented; + const hasAccountTheme = buildContext.implementedThemeTypes.account.isImplemented; + const newContent = Buffer.from( [ `/* prettier-ignore-start */`, @@ -36,6 +84,8 @@ export async function generateKcGenTs(params: { ``, `// This file is auto-generated by Keycloakify`, ``, + isReactProject && `import { lazy, Suspense, type ReactNode } from "react";`, + ``, `export type ThemeName = ${buildContext.themeNames.map(themeName => `"${themeName}"`).join(" | ")};`, ``, `export const themeNames: ThemeName[] = [${buildContext.themeNames.map(themeName => `"${themeName}"`).join(", ")}];`, @@ -54,9 +104,52 @@ export async function generateKcGenTs(params: { 2 )};`, ``, + `export type KcContext =`, + hasLoginTheme && ` | import("./login/KcContext").KcContext`, + hasAccountTheme && ` | import("./account/KcContext").KcContext`, + ` ;`, + ``, + `declare global {`, + ` interface Window {`, + ` kcContext?: KcContext;`, + ` }`, + `}`, + ``, + ...(!isReactProject + ? [] + : [ + hasLoginTheme && + `export const KcLoginPage = lazy(() => import("./login/KcPage"));`, + hasAccountTheme && + `export const KcAccountPage = lazy(() => import("./account/KcPage"));`, + ``, + `export function KcPage(`, + ` props: {`, + ` kcContext: KcContext;`, + ` fallback?: ReactNode;`, + ` }`, + `) {`, + ` const { kcContext, fallback } = props;`, + ` return (`, + ` `, + ` {(() => {`, + ` switch (kcContext.themeType) {`, + hasLoginTheme && + ` case "login": return ;`, + hasAccountTheme && + ` case "account": return ;`, + ` }`, + ` })()}`, + ` `, + ` );`, + `}` + ]), + ``, `/* prettier-ignore-end */`, `` - ].join("\n"), + ] + .filter(item => typeof item === "string") + .join("\n"), "utf8" ); @@ -65,4 +158,18 @@ export async function generateKcGenTs(params: { } await fs.writeFile(filePath, newContent); + + delete_legacy_file: { + if (!isReactProject) { + break delete_legacy_file; + } + + const legacyFilePath = filePath.replace(/tsx$/, "ts"); + + if (!(await existsAsync(legacyFilePath))) { + break delete_legacy_file; + } + + await fs.unlink(legacyFilePath); + } }