import * as fs from "fs"; import { join as pathJoin, dirname as pathDirname } from "path"; import { assert } from "tsafe/assert"; import { Reflect } from "tsafe/Reflect"; import type { BuildOptions } from "../BuildOptions"; import { type ThemeType, resources_common, lastKeycloakVersionWithAccountV1 } from "../../constants"; import { downloadBuiltinKeycloakTheme } from "../../download-builtin-keycloak-theme"; import { transformCodebase } from "../../tools/transformCodebase"; export type BuildOptionsLike = { themeName: string; extraThemeNames: string[]; groupId: string; artifactId: string; themeVersion: string; }; { const buildOptions = Reflect(); assert(); } export async function generateJavaStackFiles(params: { projectDirPath: string; keycloakThemeBuildingDirPath: string; implementedThemeTypes: Record; buildOptions: BuildOptionsLike; }): Promise<{ jarFilePath: string; }> { const { projectDirPath, buildOptions: { groupId, themeName, extraThemeNames, themeVersion, artifactId }, keycloakThemeBuildingDirPath, implementedThemeTypes } = params; { const { pomFileCode } = (function generatePomFileCode(): { pomFileCode: string; } { const pomFileCode = [ ``, ``, ` 4.0.0`, ` ${groupId}`, ` ${artifactId}`, ` ${themeVersion}`, ` ${artifactId}`, ` `, ` jar`, ` `, ` 17`, ` UTF-8`, ` 999.0.0-SNAPSHOT`, ` 32.0.0-jre`, ` 1.18.28`, ` 1.1.1`, ` `, ` `, ` `, ` `, ` maven-compiler-plugin`, ` 3.11.0`, ` `, ` \${java.version}`, ` \${java.version}`, ` -Xlint:unchecked`, ` -Xlint:deprecation`, ` false`, ` `, ` `, ` com.google.auto.service`, ` auto-service`, ` \${auto-service.version}`, ` `, ` `, ` org.projectlombok`, ` lombok`, ` \${lombok.version}`, ` `, ` `, ` `, ` `, ` `, ` org.apache.maven.plugins`, ` maven-jar-plugin`, ` 3.2.0`, ` `, ` `, ` `, ` `, ` `, ` `, ` `, ` `, ` `, ` `, ` `, ` com.spotify.fmt`, ` fmt-maven-plugin`, ` 2.20`, ` `, ` `, ` `, ` `, ` `, ` org.projectlombok`, ` lombok`, ` \${lombok.version}`, ` provided`, ` `, ` `, ` com.google.auto.service`, ` auto-service`, ` \${auto-service.version}`, ` provided`, ` `, ` `, ` org.keycloak`, ` keycloak-server-spi`, ` \${keycloak.version}`, ` provided`, ` `, ` `, ` org.keycloak`, ` keycloak-server-spi-private`, ` \${keycloak.version}`, ` provided`, ` `, ` `, ` org.keycloak`, ` keycloak-services`, ` \${keycloak.version}`, ` provided`, ` `, ` `, ` jakarta.ws.rs`, ` jakarta.ws.rs-api`, ` 3.1.0`, ` provided`, ` `, ` `, ` com.google.guava`, ` guava`, ` \${guava.version}`, ` provided`, ` `, ` `, `` ].join("\n"); return { pomFileCode }; })(); fs.writeFileSync(pathJoin(keycloakThemeBuildingDirPath, "pom.xml"), Buffer.from(pomFileCode, "utf8")); } const accountV1 = "account-v1"; { const builtinKeycloakThemeTmpDirPath = pathJoin(keycloakThemeBuildingDirPath, "..", "tmp_yxdE2_builtin_keycloak_theme"); await downloadBuiltinKeycloakTheme({ projectDirPath, "destDirPath": builtinKeycloakThemeTmpDirPath, "keycloakVersion": lastKeycloakVersionWithAccountV1 }); const accountV1DirPath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme", accountV1, "account"); transformCodebase({ "srcDirPath": pathJoin(builtinKeycloakThemeTmpDirPath, "base", "account"), "destDirPath": accountV1DirPath }); const commonResourceFilePaths = [ "node_modules/patternfly/dist/css/patternfly.min.css", "node_modules/patternfly/dist/css/patternfly-additions.min.css" ]; for (const relativeFilePath of commonResourceFilePaths.map(path => pathJoin(...path.split("/")))) { const destFilePath = pathJoin(accountV1DirPath, "resources", resources_common, relativeFilePath); fs.mkdirSync(pathDirname(destFilePath), { "recursive": true }); fs.cpSync(pathJoin(builtinKeycloakThemeTmpDirPath, "keycloak", "common", "resources", relativeFilePath), destFilePath); } const resourceFilePaths = ["css/account.css"]; for (const relativeFilePath of resourceFilePaths.map(path => pathJoin(...path.split("/")))) { const destFilePath = pathJoin(accountV1DirPath, "resources", relativeFilePath); fs.mkdirSync(pathDirname(destFilePath), { "recursive": true }); fs.cpSync(pathJoin(builtinKeycloakThemeTmpDirPath, "keycloak", "account", "resources", relativeFilePath), destFilePath); } fs.rmdirSync(builtinKeycloakThemeTmpDirPath, { "recursive": true }); fs.writeFileSync( pathJoin(accountV1DirPath, "theme.properties"), Buffer.from( [ "accountResourceProvider=org.keycloak.services.resources.account.AccountFormService", "", "locales=ar,ca,cs,da,de,en,es,fr,fi,hu,it,ja,lt,nl,no,pl,pt-BR,ru,sk,sv,tr,zh-CN", "", "styles=" + [...resourceFilePaths, ...commonResourceFilePaths.map(path => `resources_common/${path}`)].join(" "), "", "##### css classes for form buttons", "# main class used for all buttons", "kcButtonClass=btn", "# classes defining priority of the button - primary or default (there is typically only one priority button for the form)", "kcButtonPrimaryClass=btn-primary", "kcButtonDefaultClass=btn-default", "# classes defining size of the button", "kcButtonLargeClass=btn-lg", "" ].join("\n"), "utf8" ) ); } transformCodebase({ "srcDirPath": pathJoin(__dirname, "account-v1-java"), "destDirPath": pathJoin(keycloakThemeBuildingDirPath, "src", "main", "java", "org", "keycloak") }); { const themeManifestFilePath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "META-INF", "keycloak-themes.json"); try { fs.mkdirSync(pathDirname(themeManifestFilePath)); } catch {} fs.writeFileSync( themeManifestFilePath, Buffer.from( JSON.stringify( { "themes": [ { "name": accountV1, "types": ["account"] }, ...[themeName, ...extraThemeNames].map(themeName => ({ "name": themeName, "types": Object.entries(implementedThemeTypes) .filter(([, isImplemented]) => isImplemented) .map(([themeType]) => themeType) })) ] }, null, 2 ), "utf8" ) ); } return { "jarFilePath": pathJoin(keycloakThemeBuildingDirPath, "target", `${artifactId}-${themeVersion}.jar`) }; }