diff --git a/src/bin/keycloakify/buildJars/buildJars.ts b/src/bin/keycloakify/buildJars/buildJars.ts index aadf9288..f4c1ed44 100644 --- a/src/bin/keycloakify/buildJars/buildJars.ts +++ b/src/bin/keycloakify/buildJars/buildJars.ts @@ -5,12 +5,12 @@ import { getKeycloakVersionRangeForJar } from "./getKeycloakVersionRangeForJar"; import { buildJar } from "./buildJar"; export async function buildJars(params: { - doImplementAccountTheme: boolean; + doesImplementAccountTheme: boolean; buildOptions: { keycloakifyBuildDirPath: string; }; }): Promise<{ lastJarFileBasename: string }> { - const { doImplementAccountTheme, buildOptions } = params; + const { doesImplementAccountTheme, buildOptions } = params; let lastJarFileBasename: string | undefined = undefined; @@ -20,7 +20,7 @@ export async function buildJars(params: { keycloakThemeAdditionalInfoExtensionVersions .map(keycloakThemeAdditionalInfoExtensionVersion => { const keycloakVersionRange = getKeycloakVersionRangeForJar({ - doImplementAccountTheme, + doesImplementAccountTheme, keycloakAccountV1Version, keycloakThemeAdditionalInfoExtensionVersion }); diff --git a/src/bin/keycloakify/buildJars/getKeycloakVersionRangeForJar.ts b/src/bin/keycloakify/buildJars/getKeycloakVersionRangeForJar.ts index cd774fa3..7cf11480 100644 --- a/src/bin/keycloakify/buildJars/getKeycloakVersionRangeForJar.ts +++ b/src/bin/keycloakify/buildJars/getKeycloakVersionRangeForJar.ts @@ -2,35 +2,35 @@ import { assert, type Equals } from "tsafe/assert"; import type { KeycloakAccountV1Versions, KeycloakThemeAdditionalInfoExtensionVersions } from "./extensionVersions"; export function getKeycloakVersionRangeForJar(params: { - doImplementAccountTheme: boolean; + doesImplementAccountTheme: boolean; keycloakAccountV1Version: KeycloakAccountV1Versions; keycloakThemeAdditionalInfoExtensionVersion: KeycloakThemeAdditionalInfoExtensionVersions; }): string | undefined { - const { keycloakAccountV1Version, keycloakThemeAdditionalInfoExtensionVersion, doImplementAccountTheme } = params; + const { keycloakAccountV1Version, keycloakThemeAdditionalInfoExtensionVersion, doesImplementAccountTheme } = params; switch (keycloakAccountV1Version) { case null: switch (keycloakThemeAdditionalInfoExtensionVersion) { case null: - return doImplementAccountTheme ? "21-and-below" : "21-and-below"; + return doesImplementAccountTheme ? "21-and-below" : "21-and-below"; case "0.1": - return doImplementAccountTheme ? undefined : "22-and-above"; + return doesImplementAccountTheme ? undefined : "22-and-above"; } assert>(false); case "0.3": switch (keycloakThemeAdditionalInfoExtensionVersion) { case null: - return doImplementAccountTheme ? undefined : undefined; + return doesImplementAccountTheme ? undefined : undefined; case "0.1": - return doImplementAccountTheme ? "23" : undefined; + return doesImplementAccountTheme ? "23" : undefined; } assert>(false); case "0.4": switch (keycloakThemeAdditionalInfoExtensionVersion) { case null: - return doImplementAccountTheme ? undefined : undefined; + return doesImplementAccountTheme ? undefined : undefined; case "0.1": - return doImplementAccountTheme ? "24-and-above" : undefined; + return doesImplementAccountTheme ? "24-and-above" : undefined; } assert>(false); } diff --git a/src/bin/keycloakify/generateTheme/generateSrcMainResources.ts b/src/bin/keycloakify/generateTheme/generateSrcMainResources.ts index 62eb244b..24196759 100644 --- a/src/bin/keycloakify/generateTheme/generateSrcMainResources.ts +++ b/src/bin/keycloakify/generateTheme/generateSrcMainResources.ts @@ -42,7 +42,7 @@ export async function generateSrcMainResources(params: { buildOptions: BuildOptionsLike; keycloakifyVersion: string; srcMainResourcesDirPath: string; -}): Promise<{ implementedThemeTypes: Record }> { +}): Promise<{ doesImplementAccountTheme: boolean }> { const { themeName, themeSrcDirPath, keycloakifySrcDirPath, buildOptions, keycloakifyVersion, srcMainResourcesDirPath } = params; const getThemeTypeDirPath = (params: { themeType: ThemeType | "email" }) => { @@ -263,5 +263,5 @@ export async function generateSrcMainResources(params: { fs.writeFileSync(keycloakThemeJsonFilePath, Buffer.from(JSON.stringify(parsedKeycloakThemeJson, null, 2), "utf8")); } - return { implementedThemeTypes }; + return { "doesImplementAccountTheme": implementedThemeTypes.account }; } diff --git a/src/bin/keycloakify/generateTheme/generateTheme.ts b/src/bin/keycloakify/generateTheme/generateTheme.ts index ccbadda2..94775955 100644 --- a/src/bin/keycloakify/generateTheme/generateTheme.ts +++ b/src/bin/keycloakify/generateTheme/generateTheme.ts @@ -1,22 +1,12 @@ -import { type ThemeType } from "../../constants"; import { join as pathJoin } from "path"; import type { BuildOptions } from "../buildOptions"; import { assert } from "tsafe/assert"; -import { generateSrcMainResources } from "./generateSrcMainResources"; +import { generateSrcMainResources, type BuildOptionsLike as BuildOptionsLike_generateSrcMainResources } from "./generateSrcMainResources"; import { generateThemeVariations } from "./generateThemeVariants"; -export type BuildOptionsLike = { - bundler: "vite" | "webpack"; - themeNames: string[]; - extraThemeProperties: string[] | undefined; - themeVersion: string; - loginThemeResourcesFromKeycloakVersion: string; +export type BuildOptionsLike = BuildOptionsLike_generateSrcMainResources & { keycloakifyBuildDirPath: string; - reactAppBuildDirPath: string; - cacheDirPath: string; - assetsDirPath: string; - urlPathname: string | undefined; - npmWorkspaceRootDirPath: string; + themeNames: string[]; }; assert(); @@ -26,14 +16,16 @@ export async function generateTheme(params: { keycloakifySrcDirPath: string; buildOptions: BuildOptionsLike; keycloakifyVersion: string; -}): Promise<{ implementedThemeTypes: Record }> { +}): Promise<{ doesImplementAccountTheme: boolean }> { const { themeSrcDirPath, keycloakifySrcDirPath, buildOptions, keycloakifyVersion } = params; const [themeName, ...themeVariantNames] = buildOptions.themeNames; - const { implementedThemeTypes } = await generateSrcMainResources({ + const srcMainResourcesDirPath = pathJoin(buildOptions.keycloakifyBuildDirPath, "src", "main", "resources"); + + const { doesImplementAccountTheme } = await generateSrcMainResources({ themeName, - "srcMainResourcesDirPath": pathJoin(buildOptions.keycloakifyBuildDirPath, "src", "main", "resources"), + srcMainResourcesDirPath, themeSrcDirPath, keycloakifySrcDirPath, keycloakifyVersion, @@ -44,10 +36,9 @@ export async function generateTheme(params: { generateThemeVariations({ themeName, themeVariantName, - implementedThemeTypes, - buildOptions + srcMainResourcesDirPath }); } - return { implementedThemeTypes }; + return { doesImplementAccountTheme }; } diff --git a/src/bin/keycloakify/generateTheme/generateThemeVariants.ts b/src/bin/keycloakify/generateTheme/generateThemeVariants.ts index 63c6e714..6b889b6e 100644 --- a/src/bin/keycloakify/generateTheme/generateThemeVariants.ts +++ b/src/bin/keycloakify/generateTheme/generateThemeVariants.ts @@ -1,12 +1,50 @@ -import type { ThemeType } from "../../constants"; +import { join as pathJoin, extname as pathExtname, sep as pathSep } from "path"; +import { transformCodebase } from "../../tools/transformCodebase"; +import { assert } from "tsafe/assert"; +import * as fs from "fs"; -export function generateThemeVariations(params: { - themeName: string; - themeVariantName: string; - implementedThemeTypes: Record; - buildOptions: { - keycloakifyBuildDirPath: string; - }; -}) { - //TODO: Implement +export function generateThemeVariations(params: { themeName: string; themeVariantName: string; srcMainResourcesDirPath: string }) { + const { themeName, themeVariantName, srcMainResourcesDirPath } = params; + + const mainThemeDirPath = pathJoin(srcMainResourcesDirPath, "theme", themeName); + + transformCodebase({ + "srcDirPath": mainThemeDirPath, + "destDirPath": pathJoin(mainThemeDirPath, themeVariantName), + "transformSourceCode": ({ fileRelativePath, sourceCode }) => { + if (pathExtname(fileRelativePath) === ".ftl" && fileRelativePath.split(pathSep).length === 2) { + const modifiedSourceCode = Buffer.from( + Buffer.from(sourceCode) + .toString("utf-8") + .replace(`out["themeName"] = "${themeName}";`, `out["themeName"] = "${themeVariantName}";`), + "utf8" + ); + + assert(Buffer.compare(modifiedSourceCode, sourceCode) !== 0); + + return { modifiedSourceCode }; + } + + return { "modifiedSourceCode": sourceCode }; + } + }); + + { + const keycloakThemeJsonFilePath = pathJoin(srcMainResourcesDirPath, "META-INF", "keycloak-themes.json"); + + const modifiedParsedJson = JSON.parse(fs.readFileSync(keycloakThemeJsonFilePath).toString("utf8")) as { + themes: { name: string; types: string[] }[]; + }; + + modifiedParsedJson.themes.push({ + "name": themeVariantName, + "types": (() => { + const theme = modifiedParsedJson.themes.find(({ name }) => name === themeName); + assert(theme !== undefined); + return theme.types; + })() + }); + + fs.writeFileSync(keycloakThemeJsonFilePath, Buffer.from(JSON.stringify(modifiedParsedJson, null, 2), "utf8")); + } } diff --git a/src/bin/keycloakify/keycloakify.ts b/src/bin/keycloakify/keycloakify.ts index aafb47f2..c7a98de6 100644 --- a/src/bin/keycloakify/keycloakify.ts +++ b/src/bin/keycloakify/keycloakify.ts @@ -29,7 +29,7 @@ export async function main() { fs.writeFileSync(pathJoin(buildOptions.keycloakifyBuildDirPath, ".gitignore"), Buffer.from("*", "utf8")); } - const { implementedThemeTypes } = await generateTheme({ + const { doesImplementAccountTheme } = await generateTheme({ themeSrcDirPath, "keycloakifySrcDirPath": pathJoin(getThisCodebaseRootDirPath(), "src"), "keycloakifyVersion": readThisNpmProjectVersion(), @@ -51,7 +51,7 @@ export async function main() { } const { lastJarFileBasename } = await buildJars({ - "doImplementAccountTheme": implementedThemeTypes.account, + doesImplementAccountTheme, buildOptions });