Refactor
This commit is contained in:
parent
88fa63d848
commit
5a7d452429
@ -1,6 +1,6 @@
|
|||||||
import { assert } from "tsafe/assert";
|
import { assert } from "tsafe/assert";
|
||||||
import { Reflect } from "tsafe/Reflect";
|
import { Reflect } from "tsafe/Reflect";
|
||||||
import type { BuildOptions } from "./buildOptions";
|
import type { BuildOptions } from "../buildOptions";
|
||||||
|
|
||||||
type BuildOptionsLike = {
|
type BuildOptionsLike = {
|
||||||
groupId: string;
|
groupId: string;
|
||||||
|
@ -9,7 +9,6 @@ import { transformCodebase } from "../../tools/transformCodebase";
|
|||||||
import { rmSync } from "../../tools/fs.rmSync";
|
import { rmSync } from "../../tools/fs.rmSync";
|
||||||
|
|
||||||
type BuildOptionsLike = {
|
type BuildOptionsLike = {
|
||||||
keycloakifyBuildDirPath: string;
|
|
||||||
cacheDirPath: string;
|
cacheDirPath: string;
|
||||||
npmWorkspaceRootDirPath: string;
|
npmWorkspaceRootDirPath: string;
|
||||||
};
|
};
|
||||||
@ -20,10 +19,10 @@ type BuildOptionsLike = {
|
|||||||
assert<typeof buildOptions extends BuildOptionsLike ? true : false>();
|
assert<typeof buildOptions extends BuildOptionsLike ? true : false>();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function bringInAccountV1(params: { buildOptions: BuildOptionsLike }) {
|
export async function bringInAccountV1(params: { buildOptions: BuildOptionsLike; srcMainResourcesDirPath: string }) {
|
||||||
const { buildOptions } = params;
|
const { buildOptions, srcMainResourcesDirPath } = params;
|
||||||
|
|
||||||
const builtinKeycloakThemeTmpDirPath = pathJoin(buildOptions.keycloakifyBuildDirPath, "..", "tmp_yxdE2_builtin_keycloak_theme");
|
const builtinKeycloakThemeTmpDirPath = pathJoin(srcMainResourcesDirPath, "..", "tmp_yxdE2_builtin_keycloak_theme");
|
||||||
|
|
||||||
await downloadBuiltinKeycloakTheme({
|
await downloadBuiltinKeycloakTheme({
|
||||||
"destDirPath": builtinKeycloakThemeTmpDirPath,
|
"destDirPath": builtinKeycloakThemeTmpDirPath,
|
||||||
@ -31,7 +30,7 @@ export async function bringInAccountV1(params: { buildOptions: BuildOptionsLike
|
|||||||
buildOptions
|
buildOptions
|
||||||
});
|
});
|
||||||
|
|
||||||
const accountV1DirPath = pathJoin(buildOptions.keycloakifyBuildDirPath, "src", "main", "resources", "theme", accountV1ThemeName, "account");
|
const accountV1DirPath = pathJoin(srcMainResourcesDirPath, "theme", accountV1ThemeName, "account");
|
||||||
|
|
||||||
transformCodebase({
|
transformCodebase({
|
||||||
"srcDirPath": pathJoin(builtinKeycloakThemeTmpDirPath, "base", "account"),
|
"srcDirPath": pathJoin(builtinKeycloakThemeTmpDirPath, "base", "account"),
|
||||||
|
267
src/bin/keycloakify/generateTheme/generateSrcMainResources.ts
Normal file
267
src/bin/keycloakify/generateTheme/generateSrcMainResources.ts
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
import { transformCodebase } from "../../tools/transformCodebase";
|
||||||
|
import * as fs from "fs";
|
||||||
|
import { join as pathJoin, resolve as pathResolve, dirname as pathDirname } from "path";
|
||||||
|
import { replaceImportsInJsCode } from "../replacers/replaceImportsInJsCode";
|
||||||
|
import { replaceImportsInCssCode } from "../replacers/replaceImportsInCssCode";
|
||||||
|
import { generateFtlFilesCodeFactory, loginThemePageIds, accountThemePageIds } from "../generateFtl";
|
||||||
|
import {
|
||||||
|
type ThemeType,
|
||||||
|
lastKeycloakVersionWithAccountV1,
|
||||||
|
keycloak_resources,
|
||||||
|
accountV1ThemeName,
|
||||||
|
basenameOfTheKeycloakifyResourcesDir
|
||||||
|
} from "../../constants";
|
||||||
|
import { isInside } from "../../tools/isInside";
|
||||||
|
import type { BuildOptions } from "../buildOptions";
|
||||||
|
import { assert, type Equals } from "tsafe/assert";
|
||||||
|
import { downloadKeycloakStaticResources } from "./downloadKeycloakStaticResources";
|
||||||
|
import { readFieldNameUsage } from "./readFieldNameUsage";
|
||||||
|
import { readExtraPagesNames } from "./readExtraPageNames";
|
||||||
|
import { generateMessageProperties } from "./generateMessageProperties";
|
||||||
|
import { bringInAccountV1 } from "./bringInAccountV1";
|
||||||
|
import { rmSync } from "../../tools/fs.rmSync";
|
||||||
|
|
||||||
|
export type BuildOptionsLike = {
|
||||||
|
bundler: "vite" | "webpack";
|
||||||
|
extraThemeProperties: string[] | undefined;
|
||||||
|
themeVersion: string;
|
||||||
|
loginThemeResourcesFromKeycloakVersion: string;
|
||||||
|
reactAppBuildDirPath: string;
|
||||||
|
cacheDirPath: string;
|
||||||
|
assetsDirPath: string;
|
||||||
|
urlPathname: string | undefined;
|
||||||
|
npmWorkspaceRootDirPath: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
assert<BuildOptions extends BuildOptionsLike ? true : false>();
|
||||||
|
|
||||||
|
export async function generateSrcMainResources(params: {
|
||||||
|
themeName: string;
|
||||||
|
themeSrcDirPath: string;
|
||||||
|
keycloakifySrcDirPath: string;
|
||||||
|
buildOptions: BuildOptionsLike;
|
||||||
|
keycloakifyVersion: string;
|
||||||
|
srcMainResourcesDirPath: string;
|
||||||
|
}): Promise<{ implementedThemeTypes: Record<ThemeType | "email", boolean> }> {
|
||||||
|
const { themeName, themeSrcDirPath, keycloakifySrcDirPath, buildOptions, keycloakifyVersion, srcMainResourcesDirPath } = params;
|
||||||
|
|
||||||
|
const getThemeTypeDirPath = (params: { themeType: ThemeType | "email" }) => {
|
||||||
|
const { themeType } = params;
|
||||||
|
return pathJoin(srcMainResourcesDirPath, "theme", themeName, themeType);
|
||||||
|
};
|
||||||
|
|
||||||
|
const cssGlobalsToDefine: Record<string, string> = {};
|
||||||
|
|
||||||
|
const implementedThemeTypes: Record<ThemeType | "email", boolean> = {
|
||||||
|
"login": false,
|
||||||
|
"account": false,
|
||||||
|
"email": false
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const themeType of ["login", "account"] as const) {
|
||||||
|
if (!fs.existsSync(pathJoin(themeSrcDirPath, themeType))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
implementedThemeTypes[themeType] = true;
|
||||||
|
|
||||||
|
const themeTypeDirPath = getThemeTypeDirPath({ themeType });
|
||||||
|
|
||||||
|
apply_replacers_and_move_to_theme_resources: {
|
||||||
|
const destDirPath = pathJoin(themeTypeDirPath, "resources", basenameOfTheKeycloakifyResourcesDir);
|
||||||
|
|
||||||
|
// NOTE: Prevent accumulation of files in the assets dir, as names are hashed they pile up.
|
||||||
|
rmSync(destDirPath, { "recursive": true, "force": true });
|
||||||
|
|
||||||
|
if (themeType === "account" && implementedThemeTypes.login) {
|
||||||
|
// NOTE: We prevend doing it twice, it has been done for the login theme.
|
||||||
|
|
||||||
|
transformCodebase({
|
||||||
|
"srcDirPath": pathJoin(
|
||||||
|
getThemeTypeDirPath({
|
||||||
|
"themeType": "login"
|
||||||
|
}),
|
||||||
|
"resources",
|
||||||
|
basenameOfTheKeycloakifyResourcesDir
|
||||||
|
),
|
||||||
|
destDirPath
|
||||||
|
});
|
||||||
|
|
||||||
|
break apply_replacers_and_move_to_theme_resources;
|
||||||
|
}
|
||||||
|
|
||||||
|
transformCodebase({
|
||||||
|
"srcDirPath": buildOptions.reactAppBuildDirPath,
|
||||||
|
destDirPath,
|
||||||
|
"transformSourceCode": ({ filePath, sourceCode }) => {
|
||||||
|
//NOTE: Prevent cycles, excludes the folder we generated for debug in public/
|
||||||
|
// This should not happen if users follow the new instruction setup but we keep it for retrocompatibility.
|
||||||
|
if (
|
||||||
|
isInside({
|
||||||
|
"dirPath": pathJoin(buildOptions.reactAppBuildDirPath, keycloak_resources),
|
||||||
|
filePath
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/\.css?$/i.test(filePath)) {
|
||||||
|
const { cssGlobalsToDefine: cssGlobalsToDefineForThisFile, fixedCssCode } = replaceImportsInCssCode({
|
||||||
|
"cssCode": sourceCode.toString("utf8")
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.entries(cssGlobalsToDefineForThisFile).forEach(([key, value]) => {
|
||||||
|
cssGlobalsToDefine[key] = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
return { "modifiedSourceCode": Buffer.from(fixedCssCode, "utf8") };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/\.js?$/i.test(filePath)) {
|
||||||
|
const { fixedJsCode } = replaceImportsInJsCode({
|
||||||
|
"jsCode": sourceCode.toString("utf8"),
|
||||||
|
buildOptions
|
||||||
|
});
|
||||||
|
|
||||||
|
return { "modifiedSourceCode": Buffer.from(fixedJsCode, "utf8") };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { "modifiedSourceCode": sourceCode };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const { generateFtlFilesCode } = generateFtlFilesCodeFactory({
|
||||||
|
themeName,
|
||||||
|
"indexHtmlCode": fs.readFileSync(pathJoin(buildOptions.reactAppBuildDirPath, "index.html")).toString("utf8"),
|
||||||
|
cssGlobalsToDefine,
|
||||||
|
buildOptions,
|
||||||
|
keycloakifyVersion,
|
||||||
|
themeType,
|
||||||
|
"fieldNames": readFieldNameUsage({
|
||||||
|
keycloakifySrcDirPath,
|
||||||
|
themeSrcDirPath,
|
||||||
|
themeType
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
[
|
||||||
|
...(() => {
|
||||||
|
switch (themeType) {
|
||||||
|
case "login":
|
||||||
|
return loginThemePageIds;
|
||||||
|
case "account":
|
||||||
|
return accountThemePageIds;
|
||||||
|
}
|
||||||
|
})(),
|
||||||
|
...readExtraPagesNames({
|
||||||
|
themeType,
|
||||||
|
themeSrcDirPath
|
||||||
|
})
|
||||||
|
].forEach(pageId => {
|
||||||
|
const { ftlCode } = generateFtlFilesCode({ pageId });
|
||||||
|
|
||||||
|
fs.mkdirSync(themeTypeDirPath, { "recursive": true });
|
||||||
|
|
||||||
|
fs.writeFileSync(pathJoin(themeTypeDirPath, pageId), Buffer.from(ftlCode, "utf8"));
|
||||||
|
});
|
||||||
|
|
||||||
|
generateMessageProperties({
|
||||||
|
themeSrcDirPath,
|
||||||
|
themeType
|
||||||
|
}).forEach(({ languageTag, propertiesFileSource }) => {
|
||||||
|
const messagesDirPath = pathJoin(themeTypeDirPath, "messages");
|
||||||
|
|
||||||
|
fs.mkdirSync(pathJoin(themeTypeDirPath, "messages"), { "recursive": true });
|
||||||
|
|
||||||
|
const propertiesFilePath = pathJoin(messagesDirPath, `messages_${languageTag}.properties`);
|
||||||
|
|
||||||
|
fs.writeFileSync(propertiesFilePath, Buffer.from(propertiesFileSource, "utf8"));
|
||||||
|
});
|
||||||
|
|
||||||
|
await downloadKeycloakStaticResources({
|
||||||
|
"keycloakVersion": (() => {
|
||||||
|
switch (themeType) {
|
||||||
|
case "account":
|
||||||
|
return lastKeycloakVersionWithAccountV1;
|
||||||
|
case "login":
|
||||||
|
return buildOptions.loginThemeResourcesFromKeycloakVersion;
|
||||||
|
}
|
||||||
|
})(),
|
||||||
|
"themeDirPath": pathResolve(pathJoin(themeTypeDirPath, "..")),
|
||||||
|
themeType,
|
||||||
|
buildOptions
|
||||||
|
});
|
||||||
|
|
||||||
|
fs.writeFileSync(
|
||||||
|
pathJoin(themeTypeDirPath, "theme.properties"),
|
||||||
|
Buffer.from(
|
||||||
|
[
|
||||||
|
`parent=${(() => {
|
||||||
|
switch (themeType) {
|
||||||
|
case "account":
|
||||||
|
return accountV1ThemeName;
|
||||||
|
case "login":
|
||||||
|
return "keycloak";
|
||||||
|
}
|
||||||
|
assert<Equals<typeof themeType, never>>(false);
|
||||||
|
})()}`,
|
||||||
|
...(buildOptions.extraThemeProperties ?? [])
|
||||||
|
].join("\n\n"),
|
||||||
|
"utf8"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
email: {
|
||||||
|
const emailThemeSrcDirPath = pathJoin(themeSrcDirPath, "email");
|
||||||
|
|
||||||
|
if (!fs.existsSync(emailThemeSrcDirPath)) {
|
||||||
|
break email;
|
||||||
|
}
|
||||||
|
|
||||||
|
implementedThemeTypes.email = true;
|
||||||
|
|
||||||
|
transformCodebase({
|
||||||
|
"srcDirPath": emailThemeSrcDirPath,
|
||||||
|
"destDirPath": getThemeTypeDirPath({ "themeType": "email" })
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsedKeycloakThemeJson: { themes: { name: string; types: string[] }[] } = { "themes": [] };
|
||||||
|
|
||||||
|
parsedKeycloakThemeJson.themes.push({
|
||||||
|
"name": themeName,
|
||||||
|
"types": Object.entries(implementedThemeTypes)
|
||||||
|
.filter(([, isImplemented]) => isImplemented)
|
||||||
|
.map(([themeType]) => themeType)
|
||||||
|
});
|
||||||
|
|
||||||
|
account_specific_extra_work: {
|
||||||
|
if (!implementedThemeTypes.account) {
|
||||||
|
break account_specific_extra_work;
|
||||||
|
}
|
||||||
|
|
||||||
|
await bringInAccountV1({
|
||||||
|
srcMainResourcesDirPath,
|
||||||
|
buildOptions
|
||||||
|
});
|
||||||
|
|
||||||
|
parsedKeycloakThemeJson.themes.push({
|
||||||
|
"name": accountV1ThemeName,
|
||||||
|
"types": ["account"]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const keycloakThemeJsonFilePath = pathJoin(srcMainResourcesDirPath, "META-INF", "keycloak-themes.json");
|
||||||
|
|
||||||
|
try {
|
||||||
|
fs.mkdirSync(pathDirname(keycloakThemeJsonFilePath));
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
fs.writeFileSync(keycloakThemeJsonFilePath, Buffer.from(JSON.stringify(parsedKeycloakThemeJson, null, 2), "utf8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return { implementedThemeTypes };
|
||||||
|
}
|
@ -1,28 +1,13 @@
|
|||||||
import { transformCodebase } from "../../tools/transformCodebase";
|
import { type ThemeType } from "../../constants";
|
||||||
import * as fs from "fs";
|
import { join as pathJoin } from "path";
|
||||||
import { join as pathJoin, resolve as pathResolve, dirname as pathDirname } from "path";
|
|
||||||
import { replaceImportsInJsCode } from "../replacers/replaceImportsInJsCode";
|
|
||||||
import { replaceImportsInCssCode } from "../replacers/replaceImportsInCssCode";
|
|
||||||
import { generateFtlFilesCodeFactory, loginThemePageIds, accountThemePageIds } from "../generateFtl";
|
|
||||||
import {
|
|
||||||
type ThemeType,
|
|
||||||
lastKeycloakVersionWithAccountV1,
|
|
||||||
keycloak_resources,
|
|
||||||
accountV1ThemeName,
|
|
||||||
basenameOfTheKeycloakifyResourcesDir
|
|
||||||
} from "../../constants";
|
|
||||||
import { isInside } from "../../tools/isInside";
|
|
||||||
import type { BuildOptions } from "../buildOptions";
|
import type { BuildOptions } from "../buildOptions";
|
||||||
import { assert, type Equals } from "tsafe/assert";
|
import { assert } from "tsafe/assert";
|
||||||
import { downloadKeycloakStaticResources } from "./downloadKeycloakStaticResources";
|
import { generateSrcMainResources } from "./generateSrcMainResources";
|
||||||
import { readFieldNameUsage } from "./readFieldNameUsage";
|
import { generateThemeVariations } from "./generateThemeVariants";
|
||||||
import { readExtraPagesNames } from "./readExtraPageNames";
|
|
||||||
import { generateMessageProperties } from "./generateMessageProperties";
|
|
||||||
import { bringInAccountV1 } from "./bringInAccountV1";
|
|
||||||
import { rmSync } from "../../tools/fs.rmSync";
|
|
||||||
|
|
||||||
export type BuildOptionsLike = {
|
export type BuildOptionsLike = {
|
||||||
bundler: "vite" | "webpack";
|
bundler: "vite" | "webpack";
|
||||||
|
themeNames: string[];
|
||||||
extraThemeProperties: string[] | undefined;
|
extraThemeProperties: string[] | undefined;
|
||||||
themeVersion: string;
|
themeVersion: string;
|
||||||
loginThemeResourcesFromKeycloakVersion: string;
|
loginThemeResourcesFromKeycloakVersion: string;
|
||||||
@ -37,235 +22,32 @@ export type BuildOptionsLike = {
|
|||||||
assert<BuildOptions extends BuildOptionsLike ? true : false>();
|
assert<BuildOptions extends BuildOptionsLike ? true : false>();
|
||||||
|
|
||||||
export async function generateTheme(params: {
|
export async function generateTheme(params: {
|
||||||
themeName: string;
|
|
||||||
themeSrcDirPath: string;
|
themeSrcDirPath: string;
|
||||||
keycloakifySrcDirPath: string;
|
keycloakifySrcDirPath: string;
|
||||||
buildOptions: BuildOptionsLike;
|
buildOptions: BuildOptionsLike;
|
||||||
keycloakifyVersion: string;
|
keycloakifyVersion: string;
|
||||||
}): Promise<{ implementedThemeTypes: Record<ThemeType | "email", boolean> }> {
|
}): Promise<{ implementedThemeTypes: Record<ThemeType | "email", boolean> }> {
|
||||||
const { themeName, themeSrcDirPath, keycloakifySrcDirPath, buildOptions, keycloakifyVersion } = params;
|
const { themeSrcDirPath, keycloakifySrcDirPath, buildOptions, keycloakifyVersion } = params;
|
||||||
|
|
||||||
const getThemeTypeDirPath = (params: { themeType: ThemeType | "email" }) => {
|
const [themeName, ...themeVariantNames] = buildOptions.themeNames;
|
||||||
const { themeType } = params;
|
|
||||||
return pathJoin(buildOptions.keycloakifyBuildDirPath, "src", "main", "resources", "theme", themeName, themeType);
|
|
||||||
};
|
|
||||||
|
|
||||||
const cssGlobalsToDefine: Record<string, string> = {};
|
const { implementedThemeTypes } = await generateSrcMainResources({
|
||||||
|
themeName,
|
||||||
const implementedThemeTypes: Record<ThemeType | "email", boolean> = {
|
"srcMainResourcesDirPath": pathJoin(buildOptions.keycloakifyBuildDirPath, "src", "main", "resources"),
|
||||||
"login": false,
|
themeSrcDirPath,
|
||||||
"account": false,
|
keycloakifySrcDirPath,
|
||||||
"email": false
|
keycloakifyVersion,
|
||||||
};
|
buildOptions
|
||||||
|
|
||||||
for (const themeType of ["login", "account"] as const) {
|
|
||||||
if (!fs.existsSync(pathJoin(themeSrcDirPath, themeType))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
implementedThemeTypes[themeType] = true;
|
|
||||||
|
|
||||||
const themeTypeDirPath = getThemeTypeDirPath({ themeType });
|
|
||||||
|
|
||||||
apply_replacers_and_move_to_theme_resources: {
|
|
||||||
const destDirPath = pathJoin(themeTypeDirPath, "resources", basenameOfTheKeycloakifyResourcesDir);
|
|
||||||
|
|
||||||
// NOTE: Prevent accumulation of files in the assets dir, as names are hashed they pile up.
|
|
||||||
rmSync(destDirPath, { "recursive": true, "force": true });
|
|
||||||
|
|
||||||
if (themeType === "account" && implementedThemeTypes.login) {
|
|
||||||
// NOTE: We prevend doing it twice, it has been done for the login theme.
|
|
||||||
|
|
||||||
transformCodebase({
|
|
||||||
"srcDirPath": pathJoin(
|
|
||||||
getThemeTypeDirPath({
|
|
||||||
"themeType": "login"
|
|
||||||
}),
|
|
||||||
"resources",
|
|
||||||
basenameOfTheKeycloakifyResourcesDir
|
|
||||||
),
|
|
||||||
destDirPath
|
|
||||||
});
|
|
||||||
|
|
||||||
break apply_replacers_and_move_to_theme_resources;
|
|
||||||
}
|
|
||||||
|
|
||||||
transformCodebase({
|
|
||||||
"srcDirPath": buildOptions.reactAppBuildDirPath,
|
|
||||||
destDirPath,
|
|
||||||
"transformSourceCode": ({ filePath, sourceCode }) => {
|
|
||||||
//NOTE: Prevent cycles, excludes the folder we generated for debug in public/
|
|
||||||
// This should not happen if users follow the new instruction setup but we keep it for retrocompatibility.
|
|
||||||
if (
|
|
||||||
isInside({
|
|
||||||
"dirPath": pathJoin(buildOptions.reactAppBuildDirPath, keycloak_resources),
|
|
||||||
filePath
|
|
||||||
})
|
|
||||||
) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (/\.css?$/i.test(filePath)) {
|
|
||||||
const { cssGlobalsToDefine: cssGlobalsToDefineForThisFile, fixedCssCode } = replaceImportsInCssCode({
|
|
||||||
"cssCode": sourceCode.toString("utf8")
|
|
||||||
});
|
|
||||||
|
|
||||||
Object.entries(cssGlobalsToDefineForThisFile).forEach(([key, value]) => {
|
|
||||||
cssGlobalsToDefine[key] = value;
|
|
||||||
});
|
|
||||||
|
|
||||||
return { "modifiedSourceCode": Buffer.from(fixedCssCode, "utf8") };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (/\.js?$/i.test(filePath)) {
|
|
||||||
const { fixedJsCode } = replaceImportsInJsCode({
|
|
||||||
"jsCode": sourceCode.toString("utf8"),
|
|
||||||
buildOptions
|
|
||||||
});
|
|
||||||
|
|
||||||
return { "modifiedSourceCode": Buffer.from(fixedJsCode, "utf8") };
|
|
||||||
}
|
|
||||||
|
|
||||||
return { "modifiedSourceCode": sourceCode };
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const { generateFtlFilesCode } = generateFtlFilesCodeFactory({
|
|
||||||
themeName,
|
|
||||||
"indexHtmlCode": fs.readFileSync(pathJoin(buildOptions.reactAppBuildDirPath, "index.html")).toString("utf8"),
|
|
||||||
cssGlobalsToDefine,
|
|
||||||
buildOptions,
|
|
||||||
keycloakifyVersion,
|
|
||||||
themeType,
|
|
||||||
"fieldNames": readFieldNameUsage({
|
|
||||||
keycloakifySrcDirPath,
|
|
||||||
themeSrcDirPath,
|
|
||||||
themeType
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
[
|
|
||||||
...(() => {
|
|
||||||
switch (themeType) {
|
|
||||||
case "login":
|
|
||||||
return loginThemePageIds;
|
|
||||||
case "account":
|
|
||||||
return accountThemePageIds;
|
|
||||||
}
|
|
||||||
})(),
|
|
||||||
...readExtraPagesNames({
|
|
||||||
themeType,
|
|
||||||
themeSrcDirPath
|
|
||||||
})
|
|
||||||
].forEach(pageId => {
|
|
||||||
const { ftlCode } = generateFtlFilesCode({ pageId });
|
|
||||||
|
|
||||||
fs.mkdirSync(themeTypeDirPath, { "recursive": true });
|
|
||||||
|
|
||||||
fs.writeFileSync(pathJoin(themeTypeDirPath, pageId), Buffer.from(ftlCode, "utf8"));
|
|
||||||
});
|
|
||||||
|
|
||||||
generateMessageProperties({
|
|
||||||
themeSrcDirPath,
|
|
||||||
themeType
|
|
||||||
}).forEach(({ languageTag, propertiesFileSource }) => {
|
|
||||||
const messagesDirPath = pathJoin(themeTypeDirPath, "messages");
|
|
||||||
|
|
||||||
fs.mkdirSync(pathJoin(themeTypeDirPath, "messages"), { "recursive": true });
|
|
||||||
|
|
||||||
const propertiesFilePath = pathJoin(messagesDirPath, `messages_${languageTag}.properties`);
|
|
||||||
|
|
||||||
fs.writeFileSync(propertiesFilePath, Buffer.from(propertiesFileSource, "utf8"));
|
|
||||||
});
|
|
||||||
|
|
||||||
await downloadKeycloakStaticResources({
|
|
||||||
"keycloakVersion": (() => {
|
|
||||||
switch (themeType) {
|
|
||||||
case "account":
|
|
||||||
return lastKeycloakVersionWithAccountV1;
|
|
||||||
case "login":
|
|
||||||
return buildOptions.loginThemeResourcesFromKeycloakVersion;
|
|
||||||
}
|
|
||||||
})(),
|
|
||||||
"themeDirPath": pathResolve(pathJoin(themeTypeDirPath, "..")),
|
|
||||||
themeType,
|
|
||||||
buildOptions
|
|
||||||
});
|
|
||||||
|
|
||||||
fs.writeFileSync(
|
|
||||||
pathJoin(themeTypeDirPath, "theme.properties"),
|
|
||||||
Buffer.from(
|
|
||||||
[
|
|
||||||
`parent=${(() => {
|
|
||||||
switch (themeType) {
|
|
||||||
case "account":
|
|
||||||
return accountV1ThemeName;
|
|
||||||
case "login":
|
|
||||||
return "keycloak";
|
|
||||||
}
|
|
||||||
assert<Equals<typeof themeType, never>>(false);
|
|
||||||
})()}`,
|
|
||||||
...(buildOptions.extraThemeProperties ?? [])
|
|
||||||
].join("\n\n"),
|
|
||||||
"utf8"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
email: {
|
|
||||||
const emailThemeSrcDirPath = pathJoin(themeSrcDirPath, "email");
|
|
||||||
|
|
||||||
if (!fs.existsSync(emailThemeSrcDirPath)) {
|
|
||||||
break email;
|
|
||||||
}
|
|
||||||
|
|
||||||
implementedThemeTypes.email = true;
|
|
||||||
|
|
||||||
transformCodebase({
|
|
||||||
"srcDirPath": emailThemeSrcDirPath,
|
|
||||||
"destDirPath": getThemeTypeDirPath({ "themeType": "email" })
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const parsedKeycloakThemeJson: { themes: { name: string; types: string[] }[] } = { "themes": [] };
|
|
||||||
|
|
||||||
parsedKeycloakThemeJson.themes.push({
|
|
||||||
"name": themeName,
|
|
||||||
"types": Object.entries(implementedThemeTypes)
|
|
||||||
.filter(([, isImplemented]) => isImplemented)
|
|
||||||
.map(([themeType]) => themeType)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
account_specific_extra_work: {
|
for (const themeVariantName of themeVariantNames) {
|
||||||
if (!implementedThemeTypes.account) {
|
generateThemeVariations({
|
||||||
break account_specific_extra_work;
|
themeName,
|
||||||
}
|
themeVariantName,
|
||||||
|
implementedThemeTypes,
|
||||||
await bringInAccountV1({ buildOptions });
|
buildOptions
|
||||||
|
|
||||||
parsedKeycloakThemeJson.themes.push({
|
|
||||||
"name": accountV1ThemeName,
|
|
||||||
"types": ["account"]
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
const keycloakThemeJsonFilePath = pathJoin(
|
|
||||||
buildOptions.keycloakifyBuildDirPath,
|
|
||||||
"src",
|
|
||||||
"main",
|
|
||||||
"resources",
|
|
||||||
"META-INF",
|
|
||||||
"keycloak-themes.json"
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
fs.mkdirSync(pathDirname(keycloakThemeJsonFilePath));
|
|
||||||
} catch {}
|
|
||||||
|
|
||||||
fs.writeFileSync(keycloakThemeJsonFilePath, Buffer.from(JSON.stringify(parsedKeycloakThemeJson, null, 2), "utf8"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return { implementedThemeTypes };
|
return { implementedThemeTypes };
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { ThemeType } from "../constants";
|
import type { ThemeType } from "../../constants";
|
||||||
|
|
||||||
export function generateThemeVariations(params: {
|
export function generateThemeVariations(params: {
|
||||||
themeName: string;
|
themeName: string;
|
@ -10,7 +10,6 @@ import { getThisCodebaseRootDirPath } from "../tools/getThisCodebaseRootDirPath"
|
|||||||
import { readThisNpmProjectVersion } from "../tools/readThisNpmProjectVersion";
|
import { readThisNpmProjectVersion } from "../tools/readThisNpmProjectVersion";
|
||||||
import { keycloakifyBuildOptionsForPostPostBuildScriptEnvName } from "../constants";
|
import { keycloakifyBuildOptionsForPostPostBuildScriptEnvName } from "../constants";
|
||||||
import { buildJars } from "./buildJars";
|
import { buildJars } from "./buildJars";
|
||||||
import { generateThemeVariations } from "./generateThemeVariants";
|
|
||||||
|
|
||||||
export async function main() {
|
export async function main() {
|
||||||
const buildOptions = readBuildOptions({
|
const buildOptions = readBuildOptions({
|
||||||
@ -30,25 +29,13 @@ export async function main() {
|
|||||||
fs.writeFileSync(pathJoin(buildOptions.keycloakifyBuildDirPath, ".gitignore"), Buffer.from("*", "utf8"));
|
fs.writeFileSync(pathJoin(buildOptions.keycloakifyBuildDirPath, ".gitignore"), Buffer.from("*", "utf8"));
|
||||||
}
|
}
|
||||||
|
|
||||||
const [themeName, ...themeVariantNames] = buildOptions.themeNames;
|
|
||||||
|
|
||||||
const { implementedThemeTypes } = await generateTheme({
|
const { implementedThemeTypes } = await generateTheme({
|
||||||
themeName,
|
|
||||||
themeSrcDirPath,
|
themeSrcDirPath,
|
||||||
"keycloakifySrcDirPath": pathJoin(getThisCodebaseRootDirPath(), "src"),
|
"keycloakifySrcDirPath": pathJoin(getThisCodebaseRootDirPath(), "src"),
|
||||||
"keycloakifyVersion": readThisNpmProjectVersion(),
|
"keycloakifyVersion": readThisNpmProjectVersion(),
|
||||||
buildOptions
|
buildOptions
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const themeVariantName of themeVariantNames) {
|
|
||||||
generateThemeVariations({
|
|
||||||
themeName,
|
|
||||||
themeVariantName,
|
|
||||||
implementedThemeTypes,
|
|
||||||
buildOptions
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
run_post_build_script: {
|
run_post_build_script: {
|
||||||
if (buildOptions.bundler !== "vite") {
|
if (buildOptions.bundler !== "vite") {
|
||||||
break run_post_build_script;
|
break run_post_build_script;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user