215 lines
7.9 KiB
TypeScript
Raw Normal View History

import { transformCodebase } from "../../tools/transformCodebase";
2021-02-21 18:55:06 +01:00
import * as fs from "fs";
import { join as pathJoin } from "path";
import { replaceImportsFromStaticInJsCode } from "../replacers/replaceImportsFromStaticInJsCode";
import { replaceImportsInCssCode } from "../replacers/replaceImportsInCssCode";
import { generateFtlFilesCodeFactory, loginThemePageIds, accountThemePageIds } from "../generateFtl";
import { themeTypes, type ThemeType, lastKeycloakVersionWithAccountV1, keycloak_resources } 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";
2023-07-24 00:49:12 +02:00
import { generateMessageProperties } from "./generateMessageProperties";
2023-08-24 08:58:00 +02:00
import { readStaticResourcesUsage } from "./readStaticResourcesUsage";
2022-08-16 14:41:06 +07:00
2023-08-21 05:54:17 +02:00
export type BuildOptionsLike = {
themeName: string;
extraThemeProperties: string[] | undefined;
themeVersion: string;
2023-09-03 21:02:51 +02:00
loginThemeResourcesFromKeycloakVersion: string;
2023-08-21 05:54:17 +02:00
urlPathname: string | undefined;
};
2022-08-16 14:41:06 +07:00
2023-04-01 13:31:35 +02:00
assert<BuildOptions extends BuildOptionsLike ? true : false>();
2021-03-22 20:54:28 +01:00
export async function generateTheme(params: {
projectDirPath: string;
reactAppBuildDirPath: string;
keycloakThemeBuildingDirPath: string;
2023-06-21 18:06:12 +02:00
themeSrcDirPath: string;
keycloakifySrcDirPath: string;
2022-08-16 14:41:06 +07:00
buildOptions: BuildOptionsLike;
keycloakifyVersion: string;
}): Promise<void> {
const {
projectDirPath,
reactAppBuildDirPath,
keycloakThemeBuildingDirPath,
themeSrcDirPath,
keycloakifySrcDirPath,
buildOptions,
keycloakifyVersion
} = params;
const getThemeDirPath = (themeType: ThemeType | "email") =>
pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme", buildOptions.themeName, themeType);
2021-02-21 18:55:06 +01:00
let allCssGlobalsToDefine: Record<string, string> = {};
let generateFtlFilesCode_glob: ReturnType<typeof generateFtlFilesCodeFactory>["generateFtlFilesCode"] | undefined = undefined;
for (const themeType of themeTypes) {
2023-06-21 18:06:12 +02:00
if (!fs.existsSync(pathJoin(themeSrcDirPath, themeType))) {
continue;
}
const themeDirPath = getThemeDirPath(themeType);
copy_app_resources_to_theme_path: {
const isFirstPass = themeType.indexOf(themeType) === 0;
2023-08-21 05:54:17 +02:00
if (!isFirstPass) {
break copy_app_resources_to_theme_path;
}
transformCodebase({
2023-08-21 05:54:17 +02:00
"destDirPath": pathJoin(themeDirPath, "resources", "build"),
"srcDirPath": reactAppBuildDirPath,
"transformSourceCode": ({ filePath, sourceCode }) => {
//NOTE: Prevent cycles, excludes the folder we generated for debug in public/
if (
isInside({
"dirPath": pathJoin(reactAppBuildDirPath, keycloak_resources),
filePath
})
) {
return undefined;
}
if (/\.css?$/i.test(filePath)) {
const { cssGlobalsToDefine, fixedCssCode } = replaceImportsInCssCode({
"cssCode": sourceCode.toString("utf8")
});
register_css_variables: {
if (!isFirstPass) {
break register_css_variables;
}
allCssGlobalsToDefine = {
...allCssGlobalsToDefine,
...cssGlobalsToDefine
};
}
return { "modifiedSourceCode": Buffer.from(fixedCssCode, "utf8") };
}
if (/\.js?$/i.test(filePath)) {
const { fixedJsCode } = replaceImportsFromStaticInJsCode({
2023-08-21 05:54:17 +02:00
"jsCode": sourceCode.toString("utf8")
});
return { "modifiedSourceCode": Buffer.from(fixedJsCode, "utf8") };
}
2023-08-21 05:54:17 +02:00
return { "modifiedSourceCode": sourceCode };
2022-08-16 14:41:06 +07:00
}
});
}
2022-08-16 14:41:06 +07:00
2023-06-21 18:06:12 +02:00
const generateFtlFilesCode =
generateFtlFilesCode_glob !== undefined
? generateFtlFilesCode_glob
: generateFtlFilesCodeFactory({
"indexHtmlCode": fs.readFileSync(pathJoin(reactAppBuildDirPath, "index.html")).toString("utf8"),
"cssGlobalsToDefine": allCssGlobalsToDefine,
buildOptions,
keycloakifyVersion,
themeType,
"fieldNames": readFieldNameUsage({
keycloakifySrcDirPath,
themeSrcDirPath,
themeType
})
}).generateFtlFilesCode;
2021-02-21 18:55:06 +01:00
2023-03-20 01:48:03 +01:00
[
...(() => {
switch (themeType) {
case "login":
return loginThemePageIds;
case "account":
return accountThemePageIds;
}
})(),
2023-06-21 18:06:12 +02:00
...readExtraPagesNames({
themeType,
themeSrcDirPath
})
2023-03-20 01:48:03 +01:00
].forEach(pageId => {
const { ftlCode } = generateFtlFilesCode({ pageId });
2022-08-16 14:41:06 +07:00
fs.mkdirSync(themeDirPath, { "recursive": true });
2021-03-28 13:37:02 +02:00
fs.writeFileSync(pathJoin(themeDirPath, pageId), Buffer.from(ftlCode, "utf8"));
});
2023-07-24 00:49:12 +02:00
generateMessageProperties({
themeSrcDirPath,
themeType
}).forEach(({ languageTag, propertiesFileSource }) => {
const messagesDirPath = pathJoin(themeDirPath, "messages");
fs.mkdirSync(pathJoin(themeDirPath, "messages"), { "recursive": true });
const propertiesFilePath = pathJoin(messagesDirPath, `messages_${languageTag}.properties`);
fs.writeFileSync(propertiesFilePath, Buffer.from(propertiesFileSource, "utf8"));
});
await downloadKeycloakStaticResources({
projectDirPath,
"keycloakVersion": (() => {
switch (themeType) {
case "account":
return lastKeycloakVersionWithAccountV1;
case "login":
2023-09-03 21:02:51 +02:00
return buildOptions.loginThemeResourcesFromKeycloakVersion;
}
})(),
themeDirPath,
2023-08-24 08:58:00 +02:00
themeType,
"usedResources": readStaticResourcesUsage({
keycloakifySrcDirPath,
themeSrcDirPath,
themeType
})
});
fs.writeFileSync(
pathJoin(themeDirPath, "theme.properties"),
Buffer.from(
[
`parent=${(() => {
switch (themeType) {
case "account":
return "account-v1";
case "login":
return "keycloak";
}
assert<Equals<typeof themeType, never>>(false);
})()}`,
...(buildOptions.extraThemeProperties ?? [])
].join("\n\n"),
"utf8"
)
);
}
2021-02-21 18:55:06 +01:00
2022-04-20 00:39:40 +02:00
email: {
const emailThemeSrcDirPath = pathJoin(themeSrcDirPath, "email");
if (!fs.existsSync(emailThemeSrcDirPath)) {
break email;
}
2022-04-20 00:39:40 +02:00
transformCodebase({
2023-03-24 05:43:34 +01:00
"srcDirPath": emailThemeSrcDirPath,
"destDirPath": getThemeDirPath("email")
2022-04-20 00:39:40 +02:00
});
}
2021-02-21 18:55:06 +01:00
}